# Traefik Reverse Proxy Setup ## Overview Traefik serves as the reverse proxy and load balancer for Headquarter in production, handling: - SSL/TLS termination - Automatic HTTPS via Let's Encrypt - Route-based traffic distribution - WebSocket support ## Architecture ``` Internet ↓ Traefik (443) ├───▶ api.yourdomain.com → Headquarter API (8000) └───▶ app.yourdomain.com → Headquarter Web (80) ``` ## Prerequisites - Docker Compose installed - DNS records pointing to your server: - `api.yourdomain.com` → Server IP - `app.yourdomain.com` → Server IP - Ports 80 and 443 open in firewall ## Configuration ### 1. Environment Variables ```bash # .env file API_DOMAIN=api.headquarter.example.com WEB_DOMAIN=app.headquarter.example.com # Traefik network (shared with other Traefik instances) TRAEFIK_NETWORK=web # SSL Certificate resolver TRAEFIK_CERT_RESOLVER=letsencrypt ``` ### 2. Traefik Labels Services are configured via Docker labels: ```yaml # API Service labels labels: - "traefik.enable=true" - "traefik.http.routers.headquarter-api.rule=Host(`api.headquarter.example.com`)" - "traefik.http.routers.headquarter-api.entrypoints=websecure" - "traefik.http.routers.headquarter-api.tls=true" - "traefik.http.routers.headquarter-api.tls.certresolver=${TRAEFIK_CERT_RESOLVER:-letsencrypt}" - "traefik.http.services.headquarter-api.loadbalancer.server.port=8000" # Web Service labels labels: - "traefik.enable=true" - "traefik.http.routers.headquarter-frontend.rule=Host(`app.headquarter.example.com`)" - "traefik.http.routers.headquarter-frontend.entrypoints=websecure" - "traefik.http.routers.headquarter-frontend.tls=true" - "traefik.http.routers.headquarter-frontend.tls.certresolver=${TRAEFIK_CERT_RESOLVER:-letsencrypt}" - "traefik.http.services.headquarter-frontend.loadbalancer.server.port=80" ``` ### 3. External Network Connect to existing Traefik instance: ```yaml networks: traefik: external: true name: ${TRAEFIK_NETWORK:-traefik} ``` ## Deployment Steps ### Step 1: Verify DNS Ensure DNS records resolve to your server: ```bash nslookup api.headquarter.example.com nslookup app.headquarter.example.com ``` ### Step 2: Start Services ```bash # Start with Traefik compose file docker compose -f docker-compose.traefik.yml up -d # Verify containers are running docker compose -f docker-compose.traefik.yml ps ``` ### Step 3: Check SSL Certificates ```bash # View Traefik logs docker compose -f docker-compose.traefik.yml logs -f # Check certificate status curl -v https://api.headquarter.example.com/health ``` ### Step 4: Run Migrations ```bash docker compose -f docker-compose.traefik.yml exec api alembic upgrade head ``` ## SSL Configuration ### Let's Encrypt (Default) Automatic certificate generation and renewal: ```yaml labels: - "traefik.http.routers.headquarter-api.tls.certresolver=letsencrypt" ``` ### Custom Certificates For custom or wildcard certificates: ```yaml labels: - "traefik.http.routers.headquarter-api.tls=true" - "traefik.http.routers.headquarter-api.tls.certresolver=myresolver" ``` ### Self-Signed (Development) ```yaml labels: - "traefik.http.routers.headquarter-api.tls=true" - "traefik.http.routers.headquarter-api.tls.certresolver=selfsigned" ``` ## Advanced Configuration ### Rate Limiting ```yaml labels: - "traefik.http.middlewares.ratelimit.ratelimit.average=100" - "traefik.http.routers.headquarter-api.middlewares=ratelimit" ``` ### Basic Auth (for staging) ```yaml labels: - "traefik.http.middlewares.auth.basicauth.users=admin:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/" - "traefik.http.routers.headquarter-api.middlewares=auth" ``` ### CORS Headers ```yaml labels: - "traefik.http.middlewares.cors.headers.accesscontrolalloworiginlist=*" - "traefik.http.routers.headquarter-api.middlewares=cors" ``` ## Troubleshooting ### Certificate Issues **Problem**: Certificate not generated ```bash # Check Traefik logs docker compose logs traefik # Verify DNS resolution nslookup your-domain.com # Check port 80 is accessible (required for HTTP challenge) curl -I http://your-domain.com ``` **Problem**: Certificate expired ```bash # Force renewal docker compose restart traefik # Or delete acme.json and restart rm acme.json docker compose restart traefik ``` ### Routing Issues **Problem**: 404 errors ```bash # Check Traefik dashboard (if enabled) # http://traefik.yourdomain.com # Verify labels are correct docker compose -f docker-compose.traefik.yml config # Check container is on correct network docker network inspect ${TRAEFIK_NETWORK:-traefik} ``` **Problem**: Services not detected ```bash # Verify traefik.enable label docker compose -f docker-compose.traefik.yml exec api labels # Check Docker provider in Traefik docker compose logs traefik | grep "Provider connection established" ``` ## Maintenance ### Update Traefik ```bash # Pull latest Traefik image docker compose -f docker-compose.traefik.yml pull traefik # Restart docker compose -f docker-compose.traefik.yml up -d traefik ``` ### View Dashboard Enable Traefik dashboard (secure it in production): ```yaml # traefik.yml dashboard: enabled: true # Add to docker-compose.traefik.yml labels: - "traefik.http.routers.dashboard.rule=Host(`traefik.yourdomain.com`)" - "traefik.http.routers.dashboard.tls=true" - "traefik.http.routers.dashboard.tls.certresolver=letsencrypt" ``` ## Security Considerations 1. **Always use HTTPS** in production (redirect HTTP to HTTPS) 2. **Secure Traefik dashboard** with authentication 3. **Use strong certificate resolver** (Let's Encrypt production) 4. **Keep Traefik updated** for security patches 5. **Restrict Docker socket access** if using Docker provider ## Example Complete Configuration ```yaml # docker-compose.traefik.yml services: api: build: context: ./apps/api environment: API_DOMAIN: ${API_DOMAIN} WEB_DOMAIN: ${WEB_DOMAIN} # ... other env vars labels: - "traefik.enable=true" - "traefik.http.routers.headquarter-api.rule=Host(`${API_DOMAIN}`)" - "traefik.http.routers.headquarter-api.entrypoints=websecure" - "traefik.http.routers.headquarter-api.tls=true" - "traefik.http.routers.headquarter-api.tls.certresolver=${TRAEFIK_CERT_RESOLVER:-letsencrypt}" - "traefik.http.services.headquarter-api.loadbalancer.server.port=8000" networks: - backend - traefik web: build: context: ./apps/web labels: - "traefik.enable=true" - "traefik.http.routers.headquarter-frontend.rule=Host(`${WEB_DOMAIN}`)" - "traefik.http.routers.headquarter-frontend.entrypoints=websecure" - "traefik.http.routers.headquarter-frontend.tls=true" - "traefik.http.routers.headquarter-frontend.tls.certresolver=${TRAEFIK_CERT_RESOLVER:-letsencrypt}" - "traefik.http.services.headquarter-frontend.loadbalancer.server.port=80" networks: - traefik networks: traefik: external: true name: ${TRAEFIK_NETWORK:-traefik} backend: internal: true ``` ## Resources - [Traefik Documentation](https://doc.traefik.io/traefik/) - [Docker Compose Integration](https://doc.traefik.io/traefik/providers/docker/) - [Let's Encrypt Configuration](https://doc.traefik.io/traefik/https/acme/)