Nginx Server Block For WordPress Websites

   |  5 Apr, 2015  #

Up until a few years ago, installing WordPress on an Nginx server still tended to be a little bit janky. In the early days, many websites were forced to deal with ugly permalink schemes that included the “/index.php/” root in every single link. Even after that hurdle was eliminated, other issues existed such as poor compatibility of several WordPress plugins with Nginx, rendering many of them useless. In other cases, special rules needed to be written to the Nginx server block to make a plugin or script work properly, which left many WordPress webmasters at a complete loss of what to do.

While many of these rumors still abound, the truth is that Nginx now works perfectly with WordPress with very little configuration required (if any at all) after initial server setup has been completed. Even popular WordPress plugins like Yoast SEO erroneously claim that special re-write rules are (still) required for their plugin to work properly, which is simply not true (and hasn’t been true for at least a few years already). Moreover, even WordPress.com and other enterprise-level websites owned by Automattic (the company behind WordPress) are powered by Nginx servers and have been for years!

Unlike Apache’s “virtual hosts” or having to upload messy .htaccess files all over your server, Nginx is renowned for its powerful simplicity. Pretty much all required server security and rewrite rules can take place directly in the server block located under /etc/nginx/sites-available/default and can overwrite default rules in /etc/nginx/nginx.conf

The below Nginx server block code has been specifically optimized for WordPress speed and security, although many of the rules would apply to other CMS systems too. In general, this is the setup that we use for all LittleBizzy clients.

Note: This server block is meant to be used in conjunction with our recommended Nginx configuration. Specifically, the section on rate limiting will cause errors unless rate limiting is also enabled in your nginx.conf file too.

First, you will need to edit the default “site available” on your Nginx server:

sudo nano /etc/nginx/sites-available/default

Copy and paste entire code below, making sure to change the domain name as appropriate:

## this block redirects all HTTP non-www to HTTP www version
server {
    server_name            example.com;
    listen                 *:80;
    listen                 [::]:80 ipv6only=on;
    return 301 http://www.example.com$request_uri;
}

## this block is the default configuration for the live website
server {
    server_name            www.example.com;
    listen                 *:80 default_server;
    listen                 [::]:80;
    root                   /home/example/www;
    index index.php index.html index.htm;
    autoindex off;
    ## improve public caching (no need for Last Modified too, and eTag is enabled by default in new Nginx versions)
    expires 30d;
    add_header Cache-Control "public";
    add_header Pragma public;
    if_modified_since before;
    ## first try files, then directories, otherwise query index
    location / {
        ## force trailing slashes (don't enable for bbPress/BuddyPress)
        # rewrite ^([^.]*[^/])$ $1/ permanent;
	try_files $uri $uri/ /index.php?$args;
    }
    ## make sure PHP loads via FCGI for better performance
    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/var/run/php5-fpm.sock;
        ## if using PHP7
        # fastcgi_pass unix:/run/php/php7.0-fpm.sock;
        fastcgi_index index.php;
        ## older nginx versions use: include fastcgi_params
        include fastcgi.conf;
        ## below line should not be needed
        # include snippets/fastcgi-php.conf;
    }
    location = /wp-login.php {
        ## prevent brute force attacks (must enable in nginx.conf)
        limit_req zone=one burst=1 nodelay;
        ## re-include basic FCGI settings for PHP files
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/var/run/php5-fpm.sock;
        fastcgi_index index.php;
        ## older nginx versions use: include fastcgi_params
        include fastcgi.conf;
    }
    ## block any attempted access to dotfiles
    location ~ /\. {
        deny all;
        log_not_found off;
        access_log off;
    }
    ## no need to log any access requests for favicon
    location = /favicon.ico {
        ## 204 > 404 if favicon not found
        try_files $uri =204;
        log_not_found off;
        access_log off;
    }
    ## don't log robots file and allow any requests
    location = /robots.txt {
        allow all;
        log_not_found off;
        access_log off;
    }
    ## block any attempted XMLRPC attacks
    location = /xmlrpc.php {
        deny all;
    }
    ## comment this until WP is properly setup (blocks access)
    location = /wp-config.php {
        deny all;
    }
    ## block access to hackers checking WP version
    location ~* (licence|readme|license)\.(html|txt) {
        deny all;
    }
    ## deny access to PHP files in various directories
    location ~* /(?:uploads|files|wp-content|wp-includes)/.*\.php$ {
        deny all;
    }
    ## avoid any font problems in Firefox and IE
    location ~ \.(eot|ttf|ttc|otf|woff|woff2|svg|css|js)$ {
    add_header Access-Control-Allow-Origin "*";
    }
    ## set maximum expiry times for static files
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|mp4|svg|svgz|ogg|ogv|webm|htc)$ {
        log_not_found off;
        access_log off;
    }
    ## define error pages in the web directory
    error_page 500 502 503 504 /50x.html;
        location = /50x.html {
            root /usr/share/nginx/html;
        }
    ## flag to tell Comet Cache to shhh
    location ~* \.php$ {
      fastcgi_param WP_NGINX_CONFIG done;
  }
}

Before you restart the Nginx service be sure to test it:

sudo nginx -t

Then go ahead and restart it:

sudo service nginx restart

Tags: , , , , ,

Photo Credit: Flickr

Share This Article:

6 comments on "Nginx Server Block For WordPress Websites":

  1. Looks very interesting, although nginx failed to start with this code block at least in my case.
    What I miss about Apache is that in case of error, it tells you which line is causing problems. In this case I just get “Fail” after restarting nginx. Such a bummer.

    • Hi Mauricio, not sure if you are spamming or what, but anyway this Nginx block works like a charm on all of our client servers. Be sure you comment out the rate limiting section if you don’t enable the rate limiting that is used in our recommended nginx.conf tutorial here: https://www.littlebizzy.com/blog/nginx-configuration

    • As you can see, I’m new using nginx. My complaint was about knowing what went wrong in a particular case. In the other link I discovered the comman “sudo nginx -t”, which is precisely that. In my case (using Ubuntu 14.04), the problem was the fastcgi.conf file, which is actually fastcgi_params, as your configurations says.
      Thank you so much.

      MERGED: Thank you for your response. I’m sure I’m not spamming, I’m just trying to learn. Thank you for the link, I’ll start reading it.

    • Sorry for the confusion as some people make weird comments just to spam links! Yes that command is a perfect way to test Nginx configuration sudo nginx -t and will tell you if any problems with SSL or other settings. Cheers!

  2. Do you erase everything in the “/etc/nginx/sites-available/default” file and past this block, or do you just add this block to the bottom?

Leave a Reply

Your email address will not be published.*