Nginx + Wordpress in subdirectory
I have recently migrated our home site to ASP.NET Core 1.0. This allowed me to move website in linux environment. We also have /blog under this site which is a wordpress blog. All migrated properly except W3 Total Cache. Here is what I did.
Installed PHP-FPM and DNX both are behind reverse proxy on Nginx. Here is folder hierarchy. /var/www/aspnet /var/www/wordpress
Here are all Nginx related config files
/etc/nginx/nginx.conf
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
log_format scripts '$document_root$fastcgi_script_name > $request';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
/etc/nginx/sites-available/xyz.com
server {
listen 443 ssl http2;
server_name xyz.com www.xyz.com;
ssl_certificate /etc/ssl/certs/cert_chain.crt;
ssl_certificate_key /etc/ssl/private/xyz.private.txt;
access_log /var/log/nginx/scripts.log scripts;
# Global restrictions configuration file.
# Designed to be included in any server {} block.
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 ~* /blog/(?:uploads|files)/.*\.php$ {
deny all;
}
gzip_types text/css text/x-component application/x-javascript application/javascript text/javascript text/x-js text/richtext image/svg+xml text/plain text/xsd text/xsl text/xml image/x-icon;
location ~ ^/blog/\.(css|htc|less|js|js2|js3|js4)$ {
expires 31536000s;
add_header Pragma "public";
add_header Cache-Control "max-age=31536000, public";
}
location ~ \.(html|htm|rtf|rtx|svg|svgz|txt|xsd|xsl|xml)$ {
expires 3600s;
add_header Pragma "public";
add_header Cache-Control "max-age=3600, public";
}
location ~ \.(asf|asx|wax|wmv|wmx|avi|bmp|class|divx|doc|docx|eot|exe|gif|gz|gzip|ico|jpg|jpeg|jpe|json|mdb|mid|midi|mov|qt|mp3|m4a|mp4|m4v|mpeg|mpg|mpe|mpp|otf|odb|odc|odf|odg|odp|ods|odt|ogg|pdf|png|pot|pps|ppt|pptx|ra|ram|svg|svgz|swf|tar|tif|tiff|ttf|ttc|wav|wma|wri|woff|xla|xls|xlsx|xlt|xlw|zip)$ {
expires 31536000s;
add_header Pragma "public";
add_header Cache-Control "max-age=31536000, public";
}
location / {
proxy_pass http://unix:/var/www/aspnet/kestrel.sock;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_cache_bypass $http_upgrade;
}
location /phpmyadmin/ {
alias /var/www/phpMyAdmin/;
index index.php;
}
location ~ ^/phpmyadmin/(.+\.php)$ {
alias /var/www/phpMyAdmin/$1;
fastcgi_pass unix:/run/php/phpmyadmin.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $request_filename;
# From fastcgi_params
fastcgi_param QUERY_STRING $query_string;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_param REQUEST_URI $request_uri;
fastcgi_param DOCUMENT_URI $document_uri;
fastcgi_param DOCUMENT_ROOT /var/www/phpMyAdmin;
fastcgi_param SERVER_PROTOCOL $server_protocol;
fastcgi_param GATEWAY_INTERFACE CGI/1.1;
fastcgi_param SERVER_SOFTWARE nginx/$nginx_version;
fastcgi_param REMOTE_ADDR $remote_addr;
fastcgi_param REMOTE_PORT $remote_port;
fastcgi_param SERVER_ADDR $server_addr;
fastcgi_param SERVER_PORT $server_port;
fastcgi_param SERVER_NAME $server_name;
fastcgi_param REDIRECT_STATUS 200;
}
location /blog/ {
try_files $uri $uri/ index.php?q=$request_uri;
alias /var/www/wordpress/;
index index.php;
}
location ~ \.php$ {
include /var/www/wordpress/nginx.conf;
try_files $uri $uri/ index.php?q=$request_uri =404;
alias /var/www/wordpress/$1;
fastcgi_pass unix:/run/php/phpmyadmin.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
# From fastcgi_params
fastcgi_param QUERY_STRING $query_string;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_param REQUEST_URI $request_uri;
fastcgi_param DOCUMENT_URI $document_uri;
fastcgi_param DOCUMENT_ROOT /var/www/wordpress;
fastcgi_param SERVER_PROTOCOL $server_protocol;
fastcgi_param GATEWAY_INTERFACE CGI/1.1;
fastcgi_param SERVER_SOFTWARE nginx/$nginx_version;
fastcgi_param REMOTE_ADDR $remote_addr;
fastcgi_param REMOTE_PORT $remote_port;
fastcgi_param SERVER_ADDR $server_addr;
fastcgi_param SERVER_PORT $server_port;
fastcgi_param SERVER_NAME $server_name;
fastcgi_param REDIRECT_STATUS 200;
}
}
/var/www/wordpress/nginx.conf - This is the file generated by W3 Total Cache plugin.
# BEGIN W3TC Page Cache core
set $w3tc_rewrite 1;
if ($request_method = POST) {
set $w3tc_rewrite 0;
}
if ($query_string != "") {
set $w3tc_rewrite 0;
}
if ($request_uri !~ \/$) {
set $w3tc_rewrite 0;
}
if ($http_cookie ~* "(comment_author|wp\-postpass|w3tc_logged_out|wordpress_logged_in|wptouch_switch_toggle)") {
set $w3tc_rewrite 0;
}
if ($http_cookie ~* "(w3tc_preview)") {
set $w3tc_rewrite _preview;
}
set $w3tc_ssl "";
if ($scheme = https) {
set $w3tc_ssl _ssl;
}
set $w3tc_enc "";
if ($http_accept_encoding ~ gzip) {
set $w3tc_enc _gzip;
}
set $w3tc_ext "";
if (-f "$document_root/var/www/wordpress/wp-content/cache/page_enhanced/$http_host/$request_uri/_index$w3tc_ssl$w3tc_rewrite.html$w3tc_enc") {
set $w3tc_ext .html;
}
if (-f "$document_root/var/www/wordpress/wp-content/cache/page_enhanced/$http_host/$request_uri/_index$w3tc_ssl$w3tc_rewrite.xml$w3tc_enc") {
set $w3tc_ext .xml;
}
if ($w3tc_ext = "") {
set $w3tc_rewrite 0;
}
if ($w3tc_rewrite = 1) {
rewrite .* "/var/www/wordpress/wp-content/cache/page_enhanced/$http_host/$request_uri/_index$w3tc_ssl$w3tc_rewrite$w3tc_ext$w3tc_enc" last;
}
# END W3TC Page Cache core
Once I have done above configuration. I am able to run permalinks of wordpress. However when I open /blog/ or /blog/wp-admin/ it shows not found. For troubleshooting purpose I added some custom logging in nginx as follows.
log_format scripts '$document_root$fastcgi_script_name > $request';
Here is what logs showed
/var/www/wordpress//blog/wp-admin/index.php > GET /blog/wp-admin/index.php HTTP/2.0 /var/www/wordpress//blog/index.php > GET /blog/ HTTP/2.0
I tried many solution. All of them assume that parent site would be wordpress. In my case parent site is built on DotNet Core 1. /blog is my wordpress blog. The issue must be one of the wrong rewrite rules.
To summarise the issue, I W3 Total Cache is not an issue. I can live without that. The issue on hand is regarding rewriting rules when you host a wordpress site as a subdomain to a static site. One can ignore W3 total cache configuration part. I have hosted site like mydomain.com/blog and rewriting rules are not getting applied. I tried many alternatives as of now. If somebody has implemented Wordpress as a pure subdirectory and not multisite subdirectory. They can provide their successful configuration.
This doesn't directly answer your question, but is probably a better option you may not have considered. Instead of using a plugin to do caching, using Nginx page caching. It's much faster because you don't have to make a call to PHP, which eliminates a lot of overhead.
The downside is it's tricky to invalidate the Nginx cache unless you pay for the commercial version of Nginx. You can build Nginx with plugins that do the job, but the Wordpress / Nginx caching integration is not great. None I've found work well. So you need to set your cache maximum life carefully. Interestingly, on a busy site caching for even a few seconds can have benefits. My sites change rarely, and if I need to I can just rm -rf the correct directories where the nginx page cache lives - which is actually in memory.
I have a tutorial on this here, and there will be many others around. There's a great article on Nginx microcaching here.
SF likes actual data on the page in case websites disappear.
In your nginx.conf
fastcgi_cache_key "$scheme$request_method$host$request_uri";
At the top of your site file, or in your nginx config
fastcgi_cache_path /dev/shm/nginxcache levels=1:2 keys_zone=CACHENAME:10m inactive=1440m; # Centos / Amazon Linux in RAM, 1440 minutes = 24 hours
In your location block that calls PHP
fastcgi_pass php56-fpm;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_cache_use_stale error timeout invalid_header http_500;
fastcgi_ignore_headers Cache-Control Expires Set-Cookie;
fastcgi_cache CACHENAME;
fastcgi_cache_valid 200 1440m;
fastcgi_cache_valid 403 404 405 410 414 301 302 307 60m;
add_header X-Cache $upstream_cache_status; # This can be removed if desired
fastcgi_cache_methods GET HEAD;
fastcgi_keep_conn on;
That tutorial I linked to has a lot more information and explanation.
You need a few steps along the way to fix the issue (from the current situation)...
In the filesystem...
See: https://codex.wordpress.org/Giving_WordPress_Its_Own_Directory
Move WordPress core files from
/var/www/wordpress
to/var/www/wordpress/blog
. (Hint:mv /var/www/wordpress /var/www/blog && mkdir /var/www/wordpress && mv /var/www/blog /var/www/wordpress
)Copy
/var/www/wordpress/blog/index.php
to the directory/var/www/wordpress/
.Edit the
/var/www/wordpress/index.php
file and change the linerequire( dirname( __FILE__ ) . '/wp-blog-header.php' );
torequire( dirname( __FILE__ ) . '/blog/wp-blog-header.php' );
.
Nginx:
Now, the Nginx part. Here are the changes in the relevant part/s...
location /blog {
root /var/www/wordpress;
index index.php;
try_files $uri $uri/ /blog/index.php?q=$request_uri;
}
location ~ \.php$ {
root /var/www/wordpress;
index index.php;
try_files $uri $uri/ /blog/index.php?q=$request_uri =404;
# other configuration directives
}
There are two primary changes:
- The
alias
directive becomesroot
- The
try_files
directive contains/blog/
beforeindex.php
.
I hope this helps!