SSL Certificates

SSL certificates are required for production use of Holt. HTTP is unsupported due to WebCrypto API requirements.

Quick Setup

Self-Signed SSL Certificate (Development Only)

For development and testing purposes, you can generate self-signed SSL certificates:

python3.13 self_ssl.py

Replace python3.13 with python if you’re on Windows

Self-signed certificates will only work with the frontend hosted by the backend itself and should not be used in production.

Manual Certificate Setup

Obtain certificates using Let’s Encrypt or your certificate provider and place them in the certs directory:

  • cert.pem - Your SSL certificate
  • key.pem - Your private key

Automatic SSL Certificate Management with Certbot

For production deployments, you can use Certbot to automatically obtain and renew SSL certificates from Let’s Encrypt:

Installation

Install Certbot:

sudo apt update
sudo apt install certbot

Initial Certificate Setup

Stop any services using ports 80/443:

docker compose down

Obtain certificates (replace your-domain.com with your actual domain):

sudo certbot certonly --standalone -d your-domain.com

Copy certificates to certs directory:

sudo cp /etc/letsencrypt/live/your-domain.com/fullchain.pem certs/cert.pem
sudo cp /etc/letsencrypt/live/your-domain.com/privkey.pem certs/key.pem

Automatic Renewal Setup

Set up automatic renewal:

sudo crontab -e

Add this line to check for renewal twice daily (midnight and noon):

0 0,12 * * * /usr/bin/certbot renew --quiet \
  --pre-hook "/usr/bin/docker compose -f /path/to/Holt/keel/docker-compose.yml stop nginx" \
  --post-hook "/usr/bin/docker compose -f /path/to/Holt/keel/docker-compose.yml start nginx" \
  --deploy-hook "cp /etc/letsencrypt/live/your-domain.com/fullchain.pem /path/to/Holt/keel/certs/cert.pem && \
                 cp /etc/letsencrypt/live/your-domain.com/privkey.pem /path/to/Holt/keel/certs/key.pem

Replace /path/to/Holt/keel with your actual installation path.

The pre-hook and post-hook temporarily stop nginx so Certbot in standalone mode can bind to port 80 for domain validation. If you switch to webroot mode later, you can drop these two hooks and avoid downtime entirely.

certbot renew only renews certificates that are within 30 days of expiration, so running it twice a day is safe and avoids hitting Let’s Encrypt rate limits.

Verification

Test the renewal process:

sudo certbot renew --dry-run

Check certificate expiration:

sudo certbot certificates

Troubleshooting

Common Issues

Port 80/443 already in use:

  • Stop all services using these ports before running certbot
  • Use sudo netstat -tlnp | grep :80 to find processes using port 80

Domain validation fails:

  • Ensure your domain points to the server’s IP address
  • Check firewall settings allow traffic on port 80