Skip to main content

SSL Certificate Renewal Prompt

Context

Use this prompt when renewing or setting up SSL certificates for Pacing Agency services. Most of our services use:

  • Cloudflare proxy - Automatic SSL (most client sites)
  • Let's Encrypt - Free automated certificates (self-hosted services)
  • Manual certificates - Rare, for special requirements

This prompt focuses on Let's Encrypt certificates for self-hosted services on Hetzner servers.

This prompt will help you:

  • Set up or renew Let's Encrypt certificates
  • Configure automatic renewal
  • Verify SSL is working correctly
  • Troubleshoot certificate issues

Prerequisites

  • Server access - SSH access to Hetzner server
  • Domain configured - DNS pointing to server (A record)
  • Port 80/443 open - Firewall allows HTTP/HTTPS
  • Certbot installed - Let's Encrypt client tool
  • Web server running - Nginx, Caddy, or similar

See Hetzner Tool Documentation for server details and Cloudflare Documentation for DNS.

Prompt Template

I need to set up or renew an SSL certificate for a self-hosted service on Pacing Agency infrastructure:

**Domain Information:**
- Domain/subdomain: [DOMAIN]
- Server: [SERVER_NAME] (from Hetzner documentation)
- Server IP: [SERVER_IP]
- Web server: [WEB_SERVER] (Nginx/Caddy/Apache)

**Current Status:**
- Certificate status: [STATUS] (None/Expired/Expiring soon/Valid)
- Days until expiry: [DAYS] (if applicable)
- Certificate issuer: [ISSUER] (Let's Encrypt/Other)

**Service Configuration:**
- Service type: [SERVICE_TYPE] (n8n/TwentyCRM/Notifuse/Remark42)
- Service port: [PORT]
- Reverse proxy: [PROXY_SETUP] (Yes/No)

**Requirements:**
- Certificate type: Let's Encrypt (automatic)
- Renewal method: [RENEWAL_METHOD] (Certbot standalone/Webroot/Nginx plugin)
- Automatic renewal: Yes (via cron)
- Email for expiry notices: [EMAIL]

Please provide:

1. **Certificate setup/renewal commands**:
- Certbot installation (if needed)
- Certificate request command
- Verification steps
2. **Web server configuration**:
- Nginx/Caddy SSL configuration
- Certificate paths
- SSL best practices
- HTTPS redirect setup
3. **Automatic renewal setup**:
- Cron job configuration
- Renewal test command
- Failure notification
4. **Verification checklist**:
- SSL certificate validation
- Browser test
- SSL Labs test
- Expiry monitoring
5. **Troubleshooting guide**:
- Common certificate issues
- Renewal failures
- Port conflicts
- DNS issues
6. **Documentation template** for adding to service tool doc

Include:
- Commands with explanations
- Error handling
- Security best practices
- Testing procedures

Format with clear sections and code blocks.

Variables to Customize

VariableDescriptionExample
[DOMAIN]Full domain or subdomain"n8n.pacing.agency", "crm.pacing.agency"
[SERVER_NAME]Hetzner server name"n8n2", "twenty-crm-prod-2"
[SERVER_IP]Public IP address"91.98.150.95", "49.13.82.194"
[WEB_SERVER]Web server softwareNginx, Caddy, Apache
[STATUS]Current certificate status"None", "Expired", "Expiring in 7 days", "Valid"
[DAYS]Days until expiry"7", "30", "90"
[ISSUER]Certificate authority"Let's Encrypt", "Cloudflare"
[SERVICE_TYPE]Type of service"n8n", "TwentyCRM", "Notifuse"
[PORT]Service port"5678" (n8n), "3000" (TwentyCRM)
[PROXY_SETUP]Reverse proxy status"Yes (Nginx)", "No (direct)"
[RENEWAL_METHOD]How to renew certificate"Standalone", "Webroot", "Nginx plugin"
[EMAIL]Admin email for notices"tech@pacing.agency"

Certificate Renewal Methods

Standalone - Certbot runs its own web server

  • Use when: No web server running, or can stop server briefly
  • Pros: Simple, no web server config needed
  • Cons: Requires stopping web server during renewal

Webroot - Certbot uses existing web server

  • Use when: Web server running, can't stop for renewal
  • Pros: No downtime, works with any web server
  • Cons: Requires web server configuration

Nginx Plugin - Certbot directly configures Nginx

  • Use when: Using Nginx as reverse proxy
  • Pros: Automatic Nginx configuration
  • Cons: Nginx-specific, requires plugin

Expected Output

The AI should provide:

1. Certbot Installation (if needed)

# Install Certbot on Ubuntu 24.04
apt update
apt install certbot

# If using Nginx plugin
apt install python3-certbot-nginx

# Verify installation
certbot --version

2. Certificate Request (New Certificate)

# Method 1: Standalone (requires stopping web server)
systemctl stop nginx
certbot certonly --standalone \
-d n8n.pacing.agency \
--email tech@pacing.agency \
--agree-tos \
--no-eff-email
systemctl start nginx

# Method 2: Webroot (no downtime)
certbot certonly --webroot \
-w /var/www/html \
-d n8n.pacing.agency \
--email tech@pacing.agency \
--agree-tos \
--no-eff-email

# Method 3: Nginx plugin (automatic configuration)
certbot --nginx \
-d n8n.pacing.agency \
--email tech@pacing.agency \
--agree-tos \
--no-eff-email

3. Certificate Renewal (Existing Certificate)

# Test renewal (dry run)
certbot renew --dry-run

# Perform actual renewal
certbot renew

# Renew specific certificate
certbot renew --cert-name n8n.pacing.agency

# Renew with Nginx reload
certbot renew --deploy-hook "systemctl reload nginx"

4. Nginx SSL Configuration

# /etc/nginx/sites-available/n8n.conf

server {
listen 80;
listen [::]:80;
server_name n8n.pacing.agency;

# ACME challenge for Let's Encrypt
location /.well-known/acme-challenge/ {
root /var/www/html;
}

# Redirect everything else to HTTPS
location / {
return 301 https://$host$request_uri;
}
}

server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name n8n.pacing.agency;

# SSL Certificate paths
ssl_certificate /etc/letsencrypt/live/n8n.pacing.agency/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/n8n.pacing.agency/privkey.pem;

# SSL Configuration (Mozilla Modern)
ssl_protocols TLSv1.3 TLSv1.2;
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384';
ssl_prefer_server_ciphers off;

# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/live/n8n.pacing.agency/chain.pem;

# Security headers
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;

# Proxy to service
location / {
proxy_pass http://localhost:5678;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
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;
}
}

5. Automatic Renewal Setup

# Certbot creates automatic renewal via systemd timer
# Check renewal timer status
systemctl list-timers | grep certbot

# Or via cron (if using cron instead of systemd)
# Add to crontab
crontab -e

# Add this line (runs twice daily at 3:15 AM and PM)
15 3,15 * * * certbot renew --quiet --deploy-hook "systemctl reload nginx"

# Test automatic renewal
certbot renew --dry-run

6. Verification Commands

# Check certificate details
certbot certificates

# Check expiry date
openssl x509 -in /etc/letsencrypt/live/n8n.pacing.agency/fullchain.pem -noout -dates

# Test SSL configuration
openssl s_client -connect n8n.pacing.agency:443 -servername n8n.pacing.agency

# Check SSL Labs score (from browser)
# https://www.ssllabs.com/ssltest/analyze.html?d=n8n.pacing.agency

7. Monitoring Script

#!/bin/bash
# check-ssl-expiry.sh - Check SSL certificate expiry

DOMAIN="n8n.pacing.agency"
DAYS_WARNING=30

# Get expiry date
EXPIRY=$(echo | openssl s_client -servername $DOMAIN -connect $DOMAIN:443 2>/dev/null | openssl x509 -noout -dates | grep notAfter | cut -d= -f2)
EXPIRY_EPOCH=$(date -d "$EXPIRY" +%s)
NOW_EPOCH=$(date +%s)
DAYS_LEFT=$(( ($EXPIRY_EPOCH - $NOW_EPOCH) / 86400 ))

echo "Certificate expires: $EXPIRY"
echo "Days remaining: $DAYS_LEFT"

if [ $DAYS_LEFT -lt $DAYS_WARNING ]; then
echo "⚠️ Certificate expiring soon!"
# Send alert (Slack, email, etc.)
else
echo "✅ Certificate is valid"
fi

Follow-up Actions

After setting up or renewing certificate:

1. Document in Service Tool Doc

Add SSL configuration to service documentation:

## SSL Certificate

**Domain**: [DOMAIN]
**Issuer**: Let's Encrypt
**Certificate path**: `/etc/letsencrypt/live/[DOMAIN]/`
**Automatic renewal**: Enabled (twice daily via systemd timer)
**Expiry monitoring**: `certbot certificates`
**Last renewed**: [DATE]
**Expires**: [DATE]

2. Verify HTTPS is Working

Test from multiple locations:

# Test from server
curl -I https://[DOMAIN]

# Test from external location
curl -I https://[DOMAIN] --resolve [DOMAIN]:443:[SERVER_IP]

# Check in browser (should show lock icon)

3. Test SSL Labs Score

Check SSL configuration quality:

4. Set Up Monitoring

Configure expiry monitoring:

  • Add to monitoring dashboard
  • Set alert for <30 days remaining
  • Verify automatic renewal emails work

5. Test Automatic Renewal

Ensure renewal will work:

# Dry run test (doesn't actually renew)
certbot renew --dry-run

# Should see "Congratulations, all simulated renewals succeeded"

Success Criteria

Before considering SSL setup complete, verify:

✅ Certificate is issued and valid
✅ HTTPS is working in browser
✅ HTTP redirects to HTTPS
✅ Certificate paths are correct in web server config
✅ SSL Labs score is A or A+
✅ Automatic renewal is configured
✅ Renewal test (dry run) passes
✅ Monitoring is set up
✅ Documentation is updated
✅ No SSL warnings in browser

Common Issues

Issue: Certificate request fails (DNS validation)

Symptoms: "DNS problem: NXDOMAIN looking up A for [DOMAIN]"

Solutions:

  1. Verify DNS is configured correctly:
    dig [DOMAIN]
    # Should show A record pointing to server IP
  2. Wait for DNS propagation (5-10 minutes)
  3. Test from Cloudflare DNS:
    dig @1.1.1.1 [DOMAIN]
  4. Ensure DNS record is not orange-clouded if using Cloudflare
  5. Try again after waiting

Issue: Port 80 already in use

Symptoms: "Problem binding to port 80: Could not bind to IPv4 or IPv6"

Solutions:

  1. Check what's using port 80:
    lsof -i :80
    netstat -tlnp | grep :80
  2. If Nginx is running, use webroot method instead:
    certbot certonly --webroot -w /var/www/html -d [DOMAIN]
  3. Or temporarily stop web server:
    systemctl stop nginx
    certbot certonly --standalone -d [DOMAIN]
    systemctl start nginx

Issue: Certificate not trusted in browser

Symptoms: Browser shows "Not Secure" or certificate warning

Solutions:

  1. Check certificate chain:
    certbot certificates
    # Should show "Certificate Path: /etc/letsencrypt/live/[DOMAIN]/fullchain.pem"
  2. Ensure using fullchain.pem not cert.pem:
    ssl_certificate /etc/letsencrypt/live/[DOMAIN]/fullchain.pem;
  3. Reload web server:
    systemctl reload nginx
  4. Clear browser cache and test in incognito

Issue: Automatic renewal failing

Symptoms: Renewal emails saying renewal failed

Solutions:

  1. Test renewal manually:
    certbot renew --dry-run
  2. Check logs:
    journalctl -u certbot.timer
    cat /var/log/letsencrypt/letsencrypt.log
  3. Common causes:
    • Port 80 blocked by firewall
    • Web server configuration changed
    • DNS changed
    • Rate limiting (5 renewals per week max)
  4. Fix issue and test again

Issue: Renewal succeeds but site still shows old certificate

Symptoms: Certificate renewed but browser shows old expiry date

Solutions:

  1. Reload web server:
    systemctl reload nginx
    systemctl status nginx
  2. Check web server is using correct certificate path:
    nginx -t
    grep ssl_certificate /etc/nginx/sites-enabled/*
  3. Restart web server if reload doesn't work:
    systemctl restart nginx
  4. Add deploy hook to automatic renewal:
    certbot renew --deploy-hook "systemctl reload nginx"

Cost Considerations

Let's Encrypt Certificates

Cost: £0 (completely free) Rate limits:

  • 50 certificates per domain per week
  • 5 renewals per certificate per week
  • 300 new orders per account per 3 hours

Best for:

  • Self-hosted services
  • Internal tools
  • Development environments

Cloudflare Universal SSL

Cost: £0 (included with free plan) Features:

  • Automatic issuance
  • Automatic renewal
  • Covers root and www by default

Best for:

  • Client websites
  • Public-facing sites
  • Sites behind Cloudflare proxy

Custom SSL Certificates

Cost: £50-500/year (varies by provider) Use cases:

  • Extended validation (EV) certificates
  • Wildcard certificates (also available free via Let's Encrypt)
  • Special compliance requirements

Rarely needed for Pacing Agency infrastructure.

Examples

Example 1: n8n Service

# Initial setup
certbot certonly --standalone \
-d n8n.pacing.agency \
--email tech@pacing.agency \
--agree-tos

# Nginx configuration
ssl_certificate /etc/letsencrypt/live/n8n.pacing.agency/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/n8n.pacing.agency/privkey.pem;

# Automatic renewal
certbot renew --deploy-hook "systemctl reload nginx"

Result: HTTPS enabled, A+ SSL Labs score, automatic renewal

Example 2: TwentyCRM

# Using Nginx plugin
certbot --nginx \
-d crm.pacing.agency \
--email tech@pacing.agency \
--agree-tos

# Automatic configuration by Certbot
# Verify with: nginx -t

Result: Nginx auto-configured, HTTPS working, automatic renewal enabled

Example 3: Multiple Subdomains

# Request certificate for multiple domains
certbot certonly --standalone \
-d app.pacing.agency \
-d api.pacing.agency \
--email tech@pacing.agency \
--agree-tos

# Or separate certificates (recommended)
certbot certonly --standalone -d app.pacing.agency
certbot certonly --standalone -d api.pacing.agency

Result: Separate certificates for each subdomain, easier management


Last updated: 2026-01-07
Tested on: Ubuntu 24.04 LTS with Certbot 2.x
Estimated time: 10 minutes (setup + verification)