Skip to content Skip to footer

Cloudflare SSL Certificate Setup

Free SSL certificates for Docker Compose + Nginx. No Certbot required.

Certificate Architecture

Edge Certificate (Cloudflare ↔ Visitors): 3-month validity, auto-renewed
Origin Certificate (Cloudflare ↔ Server): 15-year validity, manual setup

Quick Setup

1. Generate Certificate

Cloudflare Dashboard → SSL/TLS → Origin Server → Create Certificate

  • Hostnames: *.yourdomain.com, yourdomain.com
  • Validity: 15 years
  • Format: PEM

⚠️ Save private key immediately – shown only once.

2. Save to Server

mkdir -p nginx/ssl
nano nginx/ssl/nginx.crt    # Paste origin certificate
nano nginx/ssl/nginx.key    # Paste private key
chmod 644 nginx/ssl/nginx.crt
chmod 600 nginx/ssl/nginx.key

3. Docker Compose

nginx:
  volumes:
    - ./nginx/ssl/nginx.crt:/etc/nginx/ssl/nginx.crt:ro
    - ./nginx/ssl/nginx.key:/etc/nginx/ssl/nginx.key:ro

4. Nginx Config

server {
    listen 443 ssl http2;
    server_name yourdomain.com;
    
    ssl_certificate /etc/nginx/ssl/nginx.crt;
    ssl_certificate_key /etc/nginx/ssl/nginx.key;
    ssl_protocols TLSv1.2 TLSv1.3;
    
    location / {
        proxy_pass http://app:port;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

5. Cloudflare Settings

SSL/TLS → Overview → Set to Full (strict)

6. Deploy

docker compose up -d
docker compose logs nginx    # Verify

Troubleshooting

Cannot load certificate

ls -la nginx/ssl/              # Files exist?
cat nginx/ssl/nginx.crt        # Not empty?
chmod 644 nginx/ssl/nginx.crt
chmod 600 nginx/ssl/nginx.key
docker compose restart nginx

Lost private key: Delete old cert in Cloudflare, create new one

Test SSL

curl -I https://yourdomain.com
openssl s_client -connect yourdomain.com:443

Certificate Renewal

Origin Certificate (15 years)

  • Validity: 15 years from creation
  • Action required: Regenerate before expiry
  • Reminder: Set calendar reminder for year 2040 (or your expiry date)

Edge Certificate (3 months)

  • Validity: 90 days
  • Action required: None (auto-renewed by Cloudflare)
  • Note: This is the certificate browsers see

Security Best Practices

File Permissions

# Certificate (public) - readable by all
chmod 644 nginx/ssl/nginx.crt

# Private key (secret) - readable only by owner
chmod 600 nginx/ssl/nginx.key

Directory Structure

Recommended structure:

project/
├── docker-compose.yml
├── nginx/
│   ├── nginx.conf
│   └── ssl/
│       ├── nginx.crt    (644 permissions)
│       └── nginx.key    (600 permissions)

Version Control

NEVER commit private keys to Git:

# Add to .gitignore
echo "nginx/ssl/*.key" >> .gitignore

Consider committing certificates (public):

# Certificates are public, safe to commit
git add nginx/ssl/nginx.crt

Backup

Backup your private key securely:

# Encrypt and backup
gpg -c nginx/ssl/nginx.key
# Store nginx.key.gpg in secure location

Alternative: Using Let’s Encrypt Paths

If you prefer traditional Let’s Encrypt directory structure:

Directory Structure

mkdir -p /etc/letsencrypt/live/yourdomain.com

Save Certificates

# Origin Certificate → fullchain.pem
nano /etc/letsencrypt/live/yourdomain.com/fullchain.pem

# Private Key → privkey.pem
nano /etc/letsencrypt/live/yourdomain.com/privkey.pem

# Set permissions
chmod 644 /etc/letsencrypt/live/yourdomain.com/fullchain.pem
chmod 600 /etc/letsencrypt/live/yourdomain.com/privkey.pem

Docker Compose Configuration

volumes:
  - /etc/letsencrypt/live/yourdomain.com/fullchain.pem:/etc/letsencrypt/live/yourdomain.com/fullchain.pem:ro
  - /etc/letsencrypt/live/yourdomain.com/privkey.pem:/etc/letsencrypt/live/yourdomain.com/privkey.pem:ro

Nginx Configuration

ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;

Notes

  • Free: Included in all Cloudflare plans
  • Validity: Origin cert = 15 years, Edge cert = 90 days (auto-renewed)
  • Wildcard: *.domain.com covers all subdomains at no extra cost
  • No Certbot: Origin certificates are simpler than Let’s Encrypt
  • Browser view: Users see the 3-month Edge certificate (auto-renewed by Cloudflare)
  • Renewal: Set reminder for 2040 (or your expiry date) to regenerate Origin cert

Leave a Comment