Hosting WordPress Yourself Part 8 – Complete Nginx Configuration

In the previous post of this series, I covered security enhancements, automatic server updates, WooCommerce caching and automated server tasks. In this final post I will demonstrate a complete Nginx configuration tuned for WordPress powered sites. In addition to amalgamating all information from the previous 7 articles, best practices from various sources, such as the WordPress Codex and H5BP are included. The following example domains are also included, which each demonstrate a different scenario:

  • singlesite.com – A basic WordPress install
  • ssl.com – WordPress on HTTPS
  • fastcgi-cache.com – WordPress with FastCGI page caching
  • ssl-fastcgi-cache.com – WordPress on HTTPS with FastCGI page caching
  • multisite-subdomain.com – WordPress Multisite using subdomains
  • multisite-subdirectory.com – WordPress Multisite using subdirectories

Although this article may appear relatively short compared to previous articles, I hope the accompanying GitHub repo will provide a wealth of information. The configuration files contain inline documentation throughout and are structured in a way to reduce duplicate directives, which are common across multiple sites. This should allow you to quickly create new sites with sensible defaults out of the box, which can be customized as required.

Usage

You can use the GitHub repo as a reference for creating your own configuration, or directly by cloning the repo into your etc directory. Follow the steps below to replace your existing Nginx configuration.

Backup any existing config:

sudo mv /etc/nginx /etc/nginx.backup

Clone the repo:

sudo git clone https://github.com/A5hleyRich/wordpress-nginx.git /etc/nginx

Copy one of the example configurations from sites-available to sites-available/yourdomain.com:

sudo cp /etc/nginx/sites-available/ssl.com /etc/nginx/sites-available/yourdomain.com`

Edit the site accordingly, paying close attention to the server name and server paths. You will also need to create any directories used within the configuration and ensure Nginx has read/write permissions.

To enable the site, symlink the configuration into the sites-enabled directory:

sudo ln -s /etc/nginx/sites-available/yourdomain.com /etc/nginx/sites-enabled/yourdomain.com

Test the configuration:

sudo nginx -t

If the configuration passes, restart Nginx:

sudo /etc/init.d/nginx reload

The following configuration will be loaded, which includes sensible defaults for security, SSL and static file caching:

server {
    # Ports to listen on, uncomment one.
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    # Server name to listen for
    server_name ssl.com;

    # Path to document root
    root /sites/ssl.com/public;

    # Paths to certificate files.
    ssl_certificate /etc/ssl/ssl.com.crt;
    ssl_certificate_key /etc/ssl/ssl.com.key;

    # File to be used as index
    index index.php;

    # Overrides logs defined in nginx.conf, allows per site logs.
    access_log /sites/ssl.com/logs/access.log;
    error_log /sites/ssl.com/logs/error.log;

    # Default server block rules
    include global/server/defaults.conf;

    # SSL rules
    include global/server/ssl.conf;

    location / {
        try_files $uri $uri/ /index.php?$args;
    }

    location ~ \.php$ {
        try_files $uri =404;
        include global/fastcgi-params.conf;

        # Change socket if using a different PHP version
        fastcgi_pass unix:/run/php/php7.1-fpm.sock;
        #fastcgi_pass unix:/run/php/php7.0-fpm.sock;
        #fastcgi_pass unix:/var/run/php5-fpm.sock;
    }
}

# Redirect http to https
server {
    listen 80;
    listen [::]:80;
    server_name ssl.com www.ssl.com;

    return 301 https://ssl.com$request_uri;
}

# Redirect www to non-www
server {
    listen 443;
    listen [::]:443;
    server_name www.ssl.com;

    return 301 https://ssl.com$request_uri;
}

View on GitHub

Job done! I encourage you to explore the repo further and read through the documented configuration to get a feel for what’s going on. It should hopefully feel familiar as it follows the same conventions used throughout this series. Over time I hope to improve upon the configuration and add new best practices as they emerge. It’s also a public repo, so please open a pull request for any improvements you may have.

That concludes this article and the series as a whole. It’s been quite a journey, but one that I hope you’ve found enlightening. Please feel free to leave your questions below and any ideas you may have for future articles. Thanks for reading!

About the Author

Ashley Rich

Ashley is a PHP and JavaScript developer with a fondness for solving complex problems with simple, elegant solutions. He also has a love affair with WordPress and learning new technologies.

  • Daylighter

    Thanks for the guide!

    They were very simple to follow and still explains why each step is done.

  • Selçuk Vardar

    Ashley, you tutorial is great! Thanks a million above all.

    I have done all the steps and my blitz.io tests were perfect as expected with twentyfifiteen but after I installed my WP theme they became terrible:

    This rush generated 3 successful hits in 60 seconds and we transferred 1.22 MB of data in and out of your app. The average hit rate of 0.05/secondtranslates to about 4,320 hits/day.

    The average response time was 656 ms.

    You’ve got bigger problems, though: 99.88% of the users during this rushexperienced timeouts or errors!
    I really appriciate if you have any idea or suggestion.

  • Jhonis

    Thumbs up Ashley! Thanks for the great, and easy to follow tutorial.

    And a million thanks for the 2017 update!

  • Jhonis

    Hey Ashley,

    Everything’s been working out great up until I switched the nginx directory to match the git repository example on this page.

    Now I’m getting a 502 Bad Gateway page on a site that was working before the change.

    Did I miss something?

    • I get 502 Bad Gateway as well.

      • Jhonis

        make sure your nginx.conf has your user set, and not www-data;

        I’f you’ve been following the series, most likely you have set up your own user.

        That was my problem, and was easy to fix

        • Thanks, I reverted to the old nginx. I will try this again later 🙂