
How to set HTTPS with Certbot for Nginx on Docker
Certbot is an awesome tool to help you enable HTTPS with Let's Encrypt. It provides several instructions guiding you how to setup HTTPS. However I was blocked when I run it with the following command because... my nginx is running on docker, the cerbot failed to find the nginx instance.
sudo certbot --nginxAfter some investigation, I figured out a way to set up dockerized nginx with certbot.
Docker compose and bind mount
- create two empty directories on the docker host at the same directory with the docker-compose file:
./certbot/wwwand./certbot/conf - suppose the nginx has been already set up in the docker-compose file, add the certbot together with two volumes as follows,
services:
nginx:
build: ./nginx_home
container_name: nginx
ports:
- "80:80"
networks:
- webapp
restart: always
volumes:
- ./certbot/www/:/var/www/certbot/:ro
- ./certbot/conf/:/etc/nginx/ssl/:ro
certbot:
image: certbot/certbot:latest
volumes:
- ./certbot/www/:/var/www/certbot/:rw
- ./certbot/conf/:/etc/letsencrypt/:rw
Explanations:
- The
certbotwill store the certificates under the directory/etc/letsencryptwhich is mapped to the./cerbot/confon host, on the other hand,.certbot/confis also mounted to/etc/nginx/ssldirectory onnginxcontainer. - The other shared directory
./certbot/wwwis used for the HTTP-01 challenge. Once you get a certificate,Let's encryptvalidates that you control the domain names withchallenges, in a nutshell, it issues a token then verifiy it with a http request to your web server like below,
So, to pass the challenge the nginx config file also needs to be updated to expose the token,
server {
listen 80;
listen [::]:80;
server_name [YOUR_DOMAIN]
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
...
}Run the certbot
Use docker compose run to obtain a certificate, you'd better to apply with --dry-run for a test first as Let's Encrypt limits the available free cerfitificates per month.
docker compose run --rm certbot \
certonly --webroot --webroot-path /var/www/certbot/ --dry-run -d [YOUR_DOMAIN]You probably need to provide your email address and consent the Terms of Service.
if everything goes well you can run the above command without the --dry-run flag.
Configure the certificates with Nginx
Now you should have your certificates under the directory ./certbot/conf/live/[YOUR_DOMAIN], it's time to configure the nginx with the certificates as follows,
and it's better to add a 301 redirect to prevent the http access.
server {
listen 80;
listen [::]:80;
server_name [YOUR_DOMAIN]
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://[YOUR_DOMAIN]$request_uri;
}
...
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name [YOUR_DOMAIN];
ssl_certificate /etc/nginx/ssl/live/[YOUR_DOMAIN]/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/live/[YOUR_DOMAIN]/privkey.pem;
location / {
proxy_pass http://webapp:3000;
}
...
}Renew certificates
Let's Encrypt certificates only last for three month, to renew it, run the following command,
docker compose run --rm certbot renew --webroot --webroot-path /var/www/certbot/Side notes
- Don't forget to add the 433 listening in the nginx config
- Don't forget to enable the firewall of your server before testing the https.
- You can test the certificates with
openssl s_client -connect [YOUR_DOMAIN]:443 -showcerts - If you need to expand the certificate's domain, use
certbot certonly --cert-name example.com --webroot --webroot-path /var/www/certbot/ -d example.com,www.example.com