Over the past few months I’ve been working with WordPress sites a surprising amount. During this same time, I decided to switch all of my sites over to HTTPS exclusively. The switch was relatively painless, especially since free SSL certificate are now available.

I started with the HTML 5 Boilerplate team’s Nginx configuration snippets maintained by Andy Dawson. I had to make a few adjustments to them related to SSL and PHP but a majority of their defaults I didn’t need to touch at all.

Nginx Redirects

The Nginx return directive can be used to efficiently return a code and optional URL to the client. When redirecting to SSL or www to non-www, you’ll generally want to return 301 Moved Permanently. Rather than including an if statement in your existing server block, a more efficient way for to handle Nginx redirects is to separate the two servers.

server {
    listen 80;
    server_name www.rudeotter.com;
    return 301 http://example.org$request_uri;
}

server {
    listen 80;
    server_name rudeotter.com;
    ...
}

Here the first server block is listening on the www subdomain and simply passes any request on to the root domain that has been configured to actually serve your site. That’s really all it takes to do a basic Nginx redirect! Below are some sample redirects that you’ll likely encounter and explanations for what’s happening.

Redirecting HTTP to HTTPS

server {
    listen [::]:80;
    listen 80;
    server_name rudeotter.com www.rudeotter.com;

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

This first block just redirects HTTP connections to HTTPS. The listen directive sets the port and address Nginx will listen on. The first one enables IPv6 support and the second is our standard IPv4. Since no specific addresses are used, Nginx will bind to all interfaces rather than a specific IP address. The server_name directive defines the virtual server names

On the second to last line, return is used for a Nginx redirect to HTTPS. The 301 indicates that this is a permanent redirect.

Redirecting HTTPS requests to preferred URL

server {
    listen [::]:443 ssl spdy;
    listen 443 ssl spdy;
    server_name www.rudeotter.com;

    ssl_certificate /srv/ssl/rudeotter.crt;
    ssl_certificate_key /srv/ssl/rudeotter.key;

In this block listen is listening to port 443. The ssl parameter enables HTTPS and spdy enables the SPDY protocol that Google is developing with the goal of reducing page latency.

The final two lines define the certificate file and the private key used for SSL. I have my certificate and key in a server block, but Nginx recommends putting them in the http level for memory efficiency if your certificate is valid for multiple domains.

    include h5bp/directive-only/ssl.conf;
    include h5bp/directive-only/ssl-stapling.conf;
    include h5bp/directive-only/spdy.conf;

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

The three include lines pull in additional settings from the HTML5 Boilerplate server snippets for SSL, OCSP, and SPDY. OCSP Stapling (ssl-stapling.conf) improves SSL negotiation by having the browser request certificate validation rather than downloading large lists of revoked certificates Requests. At the end, Nginx redirects requests to our preferred domain with HTTPS using return once more.

PHP for WordPress over HTTPS

server {
    listen [::]:443 ssl spdy;
    listen 443 ssl spdy;
    server_name rudeotter.com;

    ssl_certificate /srv/ssl/rudeotter.crt;
    ssl_certificate_key /srv/ssl/rudeotter.key;

    include h5bp/directive-only/ssl.conf;
    include h5bp/directive-only/ssl-stapling.conf;
    include h5bp/directive-only/spdy.conf;

    rewrite ^/sitemap_index\.xml$ /index.php?sitemap=1 last;
    rewrite ^/([^/]+?)-sitemap([0-9]+)?\.xml$ /index.php?sitemap=$1&sitemap_n=$2 last;

Only the last two lines are new and are similar to a Nginx redirect using return. In this case, the rewrite directives use regular expressions to modify the requested URI rather than redirecting the user. This is used by the Yoast WordPress SEO plugin for sitemap generation.

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

    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/var/run/php5-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
    }

    include h5bp/basic.conf;
    include conf.d/*.conf;
}

Despite being the first location directive, this one is intended to only apply if the one below fails. It uses try_files to check for the existence of the requested file in the order listed, returning the first one found. First it checks for the request as a file and then as a directory. If those do not exist, the last parameter is used sending the request to PHP.

The second location directive only allows files ending in .php. The tilde ~ indicates case-sensitive matching, the backslash before a period \. is an actual period, and the dollar sign $ is the ending of the string.

If the PHP file being requested does not exist, try_files returns a 404 error. The directive fastcgi_split_path_info defines a regex that splits a request into the SCRIPT_FILENAME and PATH_INFO parameters. fastcgi_pass sets the address of the FastCGI server in this case a Unix domain socket is used rather than an IP address. fastcgi_index sets the file name that will be appending after a URI ending in a slash. The ngx_http_fastcgi_module documentation has details and examples.

Finally, the include for basic.conf imports rules recommended to always be applied. The include for conf.d just turns off logging for a few files that I didn’t want to see in my Nginx logs anymore.

This Nginx redirect configuration file is available on GitHub.

%d bloggers like this: