101 lines
3.3 KiB
Markdown
101 lines
3.3 KiB
Markdown
# Enabling HTTPS with Certbot and Nginx
|
|
|
|
The production Docker stack ships with an Nginx front-end (the `frontend` service). Follow these steps to terminate HTTPS traffic with Let's Encrypt certificates.
|
|
|
|
## 1. Prerequisites
|
|
|
|
- DNS `A` records for your domain (e.g. `vip.example.com`) pointing to `162.243.171.221`.
|
|
- Ports **80** and **443** open in the DigitalOcean firewall.
|
|
- Docker Compose production stack deployed.
|
|
- Certbot installed on the droplet (`apt-get install -y certbot` already run).
|
|
|
|
## 2. Obtain certificates
|
|
|
|
Run Certbot in standalone mode (temporarily stop the `frontend` container during issuance if it is already binding to port 80):
|
|
|
|
```bash
|
|
# Stop the frontend container temporarily
|
|
docker compose -f docker-compose.prod.yml stop frontend
|
|
|
|
# Request the certificate (replace the domain names)
|
|
sudo certbot certonly --standalone \
|
|
-d vip.example.com \
|
|
-d www.vip.example.com
|
|
|
|
# Restart the frontend container
|
|
docker compose -f docker-compose.prod.yml start frontend
|
|
```
|
|
|
|
Certificates will be stored under `/etc/letsencrypt/live/vip.example.com/`.
|
|
|
|
## 3. Mount certificates into the frontend container
|
|
|
|
Copy the key pair into the repository (or mount the original directory as a read-only volume). For example:
|
|
|
|
```bash
|
|
sudo mkdir -p /opt/vip-coordinator/certs
|
|
sudo cp /etc/letsencrypt/live/vip.example.com/fullchain.pem /opt/vip-coordinator/certs/
|
|
sudo cp /etc/letsencrypt/live/vip.example.com/privkey.pem /opt/vip-coordinator/certs/
|
|
sudo chown root:root /opt/vip-coordinator/certs/*.pem
|
|
sudo chmod 600 /opt/vip-coordinator/certs/privkey.pem
|
|
```
|
|
|
|
Update `docker-compose.prod.yml` to mount the certificate directory (uncomment the example below):
|
|
|
|
```yaml
|
|
frontend:
|
|
volumes:
|
|
- /opt/vip-coordinator/certs:/etc/nginx/certs:ro
|
|
```
|
|
|
|
## 4. Enable the TLS server block
|
|
|
|
Edit `frontend/nginx.conf`:
|
|
|
|
1. Uncomment the TLS server block and point to `/etc/nginx/certs/fullchain.pem` and `privkey.pem`.
|
|
2. Change the port 80 server block to redirect to HTTPS (e.g. `return 301 https://$host$request_uri;`).
|
|
|
|
Example TLS block:
|
|
|
|
```nginx
|
|
server {
|
|
listen 443 ssl http2;
|
|
server_name vip.example.com www.vip.example.com;
|
|
|
|
ssl_certificate /etc/nginx/certs/fullchain.pem;
|
|
ssl_certificate_key /etc/nginx/certs/privkey.pem;
|
|
|
|
include /etc/nginx/snippets/ssl-params.conf; # optional hardening
|
|
|
|
proxy_cache_bypass $http_upgrade;
|
|
...
|
|
}
|
|
```
|
|
|
|
Rebuild and redeploy the frontend container:
|
|
|
|
```bash
|
|
docker compose -f docker-compose.prod.yml build frontend
|
|
docker compose -f docker-compose.prod.yml up -d frontend
|
|
```
|
|
|
|
## 5. Automate renewals
|
|
|
|
Certbot installs a systemd timer that runs `certbot renew` twice a day. After renewal, copy the updated certificates into `/opt/vip-coordinator/certs/` and reload the frontend container:
|
|
|
|
```bash
|
|
sudo certbot renew --dry-run
|
|
sudo cp /etc/letsencrypt/live/vip.example.com/{fullchain.pem,privkey.pem} /opt/vip-coordinator/certs/
|
|
docker compose -f docker-compose.prod.yml exec frontend nginx -s reload
|
|
```
|
|
|
|
Consider scripting the copy + reload to run after each renewal (e.g. with a cron job).
|
|
|
|
## 6. Hardening checklist
|
|
|
|
- Add `ssl_ciphers`, `ssl_prefer_server_ciphers`, and HSTS headers to Nginx.
|
|
- Restrict `ADMIN_PASSWORD` to a strong value and rotate `JWT_SECRET`.
|
|
- Enable a firewall (DigitalOcean VPC or `ufw`) allowing only SSH, HTTP, HTTPS.
|
|
- Configure automatic backups for PostgreSQL (snapshot or `pg_dump`).
|
|
|