Traefik — Operations Workbook
Traefik v2 reverse proxy on Hostinger VPS (vps-h1). Handles TLS termination and HTTP/S routing for all services on vps-h1.
Architecture
Hostinger VPS (72.60.32.61)
└── Container: root-traefik-1 image: traefik:v2.x
├── port 80 HTTP (redirect to HTTPS)
├── port 443 HTTPS (TLS termination)
├── ACME provider: Let's Encrypt (HTTP-01 challenge)
└── volume: traefik_acme (/etc/traefik/acme.json — TLS cert store)
Routing (label-based, per-container):
n8n.vps-h1.infra.zintegrowana.online → root-n8n-1 :5678
waha2.vps-h1.infra.zintegrowana.online → waha :13000
claude-proxy.vps-h1.infra.zintegrowana.online → claude-proxy :80
(any new service: add Traefik labels to its compose service)DNS: Wildcard *.vps-h1.infra.zintegrowana.online → 72.60.32.61 (Cloudflare, zone 57cb3d8f24c7cc319fb703394edc7b87).
Compose file on server: /root/docker-compose.yml
Compose file in repo: hostinger/docker-compose.yml
No dedicated Traefik dashboard URL is exposed publicly. Dashboard is disabled or bound to localhost only.
Config Management
| Config element | Location | In repo? | Notes |
|---|---|---|---|
| Static config | Traefik CLI flags in docker-compose.yml labels | Yes | entrypoints, ACME resolver, log level |
| Dynamic routing | Per-service Docker labels in docker-compose.yml | Yes | router + service definitions |
| TLS certs | traefik_acme Docker volume (acme.json) | No | Auto-managed by Let’s Encrypt |
.env | /root/.env on vps-h1 | No | Holds secrets referenced in compose |
Adding a new routed service
# In hostinger/docker-compose.yml — add labels to the new service:
labels:
- "traefik.enable=true"
- "traefik.http.routers.myservice.rule=Host(`myservice.vps-h1.infra.zintegrowana.online`)"
- "traefik.http.routers.myservice.entrypoints=websecure"
- "traefik.http.routers.myservice.tls.certresolver=letsencrypt"
- "traefik.http.services.myservice.loadbalancer.server.port=8080"# Deploy
git pull
cd /root
docker compose up -d myservice
# Traefik detects new labels dynamically — no Traefik restart neededModifying Traefik static config
Static config changes (entrypoints, ACME settings) require a Traefik restart:
docker compose -f /root/docker-compose.yml restart traefikDeployment
Fresh install
# On vps-h1 as root
cd /root
# Ensure .env is populated
docker compose up -d traefikRestart Traefik
docker compose -f /root/docker-compose.yml restart traefikCheck routing
# Verify Traefik is running
docker inspect root-traefik-1 --format '{{.State.Status}}'
# Check TLS cert for a domain
curl -I https://n8n.vps-h1.infra.zintegrowana.online
# Local HTTP check (should redirect to HTTPS)
curl -I http://72.60.32.61Backup
| Data | Method | Schedule | Destination |
|---|---|---|---|
| Routing config (compose labels) | Git repo | On every push | GitHub radieu/p24-infra |
TLS certs (traefik_acme volume) | Not backed up | — | Auto-renewed by Let’s Encrypt |
.env secrets | Not backed up in git — use .env.local on local workstation | — | Local workstation + GH Secrets |
TLS certs: If
traefik_acmevolume is lost, Traefik requests new certificates from Let’s Encrypt on first HTTPS request. Brief per-domain delay (~10s) during initial cert provisioning. Not a data-loss risk. Let’s Encrypt rate limit: 5 certificates per domain per week — avoid frequent volume destruction.
Backup = config fully in git. Restore is git pull + compose up.
Restore
Scenario 1: Traefik container crash
docker compose -f /root/docker-compose.yml up -d traefik
# TLS certs in traefik_acme volume survive container restartsScenario 2: Full vps-h1 rebuild
# 1. Provision new Hostinger VPS (Ubuntu 24.04)
# 2. Install Docker
# 3. Clone or copy compose file
git clone https://github.com/radieu/p24-infra /opt/p24-infra
cp /opt/p24-infra/hostinger/docker-compose.yml /root/docker-compose.yml
# 4. Restore .env from local workstation
scp -i C:\Users\konar\.ssh\id_ed25519 .env.local root@72.60.32.61:/root/.env
# 5. Start full stack (Traefik first — it must be up before routed services)
docker compose -f /root/docker-compose.yml up -d traefik
docker compose -f /root/docker-compose.yml up -d
# 6. TLS certs auto-provisioned on first HTTPS request per domainEstimated RTO: ~10 minutes (compose up + cert provisioning per domain).
Healthcheck / Monitoring
| Check | Method | Alert |
|---|---|---|
| Container running | cAdvisor container metrics scraped by Prometheus (job cadvisor, 72.60.32.61:8080) | ContainerCrashLooping if restarting |
| HTTP 80 responding | curl http://72.60.32.61 → expect 301/302 redirect | Manual check |
| HTTPS endpoint reachability | Blackbox exporter probes per-service URLs | EndpointDown alert per routed service |
| TLS cert expiry | Blackbox exporter ssl_earliest_cert_expiry metric | No dedicated alert rule yet — gap |
No dedicated Traefik metrics endpoint is configured. cAdvisor provides container-level CPU/mem/restart metrics only.
Manual health check:
# Container up?
ssh root@72.60.32.61 "docker inspect root-traefik-1 --format '{{.State.Status}} {{.State.Health.Status}}'"
# Verify a routed service end-to-end
curl -o /dev/null -s -w "%{http_code}" https://n8n.vps-h1.infra.zintegrowana.online/healthzPassword Rotation
Traefik has no own admin password. The dashboard is not publicly exposed.
| Credential | Managed by | Rotation |
|---|---|---|
| TLS certificates | Let’s Encrypt ACME (auto-renewed) | 90-day cycle, fully automatic |
| Traefik API tokens | None configured | N/A |
| Routed service credentials | Per-service — see each service’s ops workbook | Per-service schedule |
No password rotation action required for Traefik itself.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| 404 on a routed domain | Labels missing or wrong Host() rule | Check compose labels; docker compose up -d <service> |
| TLS cert not provisioning | HTTP-01 challenge blocked (port 80 closed) | Ensure port 80 is open in Hostinger firewall |
acme.json permission error | Traefik requires chmod 600 acme.json | docker exec root-traefik-1 chmod 600 /etc/traefik/acme.json |
| 502 Bad Gateway | Upstream container not running | docker compose -f /root/docker-compose.yml up -d <service> |
| Traefik won’t start | Port 80/443 already bound | `ss -tlnp |
| Let’s Encrypt rate limit hit | Too many cert requests for a domain | Wait up to 1 week; use staging ACME URL for testing |