WordPress Nginx Configuration

Nginx server block configuration for WordPress with WP Super Cache and fastcgi cache.

Table of Contents

Discuss WordPress and Centmin Mod Nginx on the community forums. If you prefer Memcached caching, see the WP-FFPC Plugin guide.

MySQL Database Setup

Enable InnoDB MySQL Engine and Table support by ensuring your MySQL config settings for /etc/my.cnf have the following InnoDB related settings set:

innodb=ON
default-storage-engine = InnoDB

For server-wide MySQL global UTF-8 support, add under [mysqld] group in /etc/my.cnf:

[mysqld]
 character-set-server=utf8

Restart MySQL server:

service mysql restart
# or via Centmin Mod shortcut:
mysqlrestart

Basic Nginx WordPress Configuration

Step 1: Enable WordPress Permalinks

Edit your site's Nginx vhost configuration file and add the following location block, then restart Nginx:

location /wordpress {
    try_files $uri $uri/ /wordpress/index.php?q=$request_uri;
}

Where /wordpress is where you installed WordPress, e.g. yourdomain.com/wordpress.

Step 2: Create wpsecure.conf

Create /usr/local/nginx/conf/wpsecure.conf:

# Deny access to any files with a .php extension in the uploads directory
location ~* /(?:uploads|files)/.*\.php$ {
    deny all;
}

# Block source code files that may contain passwords
location ~* \.(engine|inc|info|install|make|module|profile|test|po|sh|.*sql|theme|tpl(\.php)?|xtmpl)$|^(\..*|Entries.*|Repository|Root|Tag|Template)$|\.php_
{
    return 444;
}

#nocgi
location ~* \.(pl|cgi|py|sh|lua)\$ {
    return 444;
}

#disallow
location ~* (roundcube|webdav|smtp|http\:|soap|w00tw00t) {
    return 444;
}

location ~ /(\.|wp-config\.php|readme\.html|license\.txt) { deny all; }

Step 3: Create wpnocache.conf

Create /usr/local/nginx/conf/wpnocache.conf:

# Add trailing slash to */wp-admin requests.
rewrite /wp-admin$ $scheme://$host$uri/ permanent;

Step 4: Configure Nginx Vhost

Add the includes and try_files for WordPress permalinks to your vhost config:

server {
    listen   80;
    server_name localhost;
    root   html;

    location / {
        # autoindex  on;
    }

    location /wordpress {
        include /usr/local/nginx/conf/wpsecure.conf;
        include /usr/local/nginx/conf/wpnocache.conf;
        try_files $uri $uri/ /index.php?q=$request_uri;
    }

    include /usr/local/nginx/conf/staticfiles.conf;
    include /usr/local/nginx/conf/php.conf;
    include /usr/local/nginx/conf/drop.conf;
    #include /usr/local/nginx/conf/errorpage.conf;
}

Advanced: WordPress + fastcgi_cache + Nginx Helper

Step 1: Add fastcgi_cache to nginx.conf

Edit /usr/local/nginx/conf/nginx.conf (shortcut: nginxconf) and add below the http { block:

http {
include /usr/local/nginx/conf/wp_fastcgicache.conf;

Create /usr/local/nginx/conf/wp_fastcgicache.conf (ensure /var/cache/nginx exists):

fastcgi_cache_path /var/cache/nginx levels=1:2 keys_zone=WPCACHE:16m max_size=32m inactive=50m;
fastcgi_cache_key "$scheme$request_method$host$request_uri";
fastcgi_cache_use_stale error timeout invalid_header http_500;

log_format cache '$remote_addr - $remote_user [$time_local]  '
                  '"$request" $status $body_bytes_sent '
                  '"$http_referer" "$http_user_agent" nocache:$no_cache '
                  '$upstream_cache_status';

### Map Mobile
map $http_user_agent $is_mobile {
    default 0;
    ~*android|ip(hone|od)|windows\s+(?:ce|phone) 1;
    ~*symbian|sonyericsson|samsung|lg|blackberry 1;
    ~*mobile 1;
}

Step 2: Create wpcache.conf

Create /usr/local/nginx/conf/wpcache.conf with fastcgi cache bypass rules:

#fastcgi_cache start
set $no_cache 0;

# POST requests and urls with a query string should always go to PHP
if ($request_method = POST) {
    set $no_cache 1;
}
if ($query_string != "") {
    set $no_cache 1;
}

# Don't cache uris containing the following segments
if ($request_uri ~* "/\?add-to-cart=|cart/|my-account/|checkout/|shop/checkout/|store/checkout/|customer-dashboard/|addons/|(memcache\.php|apc\.php|wp-admin/.*|xmlrpc\.php|wp-(app|cron|login|register|mail)\.php|wp-.*\.php|feed/|index\.php|wp-comments-popup\.php|wp-links-opml\.php|wp-locations\.php|sitemap(_index)?\.xml|[a-z0-9_-]+-sitemap([0-9]+)?\.xml)") {
    set $no_cache 1;
}

# Don't use the cache for logged in users or recent commenters
if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in|edd_items_in_cart|woocommerce_items_in_cart|wordpress-sec") {
    set $no_cache 1;
}

# Add trailing slash to */wp-admin requests.
rewrite /wp-admin$ $scheme://$host$uri/ permanent;

# Centmin Mod Nginx has nginx_cache_purge module
location ~ /purge(/.*) {
    fastcgi_cache_purge WPCACHE "$scheme$request_method$host$1";
    return 200;
    allow 127.0.0.1;
    deny all;
}

Step 3: Create phpwpcache.conf

Duplicate php.conf and add fastcgi cache directives at the bottom:

cp -a /usr/local/nginx/conf/php.conf /usr/local/nginx/conf/phpwpcache.conf

Add these lines at the bottom of phpwpcache.conf just above the last closing brace }:

    fastcgi_cache_bypass $no_cache $is_mobile;
    fastcgi_no_cache $no_cache $is_mobile;
    fastcgi_cache WPCACHE;
    fastcgi_cache_valid  200 302 2m;
    fastcgi_cache_valid  301 1h;
    fastcgi_cache_valid  any 2m;
    fastcgi_cache_min_uses  1;
    add_header X-Cached $upstream_cache_status;

Step 4: Complete Vhost Configuration

Example vhost for WordPress installed at /wp:

server {
    listen   80 default_server;
    server_name localhost;
    root   html;

    access_log /var/log/nginx/localhost.access.log main buffer=32k;
    error_log  /var/log/nginx/localhost.error.log  error;
    access_log /var/log/nginx/access.cache.log cache;

    # ngx_pagespeed & ngx_pagespeed handler
    include /usr/local/nginx/conf/pagespeed.conf;
    include /usr/local/nginx/conf/pagespeedhandler.conf;

    location / {
        #include /usr/local/nginx/conf/block.conf;
    }

    location /wp {
        include /usr/local/nginx/conf/wpsecure.conf;
        include /usr/local/nginx/conf/wpcache.conf;
        include /usr/local/nginx/conf/phpwpcache.conf;
        try_files $uri $uri/ /wp/index.php?q=$request_uri;
    }

    include /usr/local/nginx/conf/staticfiles.conf;
    include /usr/local/nginx/conf/php.conf;
    include /usr/local/nginx/conf/drop.conf;
    #include /usr/local/nginx/conf/errorpage.conf;
}

Root install note: If WordPress is installed at root / instead of a subdirectory, use phpwpcache.conf instead of php.conf in the includes, and place wpsecure.conf and wpcache.conf inside the root location / block.

Step 5: Restart Nginx

service nginx restart
# or via command shortcut:
ngxrestart

Nginx Helper WordPress Plugin

Install the Nginx Helper WordPress plugin. The plugin has a hard-coded cache path of /var/run/nginx-cache which differs from the /var/cache/nginx path used above.

Add this line to wp-config.php to fix the cache path:

define( 'RT_WP_NGINX_HELPER_CACHE_PATH','/var/cache/nginx');

Advanced: fastcgi_cache + ngx_pagespeed (Deprecated)

Deprecated

The ngx_pagespeed module has been deprecated and removed from all Centmin Mod branches. The NGINX_PAGESPEED='y' variable no longer works. This content is retained for historical reference.

Follow the advanced WordPress + fastcgi_cache guide above and then enable the Nginx ngx_pagespeed module.

The ngx_pagespeed module makes most WordPress cache plugins redundant (W3 Total Cache, WP Super Cache) since it minifies, combines, and caches CSS and JS at the Nginx level.

Performance results: Testing with the Responsive WordPress theme showed approximately 24.5% faster page load times, 27.5% faster onload times, and reduced HTTP requests when ngx_pagespeed + combine_javascript filter was enabled. Chrome PageSpeed scores improved from 94 to 98.