Certificates
This document describes how to add certificates to your site using certbot
, docker
, and nginx
. For this process, the site must be already running on HTTP
.
Step 1: Edit docker compose file
Edit your docker compose file to add the certbot
service:
certbot:
image: certbot/certbot:latest
volumes:
- ./certbot/www/:/var/www/certbot/:rw
- ./certbot/conf/:/etc/letsencrypt/:rw
You also need to add these two lines as new volumes to the nginx
service to ensure it has access to the certificates. The compose file with both services should look like this:
services:
webserver:
image: nginx:latest
ports:
- 80:80
- 443:443
restart: always
volumes:
- ./nginx/conf/:/etc/nginx/conf.d/:ro
# Certbot configuration
- ./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
Now, run docker compose --build -d
to install the certbot
service. This command only installs the service; the certificate configuration is added in the next steps.
Step 2: Nginx http configuration
In your nginx
configuration file, you already have some server configuration on port 80
for HTTP
. We need to do two things now, add the following location to this server configuration:
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
This step is necessary for certbot
configuration. Then, you need to add, or replace if you already have it, the root location to this:
location / {
return 301 https://[domain-name]$request_uri;
}
This tell nginx
to redirect the traffic from HTTP
to HTTPS
. The final configuration should look something like this:
server {
listen 80;
listen [::]:80;
server_name [domain-name] www.[domain-name];
server_tokens off;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://[domain-name]$request_uri;
}
}
Remember to reload nginx
to apply the new configuration. Uou can run docker compose restart
to restart all services or just docker compose exec webserver nginx -s reload
to reload nginx
without interrupting other services.
If you already configured some https
(server listening on port 433
) comment out that part temporarily to avoid errors during the certificate creation process.
Step 3: Create certificates
First of all, ensure all configurations are ready because certbot
has limited retries for the configuration command. If the command fails multiple times, it will be blocked for a certain period.
To test the configuration command, use it with the --dry-run
flag, replacing your domain name at the end:
docker compose -f your_compose_file.yml run --rm certbot certonly --webroot --webroot-path /var/www/certbot/ --dry-run -d [domain-name]
If you receive a message stating “The dry run was successful”, you can proceed. Otherwise, review the previous steps or check your DNS configuration.
Now, run certbot
without --dry-run
flag to configure the new certificates:
docker compose -f your_compose_file.yml run --rm certbot certonly --webroot --webroot-path /var/www/certbot/ -d [domain-name]
Follow the instructions from the command prompt, which will request an email (this can be your personal email) and ask you to accept the terms and conditions.
Now add the HTTPS
configuration for nginx
and restart the service:
server {
listen 443 default_server ssl http2;
listen [::]:443 ssl http2;
server_name [domain-name];
ssl_certificate /etc/nginx/ssl/live/[domain-name]/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/live/[domain-name]/privkey.pem;
location / {
# Django configuration
}
}
Remember to replace the domain name and restart nginx
service docker compose webserver restart
.
At the end, your nginx configuration file should look like this:
server {
listen 80;
listen [::]:80;
server_name [domain-name];
server_tokens off;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://[domain-name]$request_uri;
}
}
server {
listen 443 default_server ssl;
listen [::]:443 ssl;
client_max_body_size 256M;
server_name [domain-name];
ssl_certificate /etc/nginx/ssl/live/[domain-name]/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/live/[domain-name]/privkey.pem;
location / {
proxy_pass http://[django_service_name]:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
location /static/ {
alias /code/static/;
}
}
Step 4: Renew certificates
To manually renew certificates, you can run:
docker compose run --rm certbot renew
To automatically renew them periodically, say every 60 days, you can use crontab
. Open the crontab
configuration with:
contrab -e
Now, add the following line, replacing your Docker
compose file path:
0 5 1 */2 * /usr/bin/docker compose -f /home/ubuntu/repository/docker-compose.prod.yml run --rm certbot renew --force-renew && /usr/bin/docker compose -f /home/ubuntu/repository/docker-compose.prod.yml restart nginx
Ensure /usr/bin/docker
exists and your path to the Docker file is correct, this command also restart nginx
, if you are using other service replace the command after &&
. Save the file. This will run the renewal process on the first day at 5 AM every two months.