# Traefik Stack - Reverse Proxy with SSL ## Overview Traefik acts as the central reverse proxy for all services, handling: - Automatic SSL certificate generation via Let's Encrypt - HTTP to HTTPS redirection - Service discovery via Docker labels - Security headers and compression - Rate limiting and access control ## Services - **traefik.michaelschiemer.de** - Traefik Dashboard (BasicAuth protected) - Protected by BasicAuth authentication - Accessible via HTTPS with Let's Encrypt certificate ## Local Development For local development, use the separate local configuration to avoid port conflicts and Let's Encrypt errors: ### Quick Start (Local Development) ```bash # Ensure Docker network exists docker network create traefik-public 2>/dev/null || true # Start Traefik with local configuration cd deployment/stacks/traefik docker compose -f docker-compose.local.yml up -d # Check logs docker compose -f docker-compose.local.yml logs -f # Access dashboard at http://localhost:8093/dashboard/ # Note: Dashboard is served on the API port (8093) when api.insecure=true ``` ### Local Development Configuration The local configuration (`docker-compose.local.yml` and `traefik.local.yml`) differs from production: - **Bridge network** instead of `host` mode (avoids port conflicts) - **Port mappings**: `8081:80` (HTTP) and `8093:8080` (API/Dashboard) - Note: HTTPS not needed locally - avoids port conflicts with web container (8443:443) - **HTTP-only** (no ACME/Let's Encrypt) for local development - **Dashboard**: Accessible at `http://localhost:8093/dashboard/` (HTTP, no authentication) - Also available: `http://localhost:8093/api/rawdata` and `http://localhost:8093/api/http/routers` - Note: Dashboard is served on the API port (8093) when `api.insecure=true` in `traefik.local.yml` - **No `acme.json`** required - **Console logging** (human-readable) instead of JSON file logs ### Local Development vs Production | Feature | Local (`docker-compose.local.yml`) | Production (`docker-compose.yml`) | |---------|-----------------------------------|----------------------------------| | Network Mode | Bridge | Bridge | | Ports | 8081:80, 8093:8080 (HTTP only) | 80:80, 443:443, 2222:2222 | | SSL/TLS | HTTP-only | HTTPS with Let's Encrypt | | Dashboard | `http://localhost:8093/dashboard/` | `https://traefik.michaelschiemer.de` | | Authentication | None (local dev) | BasicAuth | | Logging | Console (human-readable) | JSON files | | ACME | Disabled | Enabled | ### Troubleshooting Local Development **Container restarts in loop:** - Check if ports 8081 or 8093 are already in use: `netstat -tlnp | grep -E ':(8081|8093)' || ss -tlnp | grep -E ':(8081|8093)'` - Verify Docker network exists: `docker network ls | grep traefik-public` - Check logs: `docker compose -f docker-compose.local.yml logs -f traefik` **Services not accessible through Traefik:** - Ensure services are on `traefik-public` network - Verify Traefik labels are correctly configured - Check that services are running: `docker compose ps` ## Prerequisites 1. **Docker Network** ```bash docker network create traefik-public ``` 2. **ACME Storage File** ```bash touch acme.json chmod 600 acme.json ``` 3. **DNS Configuration** Point these domains to your server IP (94.16.110.151): - `michaelschiemer.de` - `*.michaelschiemer.de` (wildcard) ## Configuration ### 1. Create Environment File ```bash cp .env.example .env ``` ### 2. Generate Dashboard Password ```bash # Generate password hash htpasswd -nb admin your_secure_password # Example output: # admin:$apr1$8kj9d7lj$r.x5jhLVPLuCDLvJ6x0Hd0 # Important: In docker-compose.yml, replace $ with $$ # admin:$$apr1$$8kj9d7lj$$r.x5jhLVPLuCDLvJ6x0Hd0 ``` Update the `traefik.http.middlewares.traefik-auth.basicauth.users` label in `docker-compose.yml`. ### 3. Adjust Configuration (Optional) Edit `traefik.yml` for: - Log levels - Certificate resolvers - Additional entry points - Metrics configuration ## Deployment ### Initial Setup ```bash # Create network docker network create traefik-public # Create acme.json touch acme.json chmod 600 acme.json # Create log directories mkdir -p logs # Start Traefik docker compose up -d ``` ### Verify Deployment ```bash # Check container status docker compose ps # Check logs docker compose logs -f # Test dashboard access curl -I https://traefik.michaelschiemer.de # Check certificate openssl s_client -connect traefik.michaelschiemer.de:443 -servername traefik.michaelschiemer.de < /dev/null ``` ## Middleware Configuration Traefik provides several reusable middlewares in `dynamic/middlewares.yml`: ### Security Headers ```yaml labels: - "traefik.http.routers.myapp.middlewares=security-headers-global@file" ``` ### Rate Limiting ```yaml labels: # Strict: 50 req/s - "traefik.http.routers.myapp.middlewares=rate-limit-strict@file" # Moderate: 100 req/s - "traefik.http.routers.myapp.middlewares=rate-limit-moderate@file" # Lenient: 200 req/s - "traefik.http.routers.myapp.middlewares=rate-limit-lenient@file" ``` ### Compression ```yaml labels: - "traefik.http.routers.myapp.middlewares=gzip-compression@file" ``` ### VPN-Only Access (WireGuard Network) ```yaml labels: # Restrict access to WireGuard VPN network only (10.8.0.0/24) - "traefik.http.routers.myapp.middlewares=vpn-only@file" # Combined: VPN-only + BasicAuth (order matters - VPN check first, then BasicAuth) - "traefik.http.routers.myapp.middlewares=vpn-only@file,traefik-auth" ``` ### Middleware Chains ```yaml labels: # Default chain: Security + Compression - "traefik.http.routers.myapp.middlewares=default-chain@file" # Admin chain: Security + Compression + Rate Limiting - "traefik.http.routers.myapp.middlewares=admin-chain@file" ``` ## Service Integration ### Example Service Configuration Add these labels to any Docker service to expose it through Traefik: ```yaml services: myapp: image: myapp:latest networks: - traefik-public labels: # Enable Traefik - "traefik.enable=true" # Router configuration - "traefik.http.routers.myapp.rule=Host(`app.michaelschiemer.de`)" - "traefik.http.routers.myapp.entrypoints=websecure" - "traefik.http.routers.myapp.tls=true" - "traefik.http.routers.myapp.tls.certresolver=letsencrypt" # Service configuration - "traefik.http.services.myapp.loadbalancer.server.port=80" # Middleware (optional) - "traefik.http.routers.myapp.middlewares=default-chain@file" networks: traefik-public: external: true ``` ## Monitoring ### Dashboard Access Access the Traefik dashboard at: https://traefik.michaelschiemer.de Default credentials (change in production): - Username: `admin` - Password: (set via htpasswd) ### Logs ```bash # Access logs (HTTP requests) tail -f logs/access.log # Traefik logs (errors, warnings) tail -f logs/traefik.log # Container logs docker compose logs -f traefik ``` ### Prometheus Metrics Traefik exposes Prometheus metrics for monitoring: ```yaml # Add to Prometheus scrape config - job_name: 'traefik' static_configs: - targets: ['traefik:8082'] ``` ## Troubleshooting ### Certificate Issues ```bash # Check acme.json permissions ls -la acme.json # Should be: -rw------- (600) # View certificate status docker compose logs traefik | grep -i "certificate" # Force certificate renewal rm acme.json touch acme.json chmod 600 acme.json docker compose restart ``` ### DNS Issues ```bash # Verify DNS resolution dig michaelschiemer.de dig git.michaelschiemer.de # Check from external nslookup michaelschiemer.de 8.8.8.8 ``` ### Service Not Accessible ```bash # Check Traefik can reach service docker network inspect traefik-public # Verify service labels docker inspect | grep -A 20 Labels # Check Traefik logs for routing errors docker compose logs traefik | grep -i error ``` ### Port Conflicts ```bash # Check if ports 80/443 are free sudo netstat -tlnp | grep -E ':80|:443' # Stop conflicting services sudo systemctl stop nginx # or apache2 ``` ## Security Hardening ### 1. IP Whitelisting Uncomment and configure in `dynamic/middlewares.yml`: ```yaml admin-whitelist: ipWhiteList: sourceRange: - "your.vpn.ip.range/32" - "10.0.0.0/8" ``` ### 2. Strong Dashboard Password ```bash # Generate strong password openssl rand -base64 32 # Create hash htpasswd -nb admin "your_strong_password" ``` ### 3. Rate Limiting Apply rate limiting to sensitive endpoints: ```yaml labels: - "traefik.http.routers.admin.middlewares=rate-limit-strict@file" ``` ### 4. DDoS Protection ```yaml # In traefik.yml - add entry point middleware entryPoints: websecure: address: ":443" http: middlewares: - rate-limit-moderate@file ``` ## Backup ### Important Files - `acme.json` - SSL certificates - `traefik.yml` - Static configuration - `dynamic/` - Dynamic configuration ```bash # Backup certificates cp acme.json acme.json.backup.$(date +%Y%m%d) # Backup configuration tar -czf traefik-config-backup.tar.gz traefik.yml dynamic/ ``` ## Updates ```bash # Pull latest image docker compose pull # Restart with new image docker compose up -d # Verify docker compose ps docker compose logs -f ``` ## Performance Tuning ### Connection Limits In `traefik.yml`: ```yaml entryPoints: websecure: transport: respondingTimeouts: readTimeout: 60s writeTimeout: 60s lifeCycle: requestAcceptGraceTimeout: 0s graceTimeOut: 10s ``` ### Resource Limits In `docker-compose.yml`: ```yaml deploy: resources: limits: memory: 512M cpus: '0.5' reservations: memory: 256M cpus: '0.25' ``` ## Support For issues with Traefik configuration: 1. Check official Traefik documentation: https://doc.traefik.io/traefik/ 2. Review logs: `docker compose logs -f` 3. Verify network connectivity: `docker network inspect traefik-public`