SSL Certificate Configuration Prompt: Securing Your Homelab

Overview

This reference provides quick patterns for implementing SSL/TLS certificates in homelab environments, covering both public and private certificate authorities.

Certificate Types Comparison

Type Trust Renewal Cost Use Case
Let’s Encrypt Public 90 days (auto) Free Public domains
Self-Signed None Manual Free Testing only
mkcert Local CA Manual Free Internal services
Cloudflare Origin Cloudflare 15 years Free CF-proxied sites

Method 1: Let’s Encrypt (DNS Challenge)

When to Use

  • Public domain with Cloudflare DNS
  • Services behind firewall (no port 80 exposed)
  • Automatic renewal required

Configuration

# Install certbot
sudo apt install certbot python3-certbot-dns-cloudflare

# Create Cloudflare credentials
nano ~/.secrets/cloudflare.ini
dns_cloudflare_api_token = YOUR_CLOUDFLARE_API_TOKEN
# Obtain certificate
sudo certbot certonly \
  --dns-cloudflare \
  --dns-cloudflare-credentials ~/.secrets/cloudflare.ini \
  -d proxmox.yourdomain.com \
  -d '*.yourdomain.com'

# Certificates saved to:
# /etc/letsencrypt/live/yourdomain.com/fullchain.pem
# /etc/letsencrypt/live/yourdomain.com/privkey.pem

Method 2: mkcert (Local CA)

When to Use

  • Internal services (LAN only)
  • Development environment
  • Multiple devices need to trust

Installation

# Install mkcert
sudo apt install libnss3-tools
wget https://github.com/FiloSottile/mkcert/releases/download/v1.4.4/mkcert-v1.4.4-linux-amd64
sudo mv mkcert-v1.4.4-linux-amd64 /usr/local/bin/mkcert
sudo chmod +x /usr/local/bin/mkcert

# Install local CA
mkcert -install

# Generate certificate
mkcert proxmox.lab "*.lab.local" localhost 127.0.0.1 ::1

# Output:
# proxmox.lab+4.pem (certificate)
# proxmox.lab+4-key.pem (private key)

Client Installation

# Export CA certificate
cp "$(mkcert -CAROOT)/rootCA.pem" ~/ca-cert.pem

# Install on other devices:
# - Windows: Import to Trusted Root Certification Authorities
# - Linux: Copy to /usr/local/share/ca-certificates/
# - Android: Settings → Security → Install from storage

Method 3: Nginx Proxy Manager Integration

Let’s Encrypt via NPM

In NPM UI:

Proxy Host → SSL Tab
- Request new SSL certificate
- Use DNS Challenge
- DNS Provider: Cloudflare
- API Token: [your token]
- Force SSL: ON
- HTTP/2: ON
- HSTS: ON

Custom Certificate via NPM

Import mkcert certificate:

SSL Certificates → Add SSL Certificate → Custom
- Certificate Key: Upload privkey.pem
- Certificate: Upload fullchain.pem

Method 4: Proxmox ACME

Setup in Proxmox

Datacenter → ACME
1. Add Account: Let's Encrypt (Production)
2. Add Challenge Plugin:
   - Plugin ID: cloudflare
   - DNS API: Cloudflare Managed DNS
   - CF_Token: [your API token]

Node → System → Certificates
1. Add: Using ACME
2. Domain: proxmox.yourdomain.com
3. Challenge Type: DNS
4. Plugin: cloudflare
5. Order Certificate Now

Certificate Renewal Automation

Let’s Encrypt Auto-Renewal

# Test renewal
sudo certbot renew --dry-run

# Auto-renewal is configured via systemd timer
sudo systemctl status certbot.timer

Custom Renewal Script

#!/bin/bash
# renew-certs.sh

# Renew Let's Encrypt
certbot renew --quiet

# Reload services
systemctl reload nginx
systemctl reload pveproxy

# Send notification
echo "Certificates renewed successfully" | \
  mail -s "Certificate Renewal" admin@example.com

Cron Job

# Add to crontab
crontab -e

# Run weekly
0 3 * * 0 /root/renew-certs.sh

Troubleshooting

Certificate Not Trusted

Problem: Browser shows “Not Secure” warning

Solutions:

# Verify certificate chain
openssl s_client -connect domain.com:443 -showcerts

# Check CA installation (mkcert)
mkcert -CAROOT

# Reinstall CA
mkcert -uninstall
mkcert -install

DNS Challenge Fails

Problem: Let’s Encrypt can’t validate domain

Solutions:

# Verify DNS propagation
dig _acme-challenge.yourdomain.com TXT

# Check API token permissions
# Must have: Zone.DNS.Edit

# Test with verbose output
certbot certonly --dns-cloudflare --dry-run -v

Certificate Expired

Problem: Service using expired certificate

Solutions:

# Check expiry date
openssl x509 -in /path/to/cert.pem -noout -dates

# Force renewal
certbot renew --force-renewal

# Reload service
systemctl reload nginx

Security Best Practices

1. Strong Configuration

# Nginx SSL configuration
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
add_header Strict-Transport-Security "max-age=31536000" always;

2. Certificate Monitoring

# Monitor expiry
openssl x509 -in cert.pem -noout -enddate

# Alert before expiry (30 days)
EXPIRY=$(openssl x509 -enddate -noout -in cert.pem | cut -d= -f2)
EXPIRY_EPOCH=$(date -d "$EXPIRY" +%s)
NOW_EPOCH=$(date +%s)
DAYS_LEFT=$(( ($EXPIRY_EPOCH - $NOW_EPOCH) / 86400 ))

if [ $DAYS_LEFT -lt 30 ]; then
    echo "Certificate expires in $DAYS_LEFT days!" | \
      mail -s "CERT EXPIRY WARNING" admin@example.com
fi

3. Regular Audits

# Check all certificates
for cert in /etc/letsencrypt/live/*/cert.pem; do
    echo "Certificate: $cert"
    openssl x509 -in "$cert" -noout -subject -dates
    echo "---"
done

Quick Decision Guide

Need public access? → Use Let’s Encrypt with DNS challenge

Only internal access? → Use mkcert for local CA

Testing/development? → Self-signed acceptable (but mkcert preferred)

Using Cloudflare? → Cloudflare Origin Certificate or Let’s Encrypt

Multiple services? → Wildcard certificate (*.yourdomain.com)

Conclusion

Proper SSL/TLS configuration is essential for homelab security. Choose the certificate method based on your access requirements and infrastructure capabilities. Automate renewal to prevent expiry-related outages.

Key Points: - Always use HTTPS for web interfaces - Automate certificate renewal - Monitor certificate expiry - Use strong TLS configurations - Document your certificate infrastructure

For implementation details, see related articles on Nginx Proxy Manager and Cloudflare Tunnel.