If you’re running Nginx in a Docker container (for example, on a Raspberry Pi or a self-hosted server), and your domains are managed through Azure DNS or AWS Route 53, this step-by-step guide will show you how to automatically renew Let’s Encrypt SSL certificates using Certbot with the webroot
method.
1. Prerequisites
Before getting started, make sure you have:
- Docker and
docker-compose
installed - Certbot installed on the host system (not inside the container)
- Nginx running inside a Docker container
- Access to your DNS zone (Azure or AWS)
- A domain pointing to your public IP (check with https://whatismyip.com)
2. Your docker-compose.yml
Setup
Here’s a sample docker-compose.yml
configuration for Nginx:
version: '3'
services:
nginx:
image: nginx:latest
container_name: nginx
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf
- /usr/share/nginx/html:/usr/share/nginx/html
- /etc/letsencrypt:/etc/letsencrypt:ro
ports:
- "80:80"
- "443:443"
networks:
- default
- yourproject_wp_net
networks:
yourproject_wp_net:
external: true
Make sure to mount /usr/share/nginx/html
since Certbot will place temporary challenge files there.
3. First-time Certificate Issuance with Certbot (using webroot
)
Use the webroot
method to avoid stopping Nginx and prevent port conflicts:
sudo certbot certonly --webroot \
-w /usr/share/nginx/html \
-d yourdomain.com -d www.yourdomain.com \
--cert-name yourdomain.com
This command will request a new certificate if everything is configured correctly.
⚠️ IMPORTANT: Make sure yourdomain.com
and www.yourdomain.com
point to your public IP. Use dig yourdomain.com +short
to confirm.
4. Reloading Nginx When Certificates Are Renewed
Create this script at:
/etc/letsencrypt/renewal-hooks/deploy/reload_nginx_docker.sh
With the following contents:
#!/bin/bash
# Script to reload Nginx inside Docker
echo "Reloading Nginx container..."
docker-compose -f /path/to/your/docker-compose.yml exec nginx nginx -s reload || \
docker-compose -f /path/to/your/docker-compose.yml restart nginx
Make it executable:
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload_nginx_docker.sh
5. Automate Renewals with Cron
Edit your system’s crontab:
sudo crontab -e
Add this line to run every midnight:
0 0 * * * certbot renew --webroot -w /usr/share/nginx/html
Certbot will run your reload script automatically after a successful renewal.
6. Verify That Everything Works
Run a dry run to simulate the renewal process:
sudo certbot renew --dry-run
Also, test if the challenge path is being served:
curl http://yourdomain.com/.well-known/acme-challenge/test.txt
Manually create that file inside /usr/share/nginx/html/.well-known/acme-challenge/
to verify Nginx is exposing it.
7. If Your Domain is Managed in AWS Route 53
If you use AWS Route 53 instead of Azure, you can use Certbot’s DNS plugin:
sudo certbot -a dns-route53 -d yourdomain.com -d www.yourdomain.com
Make sure your AWS credentials are configured in ~/.aws/credentials
.
This is helpful if you can’t expose ports 80/443 due to firewalls or NAT restrictions.
⚠️ 8. Common Issues and Fixes
Error | Cause | Solution |
---|---|---|
bind: address already in use | System Nginx running outside Docker | Stop it with sudo systemctl stop nginx |
Some challenges have failed | Domain doesn’t point to your IP | Double-check DNS records and IP |
Unable to find a Route53 hosted zone | Domain not in AWS | Use webroot method or DNS plugin for Azure |
Conclusion
With this setup:
- Your SSL certificates will renew automatically via
certbot renew
- Your Nginx container will reload itself without downtime
- Works with Azure or AWS domains
- You retain full control without relying on external Certbot containers
Did This Guide Help You?
Leave a comment or share your setup! Hopefully, this saved you hours of debugging like it did for me. 😉
