Add comprehensive SSL certificate documentation to getting-started.md
- Explain Let's Encrypt + DuckDNS integration - Document staging vs production certificate servers - Add troubleshooting guide for certificate issues - Include best practices and validation commands - Cover wildcard certificates and DNS challenge process
This commit is contained in:
@@ -129,6 +129,152 @@ The `setup-homelab.sh` script is a comprehensive first-run configuration tool:
|
||||
|
||||
If you prefer manual control or the automated script fails, see the [Manual Setup Guide](manual-setup.md) for step-by-step instructions on installing Docker, configuring services, and deploying the homelab manually.
|
||||
|
||||
# Notes about SSL Certificates from LetsEncrypt with DuckDNS
|
||||
|
||||
## How SSL Certificates Work in Your Homelab
|
||||
|
||||
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.
|
||||
|
||||
### 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:**
|
||||
- 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
|
||||
|
||||
Your homelab is now secure with automatic SSL! 🔒
|
||||
|
||||
|
||||
## Post-Setup Next Steps
|
||||
|
||||
### Access Your Services
|
||||
|
||||
Reference in New Issue
Block a user