image/svg+xml

Nginx Virtual Host for redirecting non-www to www and HTTPS

In the past I had some problems with wrong redirections of my websites with the nginx webserver. Either the non-www to www or the redirect to the HTTPS version of my site didn’t worked. I figured out the problems with the help of others and some for myself and would like to show you how your virtual hosts should look like to prevent any random redirections. We desire that all requests without HTTPS or the www prefix (example.com) gets redirected to its counterpart (https://www.example.com).

At first we need to pickup all requests which address the unencrypted HTTP port 80. The server name should be here the www as well as the non-www version of your domain. Then we will make a redirect to the desired domain with www prefix and HTTPS included.

server {
    listen         80;
    listen    [::]:80;
    server_name    example.com  www.example.com;
    return         301 https://www.example.com$request_uri;
}

Now there is the possibility to call the site over HTTPS but to omit the www prefix. Here we are listening at the HTTPS port for the non-www version and redirect it to the desired format. Note that we need to include here our certificates to be able to accept the connection. In this case I have included my Let’s Encrypt certificate.

server {
    listen         443 ssl http2;
    server_name    example.com;

    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    return         301 https://www.example.com$request_uri;
}

For the last part there is only the main server block left for our desired URL format. This block listens for an incoming HTTPS request from a with a www prefixed URL. The user have typed the URL in the right format and triggered this block or more likely the block has been triggered by an redirection of one of our server blocks above. Include again here your certifactes and additional configurations by Let’s Encrypt. After this you can handle your main actions for your locations. I have added here some additions for restricting my Wordpress backend, for processing the PHP and a small block when my images, JS and CSS files should expire at.

server {
    listen        443 ssl http2 default_server;
    listen   [::]:443 ssl http2 default_server;

    root /var/www/example.com;
    index index.php index.html index.htm;

    server_name www.example.com;

    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    include             /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

    client_max_body_size 32M;

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

    location /wp-admin {
        auth_basic "Restricted";
        auth_basic_user_file /var/www/.htpasswd;
        try_files $uri $uri/ /index.php?q=$uri&$args;
    }

    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/run/php/php7.2-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }

    # cache control
    location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
        expires 7d;
    }
}