Sanitized mirror from private repository - 2026-04-05 10:48:21 UTC
This commit is contained in:
318
docs/infrastructure/ssl-tls-management.md
Normal file
318
docs/infrastructure/ssl-tls-management.md
Normal file
@@ -0,0 +1,318 @@
|
||||
# SSL/TLS Certificate Management
|
||||
|
||||
*Managing SSL certificates for the homelab infrastructure*
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
The homelab uses Nginx Proxy Manager (NPM) as the primary certificate authority, with Let's Encrypt providing free SSL certificates.
|
||||
|
||||
---
|
||||
|
||||
## Certificate Authorities
|
||||
|
||||
### Primary: Let's Encrypt
|
||||
- **Provider:** Let's Encrypt
|
||||
- **Validation:** HTTP-01 (automatic via NPM)
|
||||
- **Renewal:** Automatic at 90 days
|
||||
- **Domains:** *.vish.local, *.vish.gg
|
||||
|
||||
### Secondary: Self-Signed
|
||||
- **Use:** Internal services (non-public)
|
||||
- **Tool:** OpenSSL
|
||||
- **Regeneration:** As needed
|
||||
|
||||
---
|
||||
|
||||
## Certificate Locations
|
||||
|
||||
### Nginx Proxy Manager
|
||||
```
|
||||
/opt/docker/npm/data/
|
||||
├── letsencrypt/
|
||||
│ └── accounts/
|
||||
│ └── acme-v02.api.letsencrypt.org/
|
||||
└── ssl/
|
||||
└── <domain>/
|
||||
├── fullchain.pem
|
||||
├── privkey.pem
|
||||
└── bundle.crt
|
||||
```
|
||||
|
||||
### Services with Own Certs
|
||||
- **Authentik:** `/opt/authentik/ssl/`
|
||||
- **Matrix:** `/etc/matrix-synapse/ssl/`
|
||||
- **PostgreSQL:** `/etc/ssl/private/`
|
||||
|
||||
---
|
||||
|
||||
## Adding New Certificates
|
||||
|
||||
### Via NPM UI (Recommended)
|
||||
|
||||
1. Access NPM: `http://calypso.vish.local:81`
|
||||
2. Navigate to **SSL Certificates** → **Add SSL Certificate**
|
||||
3. Enter domain names:
|
||||
- `service.vish.local` (internal)
|
||||
- `service.vish.gg` (public)
|
||||
4. Enable **Force SSL**
|
||||
5. Click **Save**
|
||||
|
||||
### Via CLI (Automation)
|
||||
|
||||
```bash
|
||||
# Using certbot directly
|
||||
certbot certonly --webroot \
|
||||
-w /var/www/html \
|
||||
-d service.vish.local \
|
||||
--agree-tos \
|
||||
--email admin@vish.local
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Certificate Renewal
|
||||
|
||||
### Automatic (Default)
|
||||
- NPM auto-renews 7 days before expiration
|
||||
- No action required
|
||||
- Check logs: NPM → Logs
|
||||
|
||||
### Manual Renewal
|
||||
|
||||
```bash
|
||||
# Force renewal via NPM
|
||||
docker exec nginx-proxy-manager npm --root /etc/npm \
|
||||
force-renew
|
||||
|
||||
# Or via API
|
||||
curl -X POST http://npm/api/nginx/certificates/<id>/renew
|
||||
```
|
||||
|
||||
### Ansible Playbook
|
||||
```bash
|
||||
ansible-playbook ansible/automation/playbooks/certificate_renewal.yml
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Certificate Status
|
||||
|
||||
### Check Expiration
|
||||
|
||||
```bash
|
||||
# Via NPM
|
||||
# Navigate to SSL Certificates tab
|
||||
|
||||
# Via openssl
|
||||
echo | openssl s_client -connect service.vish.local:443 2>/dev/null | openssl x509 -noout -dates
|
||||
|
||||
# Via script
|
||||
cd /opt/npm/letsencrypt/live/
|
||||
for cert in */; do
|
||||
echo "$cert: $(openssl x509 -enddate -noout -in "$cert/cert.pem" | cut -d= -f2)"
|
||||
done
|
||||
```
|
||||
|
||||
### Certificate Dashboard
|
||||
|
||||
| Domain | Expiry | Status | Renews |
|
||||
|--------|--------|--------|--------|
|
||||
| vish.gg | +85 days | ✅ Active | Auto |
|
||||
| *.vish.local | +85 days | ✅ Active | Auto |
|
||||
|
||||
---
|
||||
|
||||
## Common Issues
|
||||
|
||||
### Rate Limiting
|
||||
|
||||
**Problem:** Too many certificate requests
|
||||
|
||||
**Solution:**
|
||||
- Wait 1 hour (Let's Encrypt limit)
|
||||
- Use staging environment for testing
|
||||
- Request multiple domains in one cert
|
||||
|
||||
### DNS Validation Failure
|
||||
|
||||
**Problem:** ACME challenge fails
|
||||
|
||||
**Solution:**
|
||||
- Verify DNS A record points to public IP
|
||||
- Check firewall allows port 80
|
||||
- Ensure no CNAME conflicts
|
||||
|
||||
### Mixed Content Warnings
|
||||
|
||||
**Problem:** HTTP resources on HTTPS page
|
||||
|
||||
**Solution:**
|
||||
- Update service config to use HTTPS URLs
|
||||
- For internal services, use HTTP (NPM handles SSL)
|
||||
- Check browser console for details
|
||||
|
||||
### Certificate Mismatch
|
||||
|
||||
**Problem:** Wrong certificate served
|
||||
|
||||
**Solution:**
|
||||
1. Check NPM proxy host settings
|
||||
2. Verify certificate is assigned
|
||||
3. Clear browser cache
|
||||
4. Check for multiple certificates
|
||||
|
||||
---
|
||||
|
||||
## Internal Services (Self-Signed)
|
||||
|
||||
### Creating Self-Signed Cert
|
||||
|
||||
```bash
|
||||
# Create directory
|
||||
mkdir -p /opt/service/ssl
|
||||
|
||||
# Generate certificate
|
||||
openssl req -x509 -nodes -days 365 \
|
||||
-newkey rsa:2048 \
|
||||
-keyout /opt/service/ssl/key.pem \
|
||||
-out /opt/service/ssl/cert.pem \
|
||||
-addext "subjectAltName=DNS:service.local,DNS:service"
|
||||
|
||||
# Set permissions
|
||||
chmod 600 /opt/service/ssl/key.pem
|
||||
```
|
||||
|
||||
### Adding to Trust Store
|
||||
|
||||
```bash
|
||||
# Linux (Ubuntu/Debian)
|
||||
sudo cp /opt/service/ssl/cert.pem /usr/local/share/ca-certificates/service.crt
|
||||
sudo update-ca-certificates
|
||||
|
||||
# macOS
|
||||
sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain /opt/service/ssl/cert.pem
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Matrix/Synapse Certificates
|
||||
|
||||
### Custom Certificate Setup
|
||||
|
||||
```yaml
|
||||
# docker-compose.yml
|
||||
services:
|
||||
synapse:
|
||||
environment:
|
||||
- SYNAPSE_TLS_CERT_FILE=/ssl/tls.crt
|
||||
- SYNAPSE_TLS_KEY_FILE=/ssl/tls.key
|
||||
volumes:
|
||||
- ./ssl:/ssl:ro
|
||||
```
|
||||
|
||||
### Federation Certificates
|
||||
|
||||
```bash
|
||||
# Add to TLS certificates
|
||||
/usr/local/bin/REDACTED_APP_PASSWORD \
|
||||
--server-name vish.local \
|
||||
--tls-cert /opt/npm/ssl/vish.gg/fullchain.pem \
|
||||
--tls-key /opt/npm/ssl/vish.gg/privkey.pem
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Security Best Practices
|
||||
|
||||
### Key Permissions
|
||||
```bash
|
||||
# Private keys should be readable only by root
|
||||
chmod 600 /path/to/privkey.pem
|
||||
chown root:root /path/to/privkey.pem
|
||||
```
|
||||
|
||||
### Cipher Suites
|
||||
|
||||
Configure in NPM under **Settings → SSL → Advanced**:
|
||||
|
||||
```
|
||||
ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-SHA384:DHE-RSA-AES256-SHA256
|
||||
```
|
||||
|
||||
### HSTS
|
||||
|
||||
Enable in NPM:
|
||||
- **Settings → SSL → Force HSTS**
|
||||
- Preload recommended
|
||||
|
||||
---
|
||||
|
||||
## Backup
|
||||
|
||||
### Backup Certificates
|
||||
|
||||
```bash
|
||||
# Backup NPM certificates
|
||||
tar -czf backups/ssl-$(date +%Y%m%d).tar.gz \
|
||||
/opt/docker/npm/data/letsencrypt/ \
|
||||
/opt/docker/npm/data/ssl/
|
||||
```
|
||||
|
||||
### Restore
|
||||
|
||||
```bash
|
||||
# Restore
|
||||
tar -xzf backups/ssl-20240101.tar.gz -C /
|
||||
|
||||
# Restart NPM
|
||||
docker-compose -f /opt/docker/npm/docker-compose.yml restart
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Monitoring
|
||||
|
||||
### Expiration Alerts
|
||||
|
||||
Configure in Prometheus/Alertmanager:
|
||||
```yaml
|
||||
groups:
|
||||
- name: certificates
|
||||
rules:
|
||||
- alert: REDACTED_APP_PASSWORD
|
||||
expr: (certify_not_after - time()) < (86400 * 30)
|
||||
for: 1h
|
||||
labels:
|
||||
severity: warning
|
||||
annotations:
|
||||
summary: "Certificate expiring soon"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Useful Commands
|
||||
|
||||
```bash
|
||||
# Check all certificates
|
||||
docker exec nginx-proxy-manager npm --root /etc/npm list
|
||||
|
||||
# Force renewal
|
||||
docker exec nginx-proxy-manager npm --root /etc/npm force-renew
|
||||
|
||||
# Manual ACME challenge
|
||||
docker exec -it nginx-proxy-manager sh
|
||||
cd /etc/letsencrypt/renewal-hooks/deploy/
|
||||
|
||||
# Verify certificate
|
||||
openssl s_client -connect vish.gg:443 -servername vish.gg
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Links
|
||||
|
||||
- [NPM Documentation](https://nginxproxymanager.com/)
|
||||
- [Let's Encrypt Docs](https://letsencrypt.org/docs/)
|
||||
- [SSL Labs Test](https://www.ssllabs.com/ssltest/)
|
||||
Reference in New Issue
Block a user