164 lines
5.8 KiB
Markdown
164 lines
5.8 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
|
|
|
|
## Port Forwarding Requirements
|
|
|
|
**Critical**: SSL certificates require ports 80 and 443 to be forwarded from your router to your homelab server.
|
|
|
|
### Router Configuration
|
|
1. Log into your router's admin interface (usually 192.168.1.1)
|
|
2. Find the "Port Forwarding" or "NAT" section
|
|
3. Create forwarding rules:
|
|
- **External Port**: 80 → **Internal IP**: your-server-ip **Internal Port**: 80
|
|
- **External Port**: 443 → **Internal IP**: your-server-ip **Internal Port**: 443
|
|
4. Protocol: TCP for both
|
|
5. Save changes
|
|
|
|
### Why This Is Required
|
|
- **Port 80**: Used by Let's Encrypt for domain ownership verification (HTTP-01 challenge)
|
|
- **Port 443**: Used for all HTTPS traffic to your services
|
|
- **Wildcard Certificates**: Enables automatic SSL for all `*.yourdomain.duckdns.org` subdomains
|
|
|
|
### Testing Port Forwarding
|
|
```bash
|
|
# Test from external network (not your local network)
|
|
curl -I http://yourdomain.duckdns.org
|
|
# Should return HTTP 200 or redirect to HTTPS
|
|
``` |