- Remove middleware reference from Gitea Traefik labels (caused routing issues) - Optimize Gitea connection pool settings (MAX_IDLE_CONNS=30, authentication_timeout=180s) - Add explicit service reference in Traefik labels - Fix intermittent 504 timeouts by improving PostgreSQL connection handling Fixes Gitea unreachability via git.michaelschiemer.de
9.8 KiB
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)
# 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
hostmode (avoids port conflicts) - Port mappings:
8081:80(HTTP) and8093: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/rawdataandhttp://localhost:8093/api/http/routers - Note: Dashboard is served on the API port (8093) when
api.insecure=trueintraefik.local.yml
- Also available:
- No
acme.jsonrequired - 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-publicnetwork - Verify Traefik labels are correctly configured
- Check that services are running:
docker compose ps
Prerequisites
-
Docker Network
docker network create traefik-public -
ACME Storage File
touch acme.json chmod 600 acme.json -
DNS Configuration Point these domains to your server IP (94.16.110.151):
michaelschiemer.de*.michaelschiemer.de(wildcard)
Configuration
1. Create Environment File
cp .env.example .env
2. Generate Dashboard Password
# 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
# 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
# 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
labels:
- "traefik.http.routers.myapp.middlewares=security-headers-global@file"
Rate Limiting
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
labels:
- "traefik.http.routers.myapp.middlewares=gzip-compression@file"
VPN-Only Access (WireGuard Network)
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
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:
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
# 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:
# Add to Prometheus scrape config
- job_name: 'traefik'
static_configs:
- targets: ['traefik:8082']
Troubleshooting
Certificate Issues
# 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
# Verify DNS resolution
dig michaelschiemer.de
dig git.michaelschiemer.de
# Check from external
nslookup michaelschiemer.de 8.8.8.8
Service Not Accessible
# Check Traefik can reach service
docker network inspect traefik-public
# Verify service labels
docker inspect <container_name> | grep -A 20 Labels
# Check Traefik logs for routing errors
docker compose logs traefik | grep -i error
Port Conflicts
# 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:
admin-whitelist:
ipWhiteList:
sourceRange:
- "your.vpn.ip.range/32"
- "10.0.0.0/8"
2. Strong Dashboard Password
# Generate strong password
openssl rand -base64 32
# Create hash
htpasswd -nb admin "your_strong_password"
3. Rate Limiting
Apply rate limiting to sensitive endpoints:
labels:
- "traefik.http.routers.admin.middlewares=rate-limit-strict@file"
4. DDoS Protection
# In traefik.yml - add entry point middleware
entryPoints:
websecure:
address: ":443"
http:
middlewares:
- rate-limit-moderate@file
Backup
Important Files
acme.json- SSL certificatestraefik.yml- Static configurationdynamic/- Dynamic configuration
# 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
# 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:
entryPoints:
websecure:
transport:
respondingTimeouts:
readTimeout: 60s
writeTimeout: 60s
lifeCycle:
requestAcceptGraceTimeout: 0s
graceTimeOut: 10s
Resource Limits
In docker-compose.yml:
deploy:
resources:
limits:
memory: 512M
cpus: '0.5'
reservations:
memory: 256M
cpus: '0.25'
Support
For issues with Traefik configuration:
- Check official Traefik documentation: https://doc.traefik.io/traefik/
- Review logs:
docker compose logs -f - Verify network connectivity:
docker network inspect traefik-public