System Administration

Cloudflare Origin Certificate Setup Guide

Overview

This guide covers setting up Cloudflare Origin Certificates with custom SSL paths for Docker Compose applications. Origin Certificates are free and included in Cloudflare’s free tier.

Prerequisites

  • Domain managed by Cloudflare (free plan or higher)
  • Docker Compose application with Nginx
  • Server with directory structure access

Understanding Cloudflare SSL

Two-Layer Certificate System

  1. Edge Certificate (Cloudflare ↔ Visitors)
    • Issued by: Google Trust Services or Let’s Encrypt
    • Validity: 3 months (auto-renewed by Cloudflare)
    • Managed by: Cloudflare (no action required)
    • What browsers see
  2. Origin Certificate (Cloudflare ↔ Your Server)
    • Issued by: Cloudflare
    • Validity: 15 years
    • Managed by: You
    • What you configure on your server

Step 1: Create Origin Certificate

  1. Login to dash.cloudflare.com
  2. Select your domain
  3. Go to: SSL/TLS → Origin Server
  4. Click “Create Certificate”

Certificate Configuration

  • Private key type: RSA (2048) – recommended
  • Certificate format: PEM
  • Hostnames: *.yourdomain.comyourdomain.com (Wildcard covers all subdomains)
  • Certificate Validity: 15 years (recommended)

Generate Certificate

Click “Create”

You will see TWO text boxes:

Box 1: Origin Certificate

-----BEGIN CERTIFICATE-----
MIIEpDCCA4ygAwIBAgIUd...
(multiple lines)
...
-----END CERTIFICATE-----

Box 2: Private Key

-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0...
(multiple lines)
...
-----END PRIVATE KEY-----

CRITICAL: The private key is shown ONLY ONCE. Save it immediately or you’ll need to regenerate.

Step 2: Save Certificates to Server

Create SSL Directory

mkdir -p nginx/ssl

Save Origin Certificate

nano nginx/ssl/nginx.crt

Paste the entire Origin Certificate including:

  • -----BEGIN CERTIFICATE-----
  • All certificate content
  • -----END CERTIFICATE-----

Save and exit (Ctrl+X, Y, Enter)

Save Private Key

nano nginx/ssl/nginx.key

Paste the entire Private Key including:

  • -----BEGIN PRIVATE KEY-----
  • All key content
  • -----END PRIVATE KEY-----

Save and exit (Ctrl+X, Y, Enter)

Set Proper Permissions

chmod 644 nginx/ssl/nginx.crt
chmod 600 nginx/ssl/nginx.key

Security Note: Private key should only be readable by owner (600).

Step 3: Configure Docker Compose

Update docker-compose.yml

Add volume mounts to your nginx service:

services:
  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
      - ./nginx/ssl/nginx.crt:/etc/nginx/ssl/nginx.crt:ro
      - ./nginx/ssl/nginx.key:/etc/nginx/ssl/nginx.key:ro
    restart: unless-stopped

Notes:

  • :ro flag makes files read-only inside container
  • Paths on left are host system paths
  • Paths on right are container internal paths

Step 4: Configure Nginx

Basic SSL Configuration

server {
    listen 80;
    server_name yourdomain.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name yourdomain.com;

    # SSL Certificate paths (inside container)
    ssl_certificate /etc/nginx/ssl/nginx.crt;
    ssl_certificate_key /etc/nginx/ssl/nginx.key;

    # SSL Configuration
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;

    # Your application configuration
    location / {
        proxy_pass http://your-app:port;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Step 5: Deploy

Start Services

docker compose up -d

or

docker-compose up -d

Verify Deployment

# Check nginx container logs
docker compose logs nginx

# Verify certificate files inside container
docker compose exec nginx ls -la /etc/nginx/ssl/

# Test HTTPS connection
curl -I https://yourdomain.com

Cloudflare SSL/TLS Settings

Required Cloudflare Configuration

In Cloudflare dashboard → SSL/TLS → Overview:

Set encryption mode to: Full (strict)

SSL/TLS Modes Explained:

  • Off: No encryption (not recommended)
  • Flexible: Cloudflare ↔ Visitor encrypted, Cloudflare ↔ Server unencrypted
  • Full: End-to-end encryption, accepts self-signed certificates
  • Full (strict): End-to-end encryption, requires valid certificate ✅

Troubleshooting

Error: Cannot load certificate

Symptom:

cannot load certificate "/etc/nginx/ssl/nginx.crt": 
BIO_new_file() failed (SSL: error:80000002:system library::No such file or directory)

Solutions:

  1. Verify files exist on host: ls -la nginx/ssl/
  2. Check file permissions: chmod 644 nginx/ssl/nginx.crt chmod 600 nginx/ssl/nginx.key
  3. Verify files are not empty: cat nginx/ssl/nginx.crt cat nginx/ssl/nginx.key
  4. Restart nginx: docker compose restart nginx

Error: Empty certificate files

If you forgot to paste content or files are 0 bytes:

# Check file sizes
ls -lh nginx/ssl/

# If empty, re-paste certificate content
nano nginx/ssl/nginx.crt
nano nginx/ssl/nginx.key

Lost Private Key

If you lost the private key:

  1. Go to Cloudflare → SSL/TLS → Origin Server
  2. Delete the old certificate
  3. Create a new certificate
  4. Save BOTH the certificate and private key immediately

Certificate Verification

Test your SSL setup:

# Test SSL handshake
openssl s_client -connect yourdomain.com:443 -servername yourdomain.com

# Check certificate expiry
echo | openssl s_client -connect yourdomain.com:443 2>/dev/null | openssl x509 -noout -dates

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

FAQ

Q: Do I need to pay for Cloudflare Origin Certificates?
A: No, they’re included in the free plan.

Q: Can I use Certbot with Cloudflare?
A: Not needed. Cloudflare Origin Certificates are simpler and last 15 years.

Q: Why does my browser show a 3-month certificate?
A: That’s the Edge Certificate between Cloudflare and visitors. It’s auto-renewed. Your 15-year Origin Certificate is for Cloudflare-to-server encryption.

Q: What happens if my Origin Certificate expires?
A: Your site will show SSL errors. Regenerate before expiry (15 years).

Q: Can I use the same certificate for multiple servers?
A: Yes, but each server needs both the certificate AND private key files.

Q: Do wildcards cost extra?
A: No, wildcard Origin Certificates are free.

Resources

Summary

  1. Generate Origin Certificate in Cloudflare (free)
  2. Save certificate as nginx.crt and private key as nginx.key
  3. Mount files in Docker Compose with :ro flag
  4. Configure Nginx to use certificates
  5. Set Cloudflare SSL mode to “Full (strict)”
  6. Certificates last 15 years, no renewal automation needed