Homepage loads but all permalinks are 404 when using nginx & PHP-FPM

It turns out that the nginx config that W3 Total Cache inserts if Disk Enhanced mode is enabled will break permalinks, but only if you restart nginx after W3 Total Cache injects the config for Disk Enhnaced mode.

Based on birgire’s suggestion, I turned off all plugins and checked the site, which started working correctly. I then turned on W3 Total Cache and surprise! the site continued to work correctly. It continued to work correctly until I restarted nginx at which point the nginx.conf file that W3 Total Cache created was loaded and the site broke. What’s causing this behavior is the following line:

if ($w3tc_rewrite = 1) {
rewrite .* "/wp-content/cache/page_enhanced/$http_host/$request_uri/_index$w3tc_rewrite$w3tc_ext" last;
}

When nginx is restarted, the above line gets loaded and all URLs are redirected to to cached HTML files in wp-content/cache/page_enhanced. On the restart though, the HTML files are purged and hence links become 404. The solution I came up with was first to change permissions on the nginx config file that W3 Total Cache normally writes to so that it could not be overwritten. I then changed the above config:

location / {
    rewrite ^(.*\/)?w3tc_rewrite_test/?$ $1?w3tc_rewrite_test=1 last;
    if ($w3tc_rewrite = 1) {
        rewrite .* "/wp-content/cache/page_enhanced/$http_host/$request_uri/_index$w3tc_rewrite$w3tc_ext" last;
    }
    try_files $uri $uri/ /index.php?$args;
} 

The config does a couple of things – the original rewrite line is wrapped inside a location block so that even if the HTML file is not located, it falls back to a regular index.php rendering model. In addition, the w3tc_rewrite_test line is to eliminate an error in the Dashboard. I’m doing this in a separate file to centralize my W3 TC config so there are two location \ directives for my site.

For extra credit, it turns out that the nginx config for W3 Total Config’s minify module is broken as well. Here is a working config1:

#Test Rewrites
    location ~ ^/wp-content/cache/minify/[^/]+/(w3tc.*)$ {
                   try_files $uri /wp-content/plugins/w3-total-cache/pub/minify.php?w3tc_rewrite_test=$1;
           }
#End Test Rewrites
# BEGIN W3TC Minify core
    set $w3tc_enc "";
    location ~ ^/wp-content/cache/minify/(.+/[X]+\.css)$ {
                try_files $uri /wp-content/plugins/w3-total-cache/pub/minify.php?test_file=$1;
    }
    location ~ ^/wp-content/cache/minify/(.+\.(css|js))$ {
                try_files $uri /wp-content/plugins/w3-total-cache/pub/minify.php?file=$1;
    }

# END W3TC Minify core

Since a lot of WordPress/W3 Total Cache info is version dependent, here’s the version info for the above config: W3 Total Cache v0.9.4 / WordPress 4.0 / nginx 1.6.2-2~bpo70+1


1 https://rtcamp.com/wordpress-nginx/tutorials/single-site/w3-total-cache/

Leave a Comment