Files
EZ-Homelab/docs/ssl-certificates.md
2026-01-21 14:10:03 -05:00

146 lines
5.1 KiB
Markdown

# SSL Certificates with Let's Encrypt and DuckDNS
Your homelab uses **Let's Encrypt** to automatically provide free SSL certificates for all your services. This ensures secure HTTPS connections without manual certificate management.
## How SSL Certificates Work in Your Homelab
### The Certificate Flow
1. **Domain Registration**: DuckDNS provides your dynamic domain (e.g., `yourname.duckdns.org`)
2. **Certificate Request**: Traefik requests a wildcard certificate (`*.yourname.duckdns.org`)
3. **Domain Validation**: Let's Encrypt validates you own the domain via DNS challenge
4. **Certificate Issuance**: Free SSL certificate is issued and stored
5. **Automatic Renewal**: Certificates renew automatically before expiration
### DuckDNS + Let's Encrypt Integration
**DuckDNS** handles dynamic DNS updates, while **Let's Encrypt** provides certificates:
- **DuckDNS**: Updates your public IP → domain mapping every 5 minutes
- **Let's Encrypt**: Issues trusted SSL certificates via ACME protocol
- **DNS Challenge**: Proves domain ownership by setting TXT records
### Wildcard Certificates Explained
Your setup uses a **wildcard certificate** (`*.yourdomain.duckdns.org`) that covers:
- `dockge.yourdomain.duckdns.org`
- `plex.yourdomain.duckdns.org`
- `jellyfin.yourdomain.duckdns.org`
- Any other subdomain automatically
**Why wildcard?** One certificate covers all services - no need for individual certificates per service.
### Certificate Storage & Management
- **Location**: `/opt/stacks/core/traefik/acme.json`
- **Permissions**: Must be `600` (read/write for owner only)
- **Backup**: Always backup this file - contains your certificates
- **Renewal**: Automatic, 30 days before expiration
## Testing vs Production Certificates
### Staging Server (For Testing)
```yaml
# In traefik.yml, add this line for testing:
caServer: https://acme-staging-v02.api.letsencrypt.org/directory
```
**Staging Benefits:**
- Unlimited certificates (no rate limits)
- Fast issuance for testing
- **Not trusted by browsers** (shows "Not Secure")
**When to use staging:**
- Setting up new environments
- Testing configurations
- Learning/development
### Production Server (For Live Use)
```yaml
# Remove or comment out caServer line for production
# certificatesResolvers:
# letsencrypt:
# acme:
# # No caServer = production
```
**Production Limits:**
>This is why you want to use staging certificates for testing purposes!!!
>Always use staging certificates if you are running the setup & deploy scripts repeatedly
- **50 certificates per domain per week**
- **5 duplicate certificates per week**
- **Trusted by all browsers**
## Certificate Troubleshooting
### Check Certificate Status
```bash
# Count certificates in storage
python3 -c "import json; d=json.load(open('/opt/stacks/core/traefik/acme.json')); print(f'Certificates: {len(d[\"letsencrypt\"][\"Certificates\"])}')}"
```
### Common Issues & Solutions
**"Certificate not trusted" or "Not Secure" warnings:**
- **Staging certificates**: Expected - use production for live sites
- **DNS propagation**: Wait 5-10 minutes after setup
- **Browser cache**: Clear browser cache and try incognito mode
**Certificate request fails:**
- Check Traefik logs: `docker logs traefik | grep -i certificate`
- Verify DuckDNS token is correct in `.env`
- Ensure ports 80/443 are open and forwarded
- Wait 1+ hours between certificate requests
**Rate limit exceeded:**
- Switch to staging server for testing
- Wait 1 week for production limits to reset
- Check status at: https://letsencrypt.org/docs/rate-limits/
### DNS Challenge Process
When requesting certificates, Traefik:
1. Asks DuckDNS to set TXT record: `_acme-challenge.yourdomain.duckdns.org`
2. Let's Encrypt checks the TXT record to verify ownership
3. If valid, certificate is issued
4. TXT record is cleaned up automatically
**Note:** DuckDNS allows only ONE TXT record at a time. Multiple Traefik instances will conflict.
### Certificate Validation Commands
```bash
# Test certificate validity
echo | openssl s_client -connect yourdomain.duckdns.org:443 -servername dockge.yourdomain.duckdns.org 2>/dev/null | openssl x509 -noout -subject -issuer -dates
# Check if certificate covers wildcards
echo | openssl s_client -connect yourdomain.duckdns.org:443 -servername any-subdomain.yourdomain.duckdns.org 2>/dev/null | openssl x509 -noout -text | grep "Subject Alternative Name"
```
## Best Practices
### For Production
- Use production Let's Encrypt server
- Backup `acme.json` regularly
- Monitor certificate expiration (Traefik dashboard)
- Keep DuckDNS token secure
### For Development/Testing
- Use staging server to avoid rate limits
- Test with different subdomains
- Reset environments safely (preserve `acme.json` if possible)
### Security Notes
- Certificates are stored encrypted in `acme.json`
- Private keys never leave your server
- HTTPS provides encryption in transit
- Consider additional security headers in Traefik
## Certificate Lifecycle
- **Validity**: 90 days
- **Renewal**: Automatic, 30 days before expiration
- **Storage**: Persistent across container restarts
- **Backup**: Include in your homelab backup strategy