Skip to main content

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:

FilePurpose
compose.ymlCore Hades services (API, Scheduler, NATS)
docker-compose.deploy.ymlAdds 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 hadesAPI service

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
warning

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 the traefik.enable=true label are exposed.
  • The web entrypoint automatically redirects all HTTP traffic to HTTPS.
  • The letsencrypt resolver 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"
LabelEffect
traefik.enable=trueOpt this container into Traefik routing
rule=Host(...)Route requests matching the configured hostname to this service
entrypoints=web,websecureAccept traffic on both HTTP and HTTPS entrypoints
tls.certresolver=letsencryptUse Let's Encrypt to issue and renew the TLS certificate
loadbalancer.server.port=8080Forward 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.