Traefik Deployment
Hades ships with a ready-to-use Traefik configuration that exposes the API over HTTPS with automatic TLS via Let's Encrypt. This is the recommended way to deploy Hades on a VM or bare-metal server.
Overview
The Traefik setup uses Docker Compose and consists of two compose files that are layered together:
| File | Purpose |
|---|---|
compose.yml | Core Hades services (API, Scheduler, NATS) |
docker-compose.deploy.yml | Adds Traefik reverse proxy with TLS and removes host port bindings |
Traefik handles:
- HTTP → HTTPS redirect (port 80 → 443)
- Automatic TLS certificate issuance and renewal via Let's Encrypt (ACME HTTP-01 challenge)
- Reverse proxying to the
hadesAPIservice
Prerequisites
- A public server (VM, VPS, dedicated host) with Docker and Docker Compose installed
- A domain name pointing to the server's public IP (e.g.,
hades.example.com) - Ports 80 and 443 open in the server's firewall
Setup
1. Clone the Repository
git clone https://github.com/ls1intum/hades.git
cd hades
2. Configure Environment Variables
cp .env.example .env
Edit .env and set the following values:
# Your email address — Let's Encrypt will send certificate expiry notices here
LETSENCRYPT_EMAIL=you@example.com
# The public domain name for the Hades API
HADES_API_HOST=hades.example.com
3. Create the Traefik ACME Storage File
Traefik stores issued certificates in a local JSON file. Create it with the correct permissions:
touch traefik/acme.json
chmod 600 traefik/acme.json
The acme.json file must have mode 0600. If permissions are too open, Traefik will refuse to start.
4. Deploy
Start all services using both compose files:
docker compose -f compose.yml -f docker-compose.deploy.yml up -d
This starts:
- Traefik on ports 80 and 443 — handles TLS termination and routing
- hadesAPI — exposed only internally (no host port binding)
- hadesScheduler — connected to the Docker socket
- nats — internal only
How It Works
Traefik Configuration (traefik/traefik.yml)
log:
level: INFO
api:
dashboard: true
entryPoints:
web:
address: ":80"
http:
redirections:
entryPoint:
to: websecure
scheme: https
websecure:
address: ":443"
providers:
docker:
exposedByDefault: false
certificatesResolvers:
letsencrypt:
acme:
storage: /etc/traefik/acme.json
httpChallenge:
entryPoint: web
Key points:
exposedByDefault: false— only services with thetraefik.enable=truelabel are exposed.- The
webentrypoint automatically redirects all HTTP traffic to HTTPS. - The
letsencryptresolver uses the HTTP-01 challenge over port 80 to verify domain ownership.
Docker Labels on hadesAPI
The API service in docker-compose.deploy.yml uses Traefik Docker labels to configure routing:
labels:
- "traefik.enable=true"
- "traefik.http.routers.hadesapi.rule=Host(`${HADES_API_HOST}`)"
- "traefik.http.routers.hadesapi.entrypoints=web,websecure"
- "traefik.http.routers.hadesapi.tls.certresolver=letsencrypt"
- "traefik.http.services.hadesapi.loadbalancer.server.port=8080"
| Label | Effect |
|---|---|
traefik.enable=true | Opt this container into Traefik routing |
rule=Host(...) | Route requests matching the configured hostname to this service |
entrypoints=web,websecure | Accept traffic on both HTTP and HTTPS entrypoints |
tls.certresolver=letsencrypt | Use Let's Encrypt to issue and renew the TLS certificate |
loadbalancer.server.port=8080 | Forward traffic to the container's internal port 8080 |
Verifying the Deployment
Check Container Status
docker compose -f compose.yml -f docker-compose.deploy.yml ps
All services should show running. Traefik may take 30–60 seconds on first start to issue a certificate.
Test HTTPS
curl https://hades.example.com/health
Or submit a test job:
curl -X POST https://hades.example.com/build \
-H "Content-Type: application/json" \
-d '{
"name": "Traefik Test",
"steps": [
{
"id": 1,
"name": "Echo",
"image": "alpine:latest",
"script": "echo Hello over HTTPS!"
}
]
}'
Check Traefik Logs
docker logs traefik -f
Look for lines like:
msg="Configuration loaded from file: /etc/traefik/traefik.yml"
msg="Starting server" entryPointName=web
msg="Starting server" entryPointName=websecure
Updating Hades
To pull the latest images and restart the stack:
docker compose -f compose.yml -f docker-compose.deploy.yml pull
docker compose -f compose.yml -f docker-compose.deploy.yml up -d
Stopping the Stack
docker compose -f compose.yml -f docker-compose.deploy.yml down
The acme.json file is preserved on disk, so certificates are retained between restarts.
Ansible Automation
For fully automated VM provisioning and deployment, Hades includes Ansible playbooks. See the ansible/hades/README.md in the repository for details.