Loading...

Blog

Latest blog posts

Set Https in Nginx running in a Docker container and update certs from Jenkins

What we want to do

The facts

  • Https (ssl) is a requirement in many sites.
  • Let's Encrypt offers free ssl certificates
  • We use Jenkins for admin tasks
  • We use an Nginx with Docker to publish our sites.

What we want to achieve

We want to add ssl certificates to a site inside our Nginx (that is in a Docker container), and automatize its renewals from Jenkins.

Let's do it

Create Certificates

We have used Let's Encrypt certificates and certbot to create them.

First we have installed certbot in the main machine (no Docker). In our case a Ubuntu, so:

sudo apt-get install letsencrypt 

In order to create the certificates the software needs to publish a file in the webserver (in example.com/.well-known/acme-challenge/). We have used the following volume (in docker-compose.yml file)

- ./letsencrypt/well-known:/www/letsencrypt

And published the folder (in Nginx config). Replace example.com for your site (ex: trito.dev):

location '/.well-known/acme-challenge' {
    default_type "text/plain";
    root      /www/letsencrypt/example.com/;
    allow all;
}

Now we are ready to create the certificates (Replace example.com and user):

sudo mkdir /home/user/docker/nginx/letsencrypt/well-known/example.com
sudo letsencrypt certonly --webroot -w /home/user/docker/nginx/letsencrypt/well-known/example.com -d example.com

Certificates created

Move to https

First we need to create a volume with the certificates

- /etc/letsencrypt/:/etc/letsencrypt/

Now we change nginx configuration to redirect to https. And create the new server for ssl. You will have something like:

server {
    listen 80;
    server_name example.com;

    location / {
        return 301 https://$host$request_uri;
    }

    location '/.well-known/acme-challenge' {
        default_type "text/plain";
        root      /www/letsencrypt/example.com/;
        allow all;
    }
}

server {
    listen 443 ssl;
    server_name example.com;

    # Configure file root, proxy_pass or whatever you use here

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

    ssl     on;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
    ssl_session_cache   shared:SSL:10m;
    ssl_session_timeout 10m;
    keepalive_timeout   70;

}

Moreover, we need to add 443 port from nging-docker to be linked with host 443 port (in Nginx docker-compose.yml):

    ports:
      - 80:80
      - 443:443

Done. We acces now to our website using https.

Renew certificates

To test the renew process. Using the dry-run option we will only perform a test, not update the certificates.

sudo letsencrypt renew --dry-run --agree-tos --email youremail@example.com

Renew from Jenkins

We want to create a jenkins task that will execute the renewal as a cron.

We first need to enable the letsencrypt command to be executed as sudo without password. We need to execute

sudo visudo

and add the following line (trito is the user)

trito ALL = NOPASSWD: /usr/bin/letsencrypt

We create a renew_certificates.sh with the following:

sudo letsencrypt renew --agree-tos --email youremail@example.com

And we create a jenkins task that executes the script each day.

That's all folks!