Install Traefik Reverse Proxy on VPS Docker
Traefik is a modern reverse proxy designed specifically for containerized environments. Its key advantages are automatic Docker label detection, SSL acquisition from Let's Encrypt without setting up Certbot separately, and configuration reloads without service restarts. It's ideal for VPS deployments running multiple services simultaneously.
Prepare Docker Network
# Create a shared network for Traefik
docker network create traefik-public
# Verify Docker is installed
docker --version
docker compose version
Directory Structure
mkdir -p ~/traefik/config ~/traefik/certs
cd ~/traefik
# Create acme.json to store SSL certificates
touch certs/acme.json
chmod 600 certs/acme.json
Create traefik.yml (Static Config)
cat > config/traefik.yml << 'EOF'
api:
dashboard: true
insecure: false
entryPoints:
web:
address: ":80"
http:
redirections:
entrypoint:
to: websecure
scheme: https
websecure:
address: ":443"
certificatesResolvers:
letsencrypt:
acme:
email: [email protected]
storage: /certs/acme.json
tlsChallenge: {}
providers:
docker:
exposedByDefault: false
network: traefik-public
file:
directory: /config/dynamic
watch: true
EOF
Create docker-compose.yml for Traefik
cat > docker-compose.yml << 'EOF'
version: "3.8"
services:
traefik:
image: traefik:v3.0
container_name: traefik
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./config/traefik.yml:/traefik.yml:ro
- ./config/dynamic:/config/dynamic:ro
- ./certs/acme.json:/certs/acme.json
networks:
- traefik-public
labels:
- "traefik.enable=true"
- "traefik.http.routers.dashboard.rule=Host(\`traefik.yourdomain.com\`)"
- "traefik.http.routers.dashboard.tls.certresolver=letsencrypt"
- "traefik.http.routers.dashboard.service=api@internal"
- "traefik.http.routers.dashboard.middlewares=auth"
- "traefik.http.middlewares.auth.basicauth.users=admin:$$apr1$$hash"
networks:
traefik-public:
external: true
EOF
docker compose up -d
Add Services for Traefik to Route
# Example docker-compose.yml for your application
services:
myapp:
image: nginx:alpine
networks:
- traefik-public
labels:
- "traefik.enable=true"
- "traefik.http.routers.myapp.rule=Host(\`app.yourdomain.com\`)"
- "traefik.http.routers.myapp.tls.certresolver=letsencrypt"
- "traefik.http.services.myapp.loadbalancer.server.port=80"
networks:
traefik-public:
external: true
Set Up Additional Middleware
# Dynamic config: config/dynamic/middlewares.yml
http:
middlewares:
security-headers:
headers:
stsSeconds: 31536000
stsIncludeSubdomains: true
contentTypeNosniff: true
browserXssFilter: true
referrerPolicy: "strict-origin-when-cross-origin"
rate-limit:
rateLimit:
average: 100
burst: 50
Verify Traefik is Working Correctly
# Check container status
docker compose ps
# View logs
docker compose logs traefik -f
# Verify ports 80/443 are open
ss -tlnp | grep -E '80|443'
# Test HTTP redirect
curl -I http://yourdomain.com
https://traefik.yourdomain.com to view all active routers, services, and middlewares in real-time.
Common Issues & Troubleshooting
Error: "acme.json has wrong permissions"
The acme.json file must have permission 600 only, otherwise Traefik will refuse to start:
chmod 600 ~/traefik/certs/acme.json
docker compose restart traefik
SSL Certificate Not Being Issued (Stuck at ACME Challenge)
Port 80 must be publicly open for HTTP challenge. Check your firewall:
# Check UFW status
sudo ufw status
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# View Traefik logs for ACME errors
docker logs traefik 2>&1 | grep -i "acme\|cert\|error"
New Container Not Being Routed
You may have forgotten the traefik.enable=true label or the network doesn't match. Check:
# View container labels
docker inspect myapp | grep -A 20 Labels
# Verify container is in traefik-public network
docker network inspect traefik-public
Dashboard Access Denied (401 Unauthorized)
Generate a proper basic auth hash:
# Generate hash for user admin with password=mypassword
echo $(htpasswd -nb admin mypassword) | sed -e s/\\$/\\$\\$/g
# Use the output in the basicauth.users label
Frequently Asked Questions
How is Traefik different from Nginx Proxy Manager?
Nginx Proxy Manager has a web UI that's easy for beginners, but Traefik integrates with Docker labels automatically. It's ideal for DevOps teams managing infrastructure as code — no need to click through the UI every time you add a service.
Does Traefik support TCP (non-HTTP) routing?
Yes, Traefik supports TCP and UDP routing through custom EntryPoints. You can route MySQL port 3306 or game server UDP ports without needing a separate Nginx instance.
Can I use Traefik with Cloudflare?
Absolutely. Use Cloudflare DNS challenge instead of HTTP challenge to obtain wildcard SSL certificates, and Cloudflare provides DDoS protection before traffic reaches Traefik. You can also set trustedIPs so Traefik sees visitor real IPs.