# Traefik Reverse Proxy Integration

Mosaic Stack supports flexible Traefik integration with three deployment modes:

1. **Bundled Mode**: Self-contained Traefik instance
2. **Upstream Mode**: Connect to external Traefik
3. **None Mode**: Direct port exposure (no reverse proxy)

## Quick Start

### Bundled Mode (Recommended for New Deployments)

```bash
# 1. Copy bundled configuration
cp .env.traefik-bundled.example .env

# 2. Update passwords and secrets in .env
# Edit POSTGRES_PASSWORD, AUTHENTIK_SECRET_KEY, JWT_SECRET, etc.

# 3. Start with bundled Traefik profile
docker compose --profile traefik-bundled up -d

# 4. Access services
# - Web: https://mosaic.local
# - API: https://api.mosaic.local
# - Auth: https://auth.mosaic.local
# - Traefik Dashboard: http://localhost:8080
```

### Upstream Mode (For Existing Traefik Instances)

```bash
# 1. Ensure external Traefik network exists
docker network create traefik-public

# 2. Copy upstream configuration
cp .env.traefik-upstream.example .env

# 3. Update .env with your domains and secrets

# 4. Create override file for network attachment
cp docker-compose.override.yml.example docker-compose.override.yml

# 5. Edit docker-compose.override.yml and uncomment upstream network section

# 6. Start services
docker compose up -d
```

### None Mode (Direct Port Access)

```bash
# 1. Use default .env.example
cp .env.example .env

# 2. Ensure TRAEFIK_MODE=none (default)

# 3. Start services
docker compose up -d

# 4. Access services on standard ports
# - Web: http://localhost:3000
# - API: http://localhost:3001
# - Auth: http://localhost:9000
```

## Configuration Reference

### Environment Variables

| Variable                    | Default             | Description                                    |
| --------------------------- | ------------------- | ---------------------------------------------- |
| `TRAEFIK_MODE`              | `none`              | Traefik mode: `bundled`, `upstream`, or `none` |
| `TRAEFIK_ENABLE`            | `false`             | Enable Traefik labels on services              |
| `MOSAIC_API_DOMAIN`         | `api.mosaic.local`  | Domain for API service                         |
| `MOSAIC_WEB_DOMAIN`         | `mosaic.local`      | Domain for Web service                         |
| `MOSAIC_AUTH_DOMAIN`        | `auth.mosaic.local` | Domain for Authentik service                   |
| `TRAEFIK_NETWORK`           | `traefik-public`    | External Traefik network (upstream mode)       |
| `TRAEFIK_TLS_ENABLED`       | `true`              | Enable TLS/HTTPS                               |
| `TRAEFIK_ACME_EMAIL`        | -                   | Email for Let's Encrypt (production)           |
| `TRAEFIK_CERTRESOLVER`      | -                   | Cert resolver name (e.g., `letsencrypt`)       |
| `TRAEFIK_DASHBOARD_ENABLED` | `true`              | Enable Traefik dashboard (bundled mode)        |
| `TRAEFIK_DASHBOARD_PORT`    | `8080`              | Dashboard port (bundled mode)                  |
| `TRAEFIK_ENTRYPOINT`        | `websecure`         | Traefik entrypoint (`web` or `websecure`)      |
| `TRAEFIK_DOCKER_NETWORK`    | `mosaic-public`     | Docker network for Traefik routing             |

### Docker Compose Profiles

| Profile           | Description                       |
| ----------------- | --------------------------------- |
| `traefik-bundled` | Activates bundled Traefik service |
| `authentik`       | Enables Authentik SSO services    |
| `ollama`          | Enables Ollama AI service         |
| `full`            | Enables all optional services     |

## Deployment Scenarios

### Local Development with Self-Signed Certificates

```bash
# .env configuration
TRAEFIK_MODE=bundled
TRAEFIK_ENABLE=true
TRAEFIK_TLS_ENABLED=true
TRAEFIK_ACME_EMAIL=  # Empty for self-signed
MOSAIC_API_DOMAIN=api.mosaic.local
MOSAIC_WEB_DOMAIN=mosaic.local
MOSAIC_AUTH_DOMAIN=auth.mosaic.local

# Start services
docker compose --profile traefik-bundled up -d

# Add to /etc/hosts
echo "127.0.0.1 mosaic.local api.mosaic.local auth.mosaic.local" | sudo tee -a /etc/hosts
```

Browser will show certificate warnings (expected for self-signed certs).

### Production with Let's Encrypt

```bash
# .env configuration
TRAEFIK_MODE=bundled
TRAEFIK_ENABLE=true
TRAEFIK_TLS_ENABLED=true
TRAEFIK_ACME_EMAIL=admin@example.com
TRAEFIK_CERTRESOLVER=letsencrypt
MOSAIC_API_DOMAIN=api.example.com
MOSAIC_WEB_DOMAIN=example.com
MOSAIC_AUTH_DOMAIN=auth.example.com
```

**Prerequisites:**

1. DNS records pointing to your server
2. Ports 80 and 443 accessible from internet
3. Uncomment ACME configuration in `docker/traefik/traefik.yml`

```yaml
# docker/traefik/traefik.yml
certificatesResolvers:
  letsencrypt:
    acme:
      email: "${TRAEFIK_ACME_EMAIL}"
      storage: "/letsencrypt/acme.json"
      httpChallenge:
        entryPoint: web
```

### Connecting to Existing Traefik (web1.corp.uscllc.local)

For the shared development environment at `~/src/traefik`:

```bash
# 1. Verify external Traefik is running
docker ps | grep traefik

# 2. Verify external network exists
docker network ls | grep traefik-public

# 3. Configure .env
TRAEFIK_MODE=upstream
TRAEFIK_ENABLE=true
TRAEFIK_NETWORK=traefik-public
TRAEFIK_DOCKER_NETWORK=traefik-public
MOSAIC_API_DOMAIN=mosaic-api.uscllc.com
MOSAIC_WEB_DOMAIN=mosaic.uscllc.com
MOSAIC_AUTH_DOMAIN=mosaic-auth.uscllc.com

# 4. Create docker-compose.override.yml
cp docker-compose.override.yml.example docker-compose.override.yml

# 5. Edit docker-compose.override.yml - uncomment network section
# networks:
#   traefik-public:
#     external: true
#     name: traefik-public

# 6. Add services to external network
# api:
#   networks:
#     - traefik-public
# web:
#   networks:
#     - traefik-public
# authentik-server:
#   networks:
#     - traefik-public

# 7. Start services
docker compose up -d
```

Services will be auto-discovered by the external Traefik instance.

## Advanced Configuration

### Custom Middleware

Add authentication or rate limiting via Traefik middleware:

```yaml
# docker-compose.override.yml
services:
  traefik:
    labels:
      # Define basic auth middleware
      - "traefik.http.middlewares.auth.basicauth.users=admin:$$apr1$$xyz..."
      # Define rate limit middleware
      - "traefik.http.middlewares.ratelimit.ratelimit.average=100"
      - "traefik.http.middlewares.ratelimit.ratelimit.burst=50"

  api:
    labels:
      # Apply middleware to API router
      - "traefik.http.routers.mosaic-api.middlewares=auth@docker,ratelimit@docker"
```

Generate basic auth password:

```bash
echo $(htpasswd -nb admin your-password) | sed -e s/\\$/\\$\\$/g
```

### Custom TLS Certificates

To use custom certificates instead of Let's Encrypt:

```yaml
# docker/traefik/dynamic/tls.yml
tls:
  certificates:
    - certFile: /certs/domain.crt
      keyFile: /certs/domain.key
```

Mount certificate directory:

```yaml
# docker-compose.override.yml
services:
  traefik:
    volumes:
      - ./certs:/certs:ro
```

### Multiple Domains

Route multiple domains to different services:

```yaml
# .env
MOSAIC_WEB_DOMAIN=mosaic.local,app.mosaic.local,www.mosaic.local
# Traefik will match all domains
```

Or use override for complex routing:

```yaml
# docker-compose.override.yml
services:
  web:
    labels:
      - "traefik.http.routers.mosaic-web.rule=Host(`mosaic.local`) || Host(`app.mosaic.local`)"
      - "traefik.http.routers.mosaic-web-www.rule=Host(`www.mosaic.local`)"
      - "traefik.http.routers.mosaic-web-www.middlewares=redirect-www"
      - "traefik.http.middlewares.redirect-www.redirectregex.regex=^https://www.mosaic.local/(.*)"
      - "traefik.http.middlewares.redirect-www.redirectregex.replacement=https://mosaic.local/$${1}"
```

## Troubleshooting

### Services Not Accessible via Domain

**Check Traefik is running:**

```bash
docker ps | grep traefik
```

**Check Traefik dashboard:**

```bash
# Bundled mode
open http://localhost:8080

# Check registered routers
curl http://localhost:8080/api/http/routers | jq
```

**Verify labels are applied:**

```bash
docker inspect mosaic-api | jq '.Config.Labels'
```

**Check DNS/hosts file:**

```bash
# Local development
cat /etc/hosts | grep mosaic
```

### Certificate Errors

**Self-signed certificates (development):**

- Browser warnings are expected
- Add exception in browser or import CA certificate

**Let's Encrypt failures:**

```bash
# Check Traefik logs
docker logs mosaic-traefik

# Verify ACME email is set
docker exec mosaic-traefik cat /etc/traefik/traefik.yml

# Check certificate storage
docker exec mosaic-traefik ls -la /letsencrypt/
```

### Upstream Mode Not Connecting

**Verify external network exists:**

```bash
docker network ls | grep traefik-public
```

**Create network if missing:**

```bash
docker network create traefik-public
```

**Check service network attachment:**

```bash
docker inspect mosaic-api | jq '.NetworkSettings.Networks'
```

**Verify external Traefik can see services:**

```bash
# From external Traefik container
docker exec <external-traefik-container> traefik healthcheck
```

### Port Conflicts

**Bundled mode port conflicts:**

```bash
# Check what's using ports
sudo lsof -i :80
sudo lsof -i :443
sudo lsof -i :8080

# Change ports in .env
TRAEFIK_HTTP_PORT=8000
TRAEFIK_HTTPS_PORT=8443
TRAEFIK_DASHBOARD_PORT=8081
```

### Dashboard Not Accessible

**Check dashboard is enabled:**

```bash
# In .env
TRAEFIK_DASHBOARD_ENABLED=true
```

**Verify Traefik configuration:**

```bash
docker exec mosaic-traefik cat /etc/traefik/traefik.yml | grep -A5 "api:"
```

**Access dashboard:**

```bash
# Default
http://localhost:8080/dashboard/

# Custom port
http://localhost:${TRAEFIK_DASHBOARD_PORT}/dashboard/
```

## Security Considerations

### Production Checklist

- [ ] Use Let's Encrypt or valid SSL certificates
- [ ] Disable Traefik dashboard or protect with authentication
- [ ] Enable HTTP to HTTPS redirect
- [ ] Configure rate limiting middleware
- [ ] Use strong passwords for all services
- [ ] Restrict Traefik dashboard to internal network
- [ ] Enable Traefik access logs for audit trail
- [ ] Regularly update Traefik image version

### Securing the Dashboard

**Option 1: Disable in production**

```bash
TRAEFIK_DASHBOARD_ENABLED=false
```

**Option 2: Add basic authentication**

```yaml
# docker-compose.override.yml
services:
  traefik:
    command:
      - "--configFile=/etc/traefik/traefik.yml"
      - "--api.dashboard=true"
    labels:
      - "traefik.http.routers.dashboard.rule=Host(`traefik.example.com`)"
      - "traefik.http.routers.dashboard.service=api@internal"
      - "traefik.http.routers.dashboard.middlewares=auth"
      - "traefik.http.middlewares.auth.basicauth.users=admin:$$apr1$$xyz..."
```

**Option 3: IP whitelist**

```yaml
# docker-compose.override.yml
services:
  traefik:
    labels:
      - "traefik.http.middlewares.ipwhitelist.ipwhitelist.sourcerange=127.0.0.1/32,10.0.0.0/8"
      - "traefik.http.routers.dashboard.middlewares=ipwhitelist"
```

## Performance Tuning

### Connection Limits

```yaml
# docker/traefik/traefik.yml
entryPoints:
  web:
    address: ":80"
    transport:
      respondingTimeouts:
        readTimeout: 60
        writeTimeout: 60
        idleTimeout: 180
  websecure:
    address: ":443"
    transport:
      respondingTimeouts:
        readTimeout: 60
        writeTimeout: 60
        idleTimeout: 180
```

### Rate Limiting

```yaml
# docker-compose.override.yml
services:
  traefik:
    labels:
      - "traefik.http.middlewares.ratelimit.ratelimit.average=100"
      - "traefik.http.middlewares.ratelimit.ratelimit.burst=200"
      - "traefik.http.middlewares.ratelimit.ratelimit.period=1s"
```

## Testing

Integration tests are available to verify Traefik configuration:

```bash
# Run all Traefik tests
./tests/integration/docker/traefik.test.sh all

# Test specific mode
./tests/integration/docker/traefik.test.sh bundled
./tests/integration/docker/traefik.test.sh upstream
./tests/integration/docker/traefik.test.sh none
```

See `tests/integration/docker/README.md` for details.

## Migration Guide

### From None Mode to Bundled Mode

```bash
# 1. Stop existing services
docker compose down

# 2. Backup current .env
cp .env .env.backup

# 3. Switch to bundled configuration
cp .env.traefik-bundled.example .env

# 4. Transfer existing secrets from .env.backup to .env

# 5. Start with Traefik profile
docker compose --profile traefik-bundled up -d

# 6. Update application URLs if needed
# Old: http://localhost:3000
# New: https://mosaic.local
```

### From Bundled Mode to Upstream Mode

```bash
# 1. Ensure external Traefik is running
docker network create traefik-public

# 2. Update .env
TRAEFIK_MODE=upstream
TRAEFIK_NETWORK=traefik-public

# 3. Create override file
cp docker-compose.override.yml.example docker-compose.override.yml

# 4. Edit override file to uncomment network section

# 5. Restart without bundled profile
docker compose down
docker compose up -d
```

## Additional Resources

- [Traefik Official Documentation](https://doc.traefik.io/traefik/)
- [Traefik Docker Provider](https://doc.traefik.io/traefik/providers/docker/)
- [Let's Encrypt with Traefik](https://doc.traefik.io/traefik/https/acme/)
- [Traefik Middleware Reference](https://doc.traefik.io/traefik/middlewares/overview/)
