- Add QUICKSTART.md and SETUP_REPOSITORY.md for Semaphore stack - Add playbooks directory for Semaphore deployment - Update Semaphore docker-compose.yml, env.example, and README - Add Traefik local configuration files - Disable semaphore.yml in Traefik dynamic config - Update docker-compose.local.yml and build-image workflow
443 lines
9.6 KiB
Markdown
443 lines
9.6 KiB
Markdown
# 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 (VPN-only + BasicAuth protected)
|
|
- ?? **Nur ?ber WireGuard VPN erreichbar** (10.8.0.0/24)
|
|
- Zus?tzlich durch BasicAuth gesch?tzt
|
|
- ?ffentlicher Zugriff ist blockiert
|
|
|
|
## 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:8080/dashboard/
|
|
```
|
|
|
|
### 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**: `8080:80` only (HTTP-only for local development)
|
|
- 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:8080/dashboard/` (HTTP, no authentication)
|
|
- Also available: `http://localhost:8080/api/rawdata` and `http://localhost:8080/api/http/routers`
|
|
- **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 | Host |
|
|
| Ports | 8080:80 (HTTP only) | Direct binding (80, 443) |
|
|
| SSL/TLS | HTTP-only | HTTPS with Let's Encrypt |
|
|
| Dashboard | `http://localhost:8080/dashboard/` | `https://traefik.michaelschiemer.de` |
|
|
| Authentication | None (local dev) | VPN + BasicAuth |
|
|
| Logging | Console (human-readable) | JSON files |
|
|
| ACME | Disabled | Enabled |
|
|
|
|
### Troubleshooting Local Development
|
|
|
|
**Container restarts in loop:**
|
|
- Check if port 8080 is already in use: `netstat -tlnp | grep ':8080' || ss -tlnp | grep ':8080'`
|
|
- 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 <container_name> | 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`
|