NGINX Docker with Certbot
This is a continuation of the last 2 tutorials to set up an NGINX web proxy in Docker. This time I am going to replace the self-signed TLS certificate with a "real" certificate from Let's Encrypt using Certbot. Though I had some issue with the directory structure and had to move a few things around to make this work. The final structure now looks like this:
/opt/docker-ingress
├── configuration
│ ├── conf.d
│ │ ├── buffers.conf
│ │ ├── cache.conf
│ │ ├── default.bak
│ │ ├── default.conf
│ │ ├── gzip.conf
│ │ ├── header.conf
│ │ ├── self-signed.conf
│ │ ├── ssl-params.conf
│ │ ├── test-instar-wiki.conf
│ │ └── timeouts.conf
│ ├── fastcgi.conf
│ ├── fastcgi_params
│ ├── koi-utf
│ ├── koi-win
│ ├── mime.types
│ ├── nginx.conf
│ ├── scgi_params
│ ├── ssl
│ │ ├── dhparam
│ │ │ └── dhparam.pem
│ │ ├── selfsigned
│ │ │ ├── nginx-selfsigned.crt
│ │ │ └── nginx-selfsigned.key
│ │ └── test-instar-wiki
│ ├── uwsgi_params
│ └── win-utf
└── docker-compose.yml
6 directories, 23 files
Install snapd
On Debian 9 (Stretch) and Debian 10 (Buster), snap can be installed directly from the command line:
apt update
apt install snapd
After this, install the core snap in order to get the latest snapd:
snap install core
core 16-2.47 from Canonical✓ installed
If you already have everything installed update it with snap refresh core
.
Certbot SnapApp
Remove any Certbot OS packages
If you have any Certbot packages installed using an OS package manager, you should remove them before installing the Certbot snap to ensure that when you run the command certbot the snap is used rather than the installation from your OS package manager:
apt-get remove certbot
Install Certbot
Run this command on the command line on the machine to install Certbot.
snap install --classic certbot
Warning: /snap/bin was not found in your $PATH. If you've not restarted your session since you installed snapd, try doing that. Please see https://forum.snapcraft.io/t/9469 for more details.
Execute the following instruction on the command line on the machine to ensure that the certbot command can be run.
ln -s /snap/bin/certbot /usr/bin/certbot
Run Certbot
Standalone or Webroot
My web server is not currently running on this machine.
Stop your webserver, then run this command to get a certificate. Certbot will temporarily spin up a webserver on your machine.
certbot certonly --standalone
No, I need to keep my web server running.
If you have a webserver that's already using port 80 and don't want to stop it while Certbot runs, run this command and follow the instructions in the terminal.
certbot certonly --webroot
Important Note: To use the webroot plugin, your server must be configured to serve files from hidden directories. If
/.well-known
is treated specially by your webserver configuration, you might need to modify the configuration to ensure that files inside/.well-known/acme-challenge
are served by the webserver.
Install your Certificate
certbot certonly --standalone
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator standalone, Installer None
...
Please enter in your domain name(s) (comma and/or space separated) (Enter 'c'
to cancel): test.instar.com
Obtaining a new certificate
Performing the following challenges:
http-01 challenge for test.instar.com
Waiting for verification...
Cleaning up challenges
Your certificate and chain have been saved at:
/etc/letsencrypt/live/test.instar.com/fullchain.pem
/etc/letsencrypt/live/test.instar.com/privkey.pem
To obtain a new or tweaked version of this certificate in the future, simply run certbot again. To non-interactively renew all of your certificates, run:
certbot renew
Your account credentials have been saved in your Certbot configuration directory at /etc/letsencrypt
. You should make a secure backup of this folder now. This configuration directory will also contain certificates and private keys obtained by Certbot so making regular backups of this folder is ideal.
Test Automatic Renewal
The Certbot packages on your system come with a cron job or systemd timer that will renew your certificates automatically before they expire. You will not need to run Certbot again, unless you change your configuration. You can test automatic renewal for your certificates by running this command:
sudo certbot renew --dry-run
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
** DRY RUN: simulating 'certbot renew' close to cert expiry
** (The test certificates below have not been saved.)
Congratulations, all renewals succeeded. The following certs have been renewed:
/etc/letsencrypt/live/test.instar.com/fullchain.pem (success)
** DRY RUN: simulating 'certbot renew' close to cert expiry
** (The test certificates above have not been saved.)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
The command to renew certbot is installed in one of the following locations:
/etc/crontab/
/etc/cron.*/*
systemctl list-timers
If you needed to stop your webserver to run Certbot, you'll want to add hook scripts to stop and start your webserver automatically:
sudo sh -c 'printf "#!/bin/sh\ndocker stop ingress\n" > /etc/letsencrypt/renewal-hooks/pre/docker-ingress.sh'
sudo sh -c 'printf "#!/bin/sh\ndocker start ingress\n" > /etc/letsencrypt/renewal-hooks/post/docker-ingress.sh'
sudo chmod 755 /etc/letsencrypt/renewal-hooks/pre/docker-ingress.sh
sudo chmod 755 /etc/letsencrypt/renewal-hooks/post/docker-ingress.sh
Configuring the NGINX Container
Docker Compose
/opt/docker-ingress/docker-compose.yml
version: "3.8"
services:
ingress:
image: nginx:stable-alpine
container_name: ingress
networks:
- gateway
ports:
- "80:80"
- "443:443"
restart: unless-stopped
volumes:
- /opt/docker-ingress/configuration/conf.d:/etc/nginx/conf.d
- /opt/docker-ingress/configuration/ssl/dhparam:/etc/nginx/ssl/dhparam
- /opt/docker-ingress/configuration/ssl/selfsigned:/etc/nginx/ssl/selfsigned
# - /etc/letsencrypt/live/test.instar.com:/etc/nginx/ssl/test.instar.com
- /etc/letsencrypt/archive/test.instar.com:/etc/nginx/ssl/test.instar.com
- /opt/docker-ingress/configuration/nginx.conf:/etc/nginx/nginx.conf
- /opt/test-static/public:/opt/test-static/public
networks:
gateway: {}
Virtual Server Configuration
/opt/docker-ingress/configuration/conf.d/default.conf
server {
listen 443 ssl;
listen [::]:443 ssl;
include conf.d/test-instar-wiki.conf;
include conf.d/ssl-params.conf;
server_name test.instar.com;
location / {
rewrite ^/(.*)$ https://wiki.instar.com/Quick_Installation/ONVIF/$1 permanent;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
SSL Configuration
/opt/docker-ingress/configuration/conf.d/test-instar-com.conf
ssl_certificate /etc/nginx/ssl/test.instar.com/fullchain1.pem;
ssl_certificate_key /etc/nginx/ssl/test.instar.com/privkey1.pem;
/opt/docker-ingress/configuration/conf.d/ssl-params.conf
ssl_protocols TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_dhparam /etc/nginx/ssl/dhparam/dhparam.pem;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384;
ssl_ecdh_curve secp384r1; # Requires nginx >= 1.1.0
ssl_session_timeout 10m;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off; # Requires nginx >= 1.5.9
ssl_stapling on; # Requires nginx >= 1.3.7
ssl_stapling_verify on; # Requires nginx => 1.3.7
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
# Disable strict transport security for now. You can uncomment the following
# line if you understand the implications.
# add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";