Deployment
Habeas runs as two containers from the same image. The engine runs libtorrent + the FastAPI backend. The web service runs the SvelteKit frontend and proxies API calls to the engine.
Network modes
Pick one compose file. Each wires the two containers differently based on how you want traffic routed.
Default bridge networking. No VPN tunnel. Good for testing or if your host already has a VPN interface you handle separately.
services:
docket-engine:
build: .
container_name: docket-engine
env_file: .env
environment:
- DOCKET_NETWORK_PROFILE=direct
- VPN_COMPOSE_MODE=container
volumes:
- ./data:/app/data
- ./logs:/app/logs
- ${DOCKET_STORAGE_MOUNT:-./storage:/storage}
ports:
- "${DOCKET_ENGINE_PORT:-54323}:54323"
restart: unless-stopped
command: ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "54323"]
docket-web:
build: .
container_name: docket-web
depends_on:
docket-engine:
condition: service_healthy
env_file: .env
environment:
- ENGINE_URL=http://docket-engine:54323
- ENGINE_WS_URL=ws://docket-engine:54323/ws
volumes:
- ./data:/app/data
- ${DOCKET_STORAGE_MOUNT_RO:-./storage:/storage:ro}
ports:
- "${DOCKET_WEB_PORT:-54322}:54322"
restart: unless-stopped
command: ["uvicorn", "web_service:app", "--host", "0.0.0.0", "--port", "54322"]127.0.0.1 instead of using Docker DNS.Quick start
git clone https://github.com/palaV/Habeas && cd Habeascp .env.example .env Edit .env to set your ports, storage path, timezone, and network profile.
docker compose -f docker-compose.yml up -d Open http://localhost:54322. First visit triggers passkey registration.
Reverse proxy
Passkey authentication (WebAuthn) requires HTTPS with a valid origin. Put Habeas behind a reverse proxy.
habeas.yourdomain.com {
reverse_proxy localhost:54322
}Then set in your .env:
FRONTEND_URL=https://habeas.yourdomain.com
TRUST_PROXY=true
TRUSTED_PROXY_IPS=127.0.0.1,::1
COOKIE_SECURE=trueStorage
The engine writes torrent data to the path configured via DOCKET_STORAGE_MOUNT. The web service mounts the same path read-only for the file browser.
DOCKET_STORAGE_MOUNT ./storage:/storage Engine: read-write mount for downloadsDOCKET_STORAGE_MOUNT_RO ./storage:/storage:ro Web: read-only mount for file browserDOCKET_DEFAULT_DOWNLOAD_PATH /storage/Downloads Default download directory inside the container./data.Persistent data
./data:/app/data both SQLite DB, secrets, libtorrent resume data, settings./logs:/app/logs both Structured log files (rotated, configurable size)/storage engine rw, web ro Torrent downloads and organized mediaConfig generator
Fill in your settings and copy the generated .env. Then grab the matching compose file from the repo.
DOCKET_WEB_PORT=54322
DOCKET_ENGINE_PORT=54323
DOCKET_NETWORK_PROFILE=direct
VPN_COMPOSE_MODE=container
DOCKET_STORAGE_MOUNT=/mnt/media:/storage
DOCKET_STORAGE_MOUNT_RO=/mnt/media:/storage:ro
TZ=America/New_York
PUID=1000
PGID=1000docker compose -f docker-compose.yml up -d All environment variables
The generator covers the basics. Below is the full reference for .env.
Core
DOCKET_ENGINE_PORT 54323 Engine API portDOCKET_WEB_PORT 54322 Web UI portFRONTEND_URL http://localhost:54322 Public URL for CORS, cookies, passkey originDOCKET_NETWORK_PROFILE direct Deployment mode: direct, host, or gluetunVPN_COMPOSE_MODE container How containers reach each other: container or hostTRUST_PROXY false Enable if behind a reverse proxy (Caddy, nginx, Traefik)TRUSTED_PROXY_IPS 127.0.0.1,::1 IPs allowed to set X-Forwarded headersPUID / PGID 1000 User/group ID for file ownership inside containersTZ America/New_York Timezone for logs and schedulingDOCKET_STORAGE_MOUNT ./storage:/storage Host:container path for torrent downloadsCOOKIE_SECURE true Secure cookie flag. Set false for HTTP-only dev.Security
IP_ALLOWLIST_ENABLED false Restrict access to specific IPsIP_ALLOWLIST Comma-separated CIDRs (e.g. 192.168.1.0/24)FAIL2BAN_ENABLED true Auto-block IPs after repeated auth failuresDB_ENCRYPTION_ENABLED false Encrypt SQLite database at restDB_ENCRYPTION_KEY Encryption key if DB encryption is enabledSESSION_SECRET (auto) Override auto-generated session signing keyCORS_ORIGINS Additional allowed CORS originsRP_ID (derived) WebAuthn relying party ID for passkey authqBittorrent API
QBIT_USERNAME Username for the qBittorrent-compatible APIQBIT_PASSWORD Password for the qBittorrent-compatible APIQBIT_SESSION_TTL 86400 Session duration in seconds (default 24h)Tracker automation
DOCKET_AUTO_TRACKER_NORMALIZATION false Normalize tracker URLs on addDOCKET_AUTO_TRACKER_HTTPS_UPGRADE false Upgrade HTTP tracker URLs to HTTPSDOCKET_AUTO_TRACKER_HTTP_FALLBACK false Fall back to HTTP if HTTPS tracker failsDOCKET_ALLOW_INSECURE_TRACKER_TLS false Accept invalid TLS certs from trackersFetch safety
DOCKET_ALLOW_PRIVATE_FETCH false Allow fetching from private/internal IPs (SSRF risk)DOCKET_FETCH_HOST_ALLOWLIST Comma-separated hosts exempt from SSRF checksDOCKET_COOKIE_FORWARD_HOST_ALLOWLIST Hosts that receive forwarded cookies on fetchLogging
LOG_CONSOLE false Echo logs to stdout (useful in Docker)LOG_LEVEL INFO Minimum log level: DEBUG, INFO, WARNING, ERRORLOG_MAX_BYTES 10485760 Max log file size before rotation (10MB)LOG_BACKUP_COUNT 5 Number of rotated log files to keep