Before you begin

In this tutorial will learn how to install Let’s Encrypt certs on a dockerized Nginx and automatically redirect non-HTTPS requests and www to non-www avoiding further SEO content duplication. In order to do that we need the following requirements:

  • Linux machine/server (with a domain/subdomain and DNS pointing to the machine IP)
  • Docker

Run Nginx from a docker image

To run Nginx using we can use the following command;

$ mkdir -p /var/www/html # website folder
$ mkdir -p /var/opt/ssl # certificates folder
$ mkdir -p /var/opt/nginx/sites-available # Nginx site configuration

$ docker run -d --name my-nginx \
-v /var/www/html:/var/www/html:ro \
-v /var/opt/ssl:/etc/ssl/:ro \
-v /var/opt/nginx/sites-available/:/etc/nginx/sites-available/:ro \
-p 80:80 \
-p 443:443 \
nginx:1.11-alpine

And these commands to make sure the container is running and we can reach it from the host:

$ docker ps | grep my-nginx

$ curl localhost:80

In this tutorial we are using nginx:1.11-alpine image because is a small image and does everything we need but other nginx offical images are available here

Finally, we are assuming that he content of the website is at /var/www/html otherwise nginx will not serve the site.

Stop server and create Let’s Encrypt certificates

Stop Nginx webserver:

$ docker stop my-nginx

Run letsencrypt docker image:

$ sudo docker run -it --rm -p 443:443 -p 80:80 --name certbot \
            -v "/etc/letsencrypt:/etc/letsencrypt" \
            -v "/var/lib/letsencrypt:/var/lib/letsencrypt" \
            quay.io/letsencrypt/letsencrypt:latest certonly

Copy certificates files from letsencrypt live folder to the shared host certificates folder:

$ mkdir -p /var/opt/ssl/

$ cp /etc/letsencrypt/live/[MY_DOMAIN]/fullchain.pem /var/opt/ssl/
$ cp /etc/letsencrypt/live/[MY_DOMAIN]/cert.pem /var/opt/ssl/
$ cp /etc/letsencrypt/live/[MY_DOMAIN]/privkey.pem /var/opt/ssl/

Specify certs and Redirect non-HTTPS traffic to HTTPS / www to non-www using Nginx

Once the certificates are created we need to create a file /var/opt/nginx/sites-available/default.conf with the following content:

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

server {
    listen 443 ssl;
    server_name www.example.com;
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    ssl_trusted_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    return 301 https://example.com$request_uri;
}

server {
	listen 443 ssl;
	server_name example.com;
  ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
  ssl_trusted_certificate /etc/letsencrypt/live/example.com/fullchain.pem;

	root /var/www/html;

	# Add index.php to the list if you are using PHP
	index index.html index.htm index.nginx-debian.html;

	location / {
		# First attempt to serve request as file, then
		# as directory, then fall back to displaying a 404.
		try_files $uri $uri/ =404;
	}

}

This file specifies where are the certificates and provides the required redirections.

Re-start Nginx

Once the certificates and the previous configuration are in place we can execute the following command to re-start Nginx:

$ docker start my-nginx

Make sure the following 4 cases (replacing example.com for your website) are redirecting to https://www.example.com:

  • http://example.com
  • http://www.example.com
  • https://example.com
  • https://www.example.com

Bonus track: Nginx redirections per page

If after placing all these HTTPS and non-www redirections you still need to redirect a specific page you could do it following these examples. the first one is a temporary redirection and the last one is a permanent redirection using Nginx.

server {
	...
  # This is a temporary redirection (302)
  rewrite ^/foo/bar/old_page.html$ https://example.com/foo/bar/new_page.html redirect;

  # This is a permanent redirection (301)
  rewrite ^/foo/bar/old_page.html$ https://example.com/foo/bar/new_page.html permanent;
  ...
}