315 lines
7.5 KiB
Markdown
315 lines
7.5 KiB
Markdown
# Traefik SSL Configuration for MerchBay Admin
|
|
|
|
This document explains how to configure paid SSL certificates for production and automatic Let's Encrypt for development.
|
|
|
|
## Network Configuration
|
|
|
|
All deployments use the external network: `traefik-public`
|
|
|
|
```bash
|
|
# Ensure the network exists
|
|
docker network inspect traefik-public >/dev/null 2>&1 || docker network create traefik-public
|
|
```
|
|
|
|
## Development (dev-admin.merchbay.app) - Automatic SSL
|
|
|
|
Development uses Let's Encrypt for automatic SSL certificate generation.
|
|
|
|
### Traefik Configuration
|
|
|
|
Ensure your Traefik has Let's Encrypt configured:
|
|
|
|
```yaml
|
|
# traefik.yml or dynamic config
|
|
certificatesResolvers:
|
|
letsencrypt:
|
|
acme:
|
|
email: admin@merchbay.app
|
|
storage: /letsencrypt/acme.json
|
|
httpChallenge:
|
|
entryPoint: web
|
|
```
|
|
|
|
### Application Labels (Already configured in docker-compose)
|
|
|
|
```yaml
|
|
labels:
|
|
- "traefik.http.routers.merchbay-admin-dev.tls.certresolver=letsencrypt"
|
|
```
|
|
|
|
## Production (merchbay.app) - Paid SSL Certificate
|
|
|
|
Production uses a paid SSL certificate (e.g., from GoDaddy, Namecheap, Cloudflare).
|
|
|
|
### Step 1: Prepare SSL Certificate Files
|
|
|
|
You should have these files from your SSL provider:
|
|
- `merchbay.app.crt` - Certificate file
|
|
- `merchbay.app.key` - Private key file
|
|
- `ca-bundle.crt` - CA bundle (optional, for chain)
|
|
|
|
Create a combined certificate file:
|
|
|
|
```bash
|
|
# Your SSL certificates are in /srv/certs
|
|
# Verify files exist
|
|
ls -la /srv/certs/
|
|
|
|
# If you have a CA bundle, create a full chain
|
|
cd /srv/certs
|
|
cat merchbay.app.crt ca-bundle.crt > merchbay.app-fullchain.crt
|
|
|
|
# Set proper permissions
|
|
sudo chmod 600 /srv/certs/*.key
|
|
sudo chmod 644 /srv/certs/*.crt
|
|
```
|
|
|
|
### Step 2: Configure Traefik File Provider
|
|
|
|
Create a dynamic configuration file for Traefik:
|
|
|
|
```bash
|
|
sudo nano /opt/traefik/dynamic/certs.yml
|
|
```
|
|
|
|
Add:
|
|
|
|
```yaml
|
|
# /opt/traefik/dynamic/certs.yml or your Traefik dynamic config location
|
|
tls:
|
|
certificates:
|
|
- certFile: /srv/certs/merchbay.app-fullchain.crt
|
|
keyFile: /srv/certs/merchbay.app.key
|
|
stores:
|
|
- default
|
|
stores:
|
|
default:
|
|
defaultCertificate:
|
|
certFile: /srv/certs/merchbay.app-fullchain.crt
|
|
keyFile: /srv/certs/merchbay.app.key
|
|
```
|
|
|
|
### Step 3: Update Traefik docker-compose.yml
|
|
|
|
Ensure Traefik has file provider enabled and certificates mounted:
|
|
|
|
```yaml
|
|
services:
|
|
traefik:
|
|
image: traefik:v2.10
|
|
command:
|
|
- "--providers.docker=true"
|
|
- "--providers.docker.network=traefik-public"
|
|
- "--providers.file.directory=/etc/traefik/dynamic"
|
|
- "--providers.file.watch=true"
|
|
- "--entrypoints.web.address=:80"
|
|
- "--entrypoints.websecure.address=:443"
|
|
# Let's Encrypt for dev
|
|
- "--certificatesresolvers.letsencrypt.acme.email=admin@merchbay.app"
|
|
- "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
|
|
- "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
|
|
volumes:
|
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
|
- /srv/certs:/srv/certs:ro
|
|
- /opt/traefik/dynamic:/etc/traefik/dynamic:ro
|
|
- traefik-letsencrypt:/letsencrypt
|
|
networks:
|
|
- traefik-public
|
|
```
|
|
|
|
### Step 4: Restart Traefik
|
|
|
|
```bash
|
|
cd /path/to/traefik
|
|
docker compose restart traefik
|
|
|
|
# Verify certificates are loaded
|
|
docker compose logs traefik | grep -i cert
|
|
```
|
|
|
|
## Application Configuration
|
|
|
|
### Development Branch (dev)
|
|
|
|
File: `docker-compose.portainer.dev.yml`
|
|
|
|
- Domain: `dev-admin.merchbay.app`
|
|
- SSL: Let's Encrypt (automatic)
|
|
- Certificate Resolver: `letsencrypt`
|
|
|
|
```yaml
|
|
labels:
|
|
- "traefik.http.routers.merchbay-admin-dev.rule=Host(`dev-admin.merchbay.app`)"
|
|
- "traefik.http.routers.merchbay-admin-dev.tls.certresolver=letsencrypt"
|
|
```
|
|
|
|
### Production Branch (main)
|
|
|
|
File: `docker-compose.portainer.yml`
|
|
|
|
- Domain: `merchbay.app`
|
|
- SSL: Paid certificate (via Traefik file provider)
|
|
- No certresolver label (uses default store)
|
|
|
|
```yaml
|
|
labels:
|
|
- "traefik.http.routers.merchbay-admin.rule=Host(`merchbay.app`)"
|
|
- "traefik.http.routers.merchbay-admin.tls=true"
|
|
# No certresolver - uses file provider certificate
|
|
```
|
|
|
|
## Gitea Secrets Configuration
|
|
|
|
### Development Secrets
|
|
|
|
```
|
|
DEV_DB_HOST=dev-mysql-host
|
|
DEV_DB_PORT=3306
|
|
DEV_DB_DATABASE=merchbay_admin_dev
|
|
DEV_DB_USERNAME=dev_user
|
|
DEV_DB_PASSWORD=dev_password
|
|
```
|
|
|
|
### Production Secrets
|
|
|
|
```
|
|
PROD_DEPLOY_HOST=prod-server-ip
|
|
PROD_DEPLOY_USER=deploy
|
|
PROD_DEPLOY_SSH_KEY=-----BEGIN RSA PRIVATE KEY-----...
|
|
PROD_DEPLOY_PORT=22
|
|
PROD_DB_HOST=prod-mysql-host
|
|
PROD_DB_PORT=3306
|
|
PROD_DB_DATABASE=merchbay_admin
|
|
PROD_DB_USERNAME=prod_user
|
|
PROD_DB_PASSWORD=prod_password
|
|
```
|
|
|
|
### Shared Secrets (if using same server)
|
|
|
|
```
|
|
DEPLOY_HOST=your-server-ip
|
|
DEPLOY_USER=deploy
|
|
DEPLOY_SSH_KEY=-----BEGIN RSA PRIVATE KEY-----...
|
|
DEPLOY_PORT=22
|
|
```
|
|
|
|
## Verification
|
|
|
|
### Check Development SSL
|
|
|
|
```bash
|
|
# Check certificate issuer (should be Let's Encrypt)
|
|
echo | openssl s_client -servername dev-admin.merchbay.app -connect dev-admin.merchbay.app:443 2>/dev/null | openssl x509 -noout -issuer
|
|
# Should show: issuer=C = US, O = Let's Encrypt, CN = R3
|
|
```
|
|
|
|
### Check Production SSL
|
|
|
|
```bash
|
|
# Check certificate issuer (should be your SSL provider)
|
|
echo | openssl s_client -servername merchbay.app -connect merchbay.app:443 2>/dev/null | openssl x509 -noout -issuer
|
|
# Should show your paid SSL provider
|
|
|
|
# Check certificate validity
|
|
echo | openssl s_client -servername merchbay.app -connect merchbay.app:443 2>/dev/null | openssl x509 -noout -dates
|
|
```
|
|
|
|
### Verify in Browser
|
|
|
|
1. Visit https://dev-admin.merchbay.app
|
|
- Certificate should be issued by "Let's Encrypt Authority X3"
|
|
|
|
2. Visit https://merchbay.com
|
|
- Certificate should be issued by your paid SSL provider
|
|
|
|
## Troubleshooting
|
|
|
|
### Development SSL Not Working
|
|
|
|
```bash
|
|
# Check Let's Encrypt logs
|
|
docker logs traefik | grep letsencrypt
|
|
|
|
# Verify acme.json permissions
|
|
ls -l /path/to/letsencrypt/acme.json
|
|
# Should be: -rw------- (600)
|
|
|
|
# Check DNS
|
|
dig dev-admin.merchbay.app +short
|
|
# Should return your server IP
|
|
```
|
|
|
|
### Production SSL Not Working
|
|
|
|
```bash
|
|
# Verify Traefik can read certificates
|
|
docker exec traefik ls -l /srv/certs/
|
|
|
|
# Check dynamic configuration is loaded
|
|
docker exec traefik cat /etc/traefik/dynamic/certs.yml
|
|
|
|
# Verify certificate format
|
|
openssl x509 -in /srv/certs/merchbay.app-fullchain.crt -text -noout
|
|
|
|
# Check private key
|
|
openssl rsa -in /srv/certs/merchbay.app.key -check
|
|
```
|
|
|
|
### Certificate Mismatch
|
|
|
|
```bash
|
|
# Verify certificate and key match
|
|
openssl x509 -noout -modulus -in /srv/certs/merchbay.app.crt | openssl md5
|
|
openssl rsa -noout -modulus -in /srv/certs/merchbay.app.key | openssl md5
|
|
# Both should output the same hash
|
|
```
|
|
|
|
## Renewing Certificates
|
|
|
|
### Development (Let's Encrypt)
|
|
|
|
Automatic renewal every 60 days. No action needed.
|
|
|
|
### Production (Paid SSL)
|
|
|
|
Before certificate expiration:
|
|
|
|
1. Download new certificate from your SSL provider
|
|
2. Update files in `/srv/certs/`
|
|
3. Restart Traefik: `docker compose restart traefik`
|
|
4. Verify: `curl -vI https://merchbay.app`
|
|
|
|
## DNS Configuration
|
|
|
|
### Development
|
|
|
|
```
|
|
Type: A
|
|
Name: dev-admin.merchbay.app
|
|
Value: YOUR_SERVER_IP
|
|
TTL: 3600
|
|
```
|
|
|
|
### Production
|
|
|
|
```
|
|
Type: A
|
|
Name: merchbay.app (or @)
|
|
Value: YOUR_SERVER_IP
|
|
TTL: 3600
|
|
|
|
Type: A
|
|
Name: www.merchbay.app
|
|
Value: YOUR_SERVER_IP
|
|
TTL: 3600
|
|
```
|
|
|
|
## Security Best Practices
|
|
|
|
1. **Keep certificates private**: Never commit SSL keys to git
|
|
2. **Use strong permissions**: 600 for private keys, 644 for certificates
|
|
3. **Monitor expiration**: Set reminders 30 days before expiration
|
|
4. **Use HSTS**: Add header after SSL is working correctly
|
|
5. **Enable OCSP stapling**: Improves SSL performance
|
|
6. **Regular updates**: Keep Traefik updated for security patches
|