Self-hosted server
A self-hosted JoobQUI is one binary, joobqui-selfhosted (./joobqui inside the image), with PostgreSQL and Redis beside it. The Quickstart runs it with Docker Compose; every variable is in Configuration.


The Compose deployment
The deployment bundle's selfhosted.compose.yml, the file the Quickstart runs:
The services of the Compose file. Without the redis profile, point REDIS_URL at your own Redis; without https, put your own proxy in front of the app ports.
First start: the setup page
With nothing configured, the server needs only a volume for its settings:
docker run -d -p 4000:4000 -v joobqui-data:/data ghcr.io/azutoolkit/joobqui-selfhosted:latest- It prints a one-time setup code in its log ("JoobQ is not set up yet ...") and serves a setup page. The code changes on every restart until setup is finished.
- Open the server at its HTTPS address and enter the code. The setup page itself is plain HTTP: put a TLS proxy in front, or open it only from a trusted network.
- Enter the public address (
https://...) and choose Sign in with JoobQ: the page shows a short code. An admin of an organization with a paid self-hosted licence approves it at app.joobq.io (Open JoobQ). The server fetches its licence itself; no key is copied or pasted. Only approve a code your own server shows you. - Enter Redis and PostgreSQL (Test checks them), then Save and start. The server saves everything encrypted in
/data/joobqui.conf(with its keyjoobqui.keybeside it, orJOOBQUI_BOOTSTRAP_KEY), generatesSESSION_SECRET,JOOBQUI_SECRETS_KEYandJOOBQUI_PAYLOAD_KEYSitself, and restarts into the console.
Environment variables still work and always win over saved values. A server configured entirely by its environment (as the Compose deployment is) still opens the setup page once, only to connect; with JOOBQUI_ENROLLMENT_TOKEN it connects itself and shows no setup page at all (see Licence and Pro key). JOOBQUI_SETUP=off skips the setup page; a server without a licence then refuses to start and says how to connect it.
What it needs
The setup page saves the connections and generates the secrets. To manage them yourself, set them in the environment (the Compose deployment does):
| Setting | Why |
|---|---|
DATABASE_URL | PostgreSQL: accounts, API tokens, the audit log, notification channels. The database must exist; tables and migrations are applied at start (and by every command-line task). |
SESSION_SECRET | Signs and encrypts the session cookies. With CRYSTAL_ENV=production the server refuses to start unless it is at least 32 characters and not one character repeated (openssl rand -hex 32). Changing it signs everybody out. |
REDIS_URL (or REDIS_HOST, REDIS_PORT, REDIS_PASS) | JoobQ's data, the live stream, session revocations, throttles, leases, schedule state. Redis 6.2 or newer; no Sentinel or Cluster. Over TLS (rediss://) the certificate chain is checked, not the server name. |
A volume at /data (JOOBQUI_DATA_DIR) | The settings the setup page saves, encrypted: the licence from Sign in with JoobQ and the secrets the server generates. Back it up with the database. See Licence and Pro key. |
JOOBQUI_SDK_TOKEN (or _FILE) | The bearer token every SDK worker and producer sends. Without it the gateway answers 503 sdk_token_not_configured. In production a token shorter than 32 characters stops the start. |
CRYSTAL_ENV=production | Loads config/joobq.production.yml, adds HSTS and turns on the start-up checks. Set it on every real deployment. |
Every other variable is in Configuration. Secrets can be files: NAME_FILE=/run/secrets/name works for DATABASE_URL, SESSION_SECRET, REDIS_URL and JOOBQUI_SDK_TOKEN.
Start, check, stop
./joobqui migrate # apply the migrations and exit (the server also does it at start)
./joobqui # run the server
./joobqui doctor # check the database, Redis, the session secret and the licence
./joobqui license:status # the licence: eligible, status, tier, seats, paid_untilStart-up retries the migrations and the event stream for JOOBQUI_BOOT_WAIT_SECONDS (60 by default) while PostgreSQL or Redis does not answer; then it prints one line naming what failed and exits with status 1. On SIGINT or SIGTERM the server stops its background work and the workflow engine before JoobQ, gives its leader leases back so another instance takes over at once, and exits with status 3 when a step failed or ran out of time.
First admin and users
Sign-up is closed by default (JOOBQUI_SIGNUP=closed). Make the first account from the command line, with the same environment as the server; the first account is an admin:
./joobqui accounts:create admin@example.com admin # password from JOOBQUI_ACCOUNT_PASSWORD, or asked twice
./joobqui invites:create 7 --role operator # a one-use sign-up invite codeSee Accounts, SSO, 2FA, roles and Command line.
Health
GET /joobq/health/check (and HEAD) is public and is what a load balancer should check; every other path under /joobq answers 404. GET /api/v1/capabilities (public) says what this server can do, including features.pro.