Operating an AssemblyAI Hub instance (v3.4.0)
Use this when the user asks you to deploy, configure, upgrade, back up, or troubleshoot their Hub server. Confirm with the user before changing a production server, and never print secrets.
Deploy with Docker Compose
git clone https://github.com/trageeker/assemblyai-hub.git && cd assemblyai-hub
cp .env.example .env
# edit .env: SECRET_KEY (openssl rand -hex 32), ADMIN_PASSWORD, POSTGRES_PASSWORD
# PUBLIC_BASE_URL=https://hub.example.com, WEBHOOK_SECRET (recommended)
# HUB_IMAGE=ghcr.io/trageeker/assemblyai-hub:3.4.0 (pin a version)
docker compose up -d
curl -s http://localhost:18080/healthzConsole: /admin (user ADMIN_USERNAME, default admin). Add AssemblyAI keys under "Upstream accounts", create client keys under "API Key". Or preload with AAI_ACCOUNTS=name:key[:region[:weight[:concurrency]]],... and HUB_API_KEYS=name:hub-....
PaaS: image ghcr.io/trageeker/assemblyai-hub:<version>, set DATABASE_URL (postgres://... accepted, ?sslmode=require OK), SECRET_KEY, ADMIN_PASSWORD, PUBLIC_BASE_URL; health check /healthz; port PORT (default 8000). Run exactly one instance (the poller, subscription refresh and sing-box run in-process).
Key settings
| Variable | Default | Notes |
|---|---|---|
SECRET_KEY | random per boot | Must be set and never changed; encrypts stored keys |
ADMIN_PASSWORD | admin | Change it |
PUBLIC_BASE_URL | empty | Enables AssemblyAI callbacks; otherwise polling only |
WEBHOOK_SECRET | random | Fix it so callbacks survive restarts |
POLL_INTERVAL | 20 | seconds |
MAX_RETRY_ACCOUNTS | 3 | accounts tried per request |
COOLDOWN_SECONDS | 60 | after a 429 |
DEFAULT_MAX_CONCURRENCY | 5 | per new account |
UPSTREAM_TIMEOUT | 300 | seconds |
MAX_UPLOAD_MB | 2048 | console uploads |
DEFAULT_SPEECH_MODELS | universal-3-5-pro,universal-2 | console uploads |
LLM_BASE_URL / LLM_API_KEY / LLM_MODEL | empty | OpenAI-compatible LLM for console AI actions |
ALLOW_OPEN_DOCS | true | /hub/docs |
Full list: https://assemblyai-hub-docs.pages.dev/deploy/configuration
Reverse proxy
Put HTTPS in front. Nginx needs client_max_body_size 2g;, long proxy_read_timeout, and Upgrade/Connection headers for /v3/ws. Caddy: reverse_proxy 127.0.0.1:18080 is enough.
Upgrade, backup, restore
docker compose pull app && docker compose up -d # or change HUB_IMAGE tag
docker compose exec -T db pg_dump -U hub hub | gzip > hub-$(date +%F).sql.gz
gunzip -c hub-YYYY-MM-DD.sql.gz | docker compose exec -T db psql -U hub hub && docker compose restart appSchema changes apply automatically at startup. Read the changelog before a major version bump. Moving servers requires the same SECRET_KEY.
Troubleshooting
| Symptom | Check |
|---|---|
| 503 no upstream account | Console → Upstream accounts: statuses (error / cooling), concurrency limits, region of the key vs accounts |
| Account stuck in "error" | Its key was rejected (401/402/403). Fix the key or billing, then "Reset status" and "Test" |
Transcripts stay processing | Callbacks unreachable: verify PUBLIC_BASE_URL is reachable from the internet; polling still updates every POLL_INTERVAL |
| Client webhook not received | GET /v2/transcript/{id} → webhook_status_code |
| Server cannot reach AssemblyAI | Console → Network proxies: import a node, test, bind it to the accounts |
| Large uploads fail | Reverse proxy body size / platform limit, MAX_UPLOAD_MB |
| Which version is running | curl /healthz |
| Logs | docker compose logs -f app (failover lines look like account N got 429) |