# 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
