Multiple WordPress Installations with Nginx - php

I am trying to use a single site config file with nginx to server an arbitrary number of WordPress installations in sub-folders, but can't get pretty permalinks to work at all.
+ root
+ WordPressOne
+ WordPressTwo
+ WordPressThree
With permalinks disabled, /WordPressOne/?p=12 works fine. With permalinks enabled, /WordPressOne/MyPage/ results in a 404 delivered from the root folder.
Since the number of WP installations in subfolders is constantly varying (it's used for development) and I don't want to have to constantly modify/create/delete site configs, I'd like it to work such that I can just copy a new WordPress installation to a new subfolder, set WP up, and have permalinks working for that installation without restarting nginx or PHP-FPM.
This is the basic site.conf used in the /etc/nginx/sites-available/ folder (it reflects a number of rules used in production as well):
server {
listen 5000 default;
server_name dev wpdev;
root /vagrant/sites;
client_max_body_size 2m;
expires -1;
charset utf-8;
index index.html index.php;
location ~* ^.+\.(manifest|appcache)$ {
expires -1;
index index.html index.htm;
uwsgi_cache off;
}
location ~* \.(?:rss|atom)$ {
expires 1h;
add_header Cache-Control "public";
}
location ~* ^.+\.(css |js|jpg|jpeg|gif|png|ico|gz|svg|svgz|ttf|otf|woff|eot|mp4|ogg|ogv|webm|txt)$ {
expires max;
access_log off;
index index.html index.htm;
add_header Cache-Control "public";
uwsgi_cache off;
}
location / {
try_files $uri $uri/ /index.php?$args;
uwsgi_cache off;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
uwsgi_cache off;
include /etc/nginx/fastcgi_params;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_script_name;
}
location ~ /\.ht {
deny all;
}
add_header "X-UA-Compatible" "IE=Edge,chrome=1";
add_header "Vary" "Accept-Language";
add_header "Access-Control-Allow-Origin" "*";
add_header "Cache-Control" "no-transform";
}
This is also used as part of a virtual machine configuration (using Vagrant, as you can see), and I'd love for designers and WP devs to not have to worry about keeping their site files in nginx updated.
Thanks!

It looks like you've copied a basic WordPress setup and I see no attempts to implement the logic you want. Each WordPress install has a router called index.php, which should be the catch-all for pretty URLs to work. They will need to carry the first path below the site root, which is probably a WordPress configuration setting.
Then you will need to set the root based on the first path component in the request_uri and route non existing files and directories to the appropriate index.php.
I'm not entirely sure this would work and can't test it for time constraints, so try this and report back:
set $wpinstall = '';
location ~ /([^/]+)/(.*)$ {
set $wpinstall = $1;
try_files $uri $uri/ #wp;
}
location #wp {
rewrite /$wpinstall/ /$wpinstall/index.php;
}
location ~ ^(.+\.php)(.*)$ {
root /vagrant/sites;
fastcgi_split_path_info ^(.*\.php)(.*)$;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root/$wpinstall$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
#...rest of fastcgi parameters
}
If you report back, be sure to include the rewriting debug info by setting the appropriate error_log debug level. In all honesty, this may be a lot easier if you use virtual hosts, based on this configuration. Your developers would only need to edit their host files.

Related

How to make Nginx find existing index.php if it is requested by its name?

I have tried to install Mamoto (ex Piwik) on a local webserver (nginx via Docker) and have the following issues:
request to http://localhost -> works perfectly (it already executes index.php).
request to http://localhost/index.php -> gives 404 (it ignores the existence of index.php).
What is going on there with Nginx?
This is my nginx-config:
server {
server_name localhost;
root /var/www;
client_max_body_size 20M;
index index.php;
location ~ ^/(index|matomo|piwik|js/index|plugins/HeatmapSessionRecording/configs)\.php {
fastcgi_pass php-upstream;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
try_files $fastcgi_script_name =404;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $realpath_root;
fastcgi_read_timeout 600;
# Prevents URIs that include the front controller. This will 404:
# http://domain.tld/index.php/some-path
# Remove the internal directive to allow URIs like this
internal;
}
## deny access to all other .php files
location ~* ^.+\.php$ {
deny all;
return 403;
}
location ~ \.(gif|ico|jpg|png|svg|js|css|htm|html|mp3|mp4|wav|ogg|avi|ttf|eot|woff|woff2|json)$ {
allow all;
## Cache images,CSS,JS and webfonts for an hour
## Increasing the duration may improve the load-time, but may cause old files to show after an Matomo upgrade
expires 1h;
add_header Pragma public;
add_header Cache-Control "public";
}
location / {
# try to serve file directly, fallback to index.php
try_files $uri $uri/ =404;
}
}
The weird thing here: when I type a "die('test');" inside index.php, I can assure that index.php is definitely available at this location and gets executed on every request without a specific filename like "localhost".
But when index.php is requested by name (this is how Matomo works internally), then it gives 404.

NGINX + Wordpress gives ERR_TOO_MANY_REDIRECTS

I have been trying to host a simple Wordpress blog using NGINX as the web-server. The blog is hosted as a subdirectory under domain_name.com/blog.
The main blog opens up correctly. But when trying to open the wp-admin under domain_name.com/blog/wp-admin my browser shows ERR_TOO_MANY_REDIRECTS.
I am not sure if this is an issue with my NGINX configuration or wordpress configuration. Following is my NGINX server block:
server {
listen 80;
server_name <domain_name.com>;
root /var/www/html;
index index.php;
location /blog {
try_files $uri $uri/ /blog/index.php?$args;
}
location ~ \.php$ {
include fastcgi.conf;
fastcgi_intercept_errors on;
fastcgi_pass php;
}
location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
expires max;
log_not_found off;
}
}
Wordpress is installed under the /var/www/html/blog directory. And the values for "siteurl" and "home" wp_options in the database are both pointing to domain_name.com/blog.
What would be a good way to solve this problem?
Additional notes that might be helpful:
When I try to access static files under the wp-content directory, they open without any issues. No redirection errors there.
It is usual for WordPress to redirect an http session to https whenever accessing wp-admin. This may be controlled using the FORCE_SSL_LOGIN and FORCE_SSL_ADMIN settings in wp-config.php.
When a reverse proxy is terminating SSL, the fact that the originating connection is over https must be conveyed to WordPress to avoid a redirection loop.
Your reverse proxy should be setting headers such as X-Forwarded-Proto.
You need to change your nginx configuration so that the HTTPS flag is set correctly for WordPress.
For example:
map $http_x_forwarded_proto $https_flag {
default off;
https on;
}
server {
listen 80;
server_name example.com;
root /var/www/html;
index index.php;
location /blog {
try_files $uri $uri/ /blog/index.php?$args;
}
location ~ \.php$ {
include fastcgi.conf;
fastcgi_intercept_errors on;
fastcgi_param HTTPS $https_flag;
fastcgi_pass php;
}
location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
expires max;
log_not_found off;
}
}

Laravel 500 error when using with nginx

I have tried a lot of configuration settings for nginx to work with laravel but none of them do. I keep getting a 500 error on my webpage.
example.com is currently unable to handle this request.
server {
listen _:80;
server_name example.com;
root "C:\Users\Administrator\Google Drive\projects\laravel";
index index.php index.html;
log_not_found off;
charset utf-8;
access_log logs/cdn.example.com-access.log ;
location ~ /\. {deny all;}
location ~ \.css {
add_header Content-Type text/css;
}
location ~ \.js {
add_header Content-Type application/x-javascript;
}
location / {
include mime.types;
}
location = /favicon.ico {
}
location = /robots.txt {
}
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9054;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
I am pretty brand new to laravel and sort of new to nginx, I have all my laravel files in the document root that I just moved from my http://localhost:8000 development server. How can I make it live and make it work with nginx?
I can see wrong configuration in your post. You need to properly setup you web server. You should set public directory as root directory, set write permissions on a storage folder.
So, change this:
root "C:\Users\Administrator\Google Drive\projects\laravel";
To this:
root "C:\Users\Administrator\Google Drive\projects\laravel\public";
And restart your web server.

Base URLs like example.com not working in NGinx

I have 12 sites that I plan to run on a single server that has NGinx and php5-fpm on it. I set them all up using one server block per conf file, all included by the main nginx.conf file. It's a mix of Wordpress, PhpMyAdmin, and PHP sites. The wordpress and PhpMyAdmin sites are working fine, but the PHP sites are not. Meaning, when I pull up example.com, Chrome says connection refused, and there's no trace of an incoming connection on NGinx logs. test.example.com pulls up the default site(because I didn't configure test.example.com then) at the same time.
I copied the nginx configs from the working sites to set up the sites that are not working, but no luck. The only difference in nginx config between the working and non-working sites are the server_name directive.
After checking and rechecking for over 2 hours, I found out that the sites that have the server_name as pqr.example.com work, but the ones with example.com don't. All of the working sites are configured to use subdomain URLs, and that's probably why they're working.
My questions are -
1. What am I missing in the config to make the abc.com work ?
2. I have two sites, example.com and example.net that I'm trying to run on the same server. Is that going to be a problem for NGinx ?
3. Does Nginx have a problem with differentiating between example.com, test.example.com, and example.net ?
4. I also noticed that if www.example.net works, www.example.com doesn't and vice versa, which means I have to assign each site that has the name abc in it different subdomains like www.example.net and test.example.com. Is this a standard/expected behavior of Nginx, or am I missing something ?
5. All of my base URLs auto redirect from http://example.com to http://www.example.com; How do I find out where that redirect is happening ?
Below are the Nginx config files that I'm having problems with, truncated to include the important parts; Please let me know if more info is needed.
Main nginx.conf file -
user www-data www-data;
pid /var/run/nginx.pid;
worker_processes 4;
worker_rlimit_nofile 100000;
events {
worker_connections 4096;
include /etc/nginx.custom.events.d/*.conf;
}
http {
default_type application/octet-stream;
access_log off;
error_log /var/log/nginx/error.log crit;
.......
server_tokens off;
include proxy.conf;
include fcgi.conf;
include conf.d/*.conf;
include /etc/nginx.custom.d/*.conf;
}
include /etc/nginx.custom.global.d/*.conf;
Here is the full working .conf file for a blog that works. All other sites have this full config, since they are just basic PHP sites.
server {
listen *:80;
server_name blog.example.com;
access_log /var/log/nginx/blog-example.access.log;
error_log /var/log/nginx/blog-example.error.log;
root /var/www/example/blog;
index index.html index.htm index.php;
# This order might seem weird - this is attempted to match last if rules below fail.
location / {
try_files $uri $uri/ /index.php?$args;
}
# Add trailing slash to */wp-admin requests.
rewrite /wp-admin$ $scheme://$host$uri/ permanent;
# Directives to send expires headers and turn off 404 error logging.
location ~* ^.+\.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|rss|atom|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ {
access_log off; log_not_found off; expires max;
}
location = /favicon.ico {
log_not_found off;
access_log off;
}
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
# Deny all attempts to access hidden files such as .htaccess, .htpasswd, .DS_Store (Mac).
# Keep logging the requests to parse later (or to pass to firewall utilities such as fail2ban)
location ~ /\. {
deny all;
}
# Deny access to any files with a .php extension in the uploads directory
# Works in sub-directory installs and also in multisite network
# Keep logging the requests to parse later (or to pass to firewall utilities such as fail2ban)
location ~* /(?:uploads|files)/.*\.php$ {
deny all;
}
location ~ [^/]\.php(/|$) {
# Zero-day exploit defense.
# http://forum.nginx.org/read.php?2,88845,page=3
# Won't work properly (404 error) if the file is not stored on this server, which is entirely possible with php-fpm/php-fcgi.
# Comment the 'try_files' line out if you set up php-fpm/php-fcgi on another machine. And then cross your fingers that you won't get hacked.
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_index index.php;
include fcgi.conf;
fastcgi_pass unix:/var/run/php-fcgi-blog-example-php-fcgi-0.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
Here's the truncated .conf file for example.com
server {
listen *:80;
server_name example.com www.example.com test.example.com;
access_log /var/log/nginx/examplecom.access.log;
error_log /var/log/nginx/examplecom.error.log;
root /var/www/example/com;
index index.html index.htm index.php;
# This order might seem weird - this is attempted to match last if rules below fail.
location / {
try_files $uri $uri/ /index.php?$args;
}
........
location ~ [^/]\.php(/|$) {
......
fastcgi_index index.php;
include fcgi.conf;
fastcgi_pass unix:/var/run/php-fcgi-examplecom-php-fcgi-0.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
Here's the truncated file for example.net
server {
listen *:80;
server_name example.net www.example.net test.example.net;
access_log /var/log/nginx/examplenet.access.log;
error_log /var/log/nginx/examplenet.error.log;
root /var/www/example/net;
index index.html index.htm index.php;
# This order might seem weird - this is attempted to match last if rules below fail.
location / {
try_files $uri $uri/ /index.php?$args;
}
........
location ~ [^/]\.php(/|$) {
......
fastcgi_index index.php;
include fcgi.conf;
fastcgi_pass unix:/var/run/php-fcgi-examplenet-php-fcgi-0.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
Meaning, when I pull up example.com, Chrome says connection refused, and there's no trace of an incoming connection on NGinx logs. test.example.com pulls up the default site(because I didn't configure test.example.com then) at the same time.
Well, your server is listening. Chances are you haven't configured your DNS records correctly, or there is DNS caching. Set your host file to test this theory.

laravel forge set up with angularjs

I have just got forge up and running and serving my site and it works great. The frontend of my site is pure angular.
I have abstracted all of the angular aspects out of the laravel app into its own directoy on my local machine and have mapped this directory to say code/app/angular on the forge vm
the laravel app is mapped to code/app/laravel
lets say I have named the site awesome.app in the Homestead.yaml file and I have mapped that in my hosts file. what I want / need is to be able to hit awesome.app and have the angular app returned and then for any calls made by the angular app to the laravel backend to be made through awesome.app/users/1 and for the laravel app to pick that up and return the correct response. Is this possible?
so basically awesome.app should return the static files and then the laravel app should be listening for requests on awesome.app/
edit: I can create two sites on the vm one for the laravel app and one for the angular and then set up angular so its default base url is the laravel site but this is not ideal as it would mean removing that setting from angular before pushing to production
edit1: I imagine that this is going to require setting up nginx to reply with the contents of the angular folder when the root domain (awesome.app) is requested and to send the rest of the requests (awesome.app/ or awesome.app/api/)to the laravel folder. I do not know how to configure nginx at all as I was using apache until switching to homestead today.
The ultimate goal being to keep the angular and laravel codebases seperate so that I can push just the angular app to s3 and just the laravel app to ec2 / elasticbeanstalk
edit2:
Thanks fideloper I finally got a chance to try out your suggestion and I think I got most of the way there. the angular app from /home/vagrant/code/awesome/angular/build is being served correctly but the requests to the /api route are returning no input file specified. I dug around and I dont think its a permissions issue as I can access the laravel app with a vanilla homestead setup so I imagine it is something wrong with the config
the laravel app is in /home/vagrant/code/awesome/laravel with the index.php being in /public as normal. as a result I changed your suggestion slightly by moving the root to the location blocks as the roots are different for / and /api. I also tried keeping the root in the server block and adding an alias in the /api/ location block instead but this also returned no input file specified
maybe you can see where I am going wrong?
server {
listen 80;
server_name awesome.app;
index index.html index.htm;
charset utf-8;
location / {
root /home/vagrant/Code/awesome/angular/build;
try_files $uri $uri/ =404;
}
location /api/ {
root /home/vagrant/Code/awesome/laravel/public;
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \/api\/index\.php$ {
root /home/vagrant/Code/awesome/laravel/public;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi_params;
#This specifically sets so the /api/ portion
#of the URL is not included
fastcgi_param SCRIPT_FILENAME $document_root/index.php;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param ENV production;
}
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
access_log off;
error_log /var/log/nginx/awesome.app-error.log error;
error_page 404 /index.php;
sendfile off;
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
}
location ~ /\.ht {
deny all;
}
}
edit3: if I remove that second location ~ .php$ location block (which I am guessing I should) I get an actual nginx 404 html page not just a 404 with no input file specified
edit4: below config works
server {
listen 80;
server_name awesome.app;
root /home/vagrant/Code/awesome/laravel/public;
index index.html index.htm index.php;
charset utf-8;
location /api/ {
try_files $uri $uri/index.php?$query_string;
}
location / {
root /home/vagrant/Code/awesome/angular/build;
try_files $uri $uri/ index.html;
}
location ~ \/api\/index\.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi_params;
#This specifically sets so the /api/ portion
#of the URL is not included
#fastcgi_param SCRIPT_FILENAME $document_root/index.php;
#fastcgi_param PATH_INFO $fastcgi_path_info;
#fastcgi_param ENV production;
}
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
access_log off;
error_log /var/log/nginx/awesome-error.log error;
error_page 404 /index.php;
sendfile off;
location ~ \.php$ {
fastcgi_split_path_info ^(.+.php)(/.+)$;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
}
location ~ /\.ht {
deny all;
}
}
You're right on your assumption on the Nginx configuration. I would do something like this on the nginx configuration (change names or file paths as needed for Homestead. I think it puts code in /home/vagrant/www instead of /var/www for example).
One Issue
I see you are differentiating at first with the url http://awesome.app vs http://awesome.app/ - however those are effectively the same URI. I would go with your second idea of http://awesome.app/ being static and http://awesome.app/api being your Laravel app.
You have two avenues of attack (well, 2 that I'll talk to, I'm sure there' more) for that:
Have Laravel serve the HTML for the home page (what you would otherwise have in an index.html page). Then create the /api route within Laravel. This lets you use a stock Nginx configuration. The story ends there, this is the easier way.
Configure the /api/ URL in Nginx to talk to PHP, while leaving any other URL to only serve static assets. A natural consequence of this is a bit more work in in your Nginx configuration.
Here's what that might look like:
server {
listen 80;
server_name awesome.app;
root /var/www/awesome.app/public;
# Not listing index.php file here on purpose
index index.html index.htm;
charset utf-8;
access_log /var/log/nginx/awesome.app.log;
error_log /var/log/nginx/awesome.app-error.log error;
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
location / {
try_files $uri $uri/ =404;
}
# Make index.php in /api url unnecessary
location /api {
try_files $uri /api/index.php$is_args$args;
}
# Only parse PHP for /api/index.php
location ~ \/api\/index\.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi_params;
# This specifically sets so the /api/ portion
# of the URL is not included
fastcgi_param SCRIPT_FILENAME $document_root/index.php
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param ENV production;
}
}
As a result, only the /api URL will be parsed by PHP.
Now, in this setup, your laravel application might get called with the url /api/index.php, which should just work still when using a base route Route::get('/', ...);.
Personally I'd keep this simpler and not do this funky Nginx setup, since it could cause more issues than it's worth. However it all depends on your setup.

Categories