Skip to content

Configuration ​

The environment variables of a self-hosted JoobQUI server. The descriptions are the comments of selfhosted.env.example, the file of the deployment bundle to copy when you deploy. A variable written without # there is one you are expected to set; the others show their default or an example.

Secrets can also be given as files: DATABASE_URL, SESSION_SECRET, REDIS_URL and JOOBQUI_SDK_TOKEN each accept NAME_FILE=/run/secrets/name (setting both forms stops the start).

Setup wizard and the data volume ​

VariableIn the example fileWhat it does
JOOBQUI_DATA_DIR/dataNothing below is required any more: started with neither DATABASE_URL nor a saved setup, the server prints a one-time setup code in its log and serves a setup page instead. The admin enters the code, the public address, Redis and PostgreSQL; the server saves them (with secrets it generates: SESSION_SECRET, JOOBQUI_SECRETS_KEY, JOOBQUI_PAYLOAD_KEYS) encrypted in this directory and restarts. A variable set here always wins over what was saved.
JOOBQUI_BOOTSTRAP_KEY(empty)The key of the saved file (32 bytes, base64: openssl rand -base64 32). Unset, a key is generated into the same directory, which protects copies of the file but not the volume itself.
JOOBQUI_SETUPonThe wizard starts when the server has no licence yet, or when nothing says where PostgreSQL or Redis is (no saved settings, no DATABASE_URL, REDIS_URL or REDIS_HOST); it asks only for what is missing. off skips it. Run the wizard on one instance; other instances sharing the volume restart into the saved settings. There is no licence key to set. The wizard's "Sign in with JoobQ" shows a short code (also printed in the log); an admin of your organization approves it at app.joobq.io/ui/connect, and the server fetches its licence, saves it here with its own installation key (which signs its check-ins), and checks in every 15 minutes (a portal it cannot reach does not end a paid period for up to 7 days after the last successful check-in). Only the server needs to reach the portal: the browser never has to reach the server for this. Without a browser: bin/joobqui-selfhosted connect --url https://... A server without a licence opens the setup page again only to connect; with JOOBQUI_SETUP=off it refuses to start.
JOOBQUI_ENROLLMENT_TOKEN
JOOBQUI_ENROLLMENT_TOKEN_FILE
(empty)
/run/secrets/joobqui_enrollment_token
Unattended installs: an enrollment token made on the portal's licensing page (Enrollment tokens). A web process started with it and no saved licence connects itself before anything else, saves the licence and its generated secrets here, and starts; with DATABASE_URL and REDIS_* set too there is no wizard at all. It is a secret: it works once by default (at most 10 times), for 24 hours by default (at most 7 days), only for your organization (and, if you said so, one address), and it is removed from the process's environment once tried. Set JOOBQUI_PUBLIC_URL with it. A token that does not work stops the server with one line (JOOBQUI_SETUP=off) or opens the setup page saying why. Prefer the _FILE form (a Docker secret); remove the token from your deployment once the server is connected. Replicas must share this data volume: they then connect once. A token made for any address only connects new servers; replacing the credentials of a running one needs a token made for its address. bin/joobqui-selfhosted disconnect --yes disconnects a server.

Required (unless the setup wizard saved them) ​

VariableIn the example fileWhat it does
SESSION_SECRET(empty) (set it)Signs and encrypts the session cookies. In production (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.
DATABASE_URL(empty) (set it)PostgreSQL: accounts, API tokens, the audit log, notification channels. The database must exist; tables and migrations (recorded in cql_schema_migrations) are applied when bin/joobqui-selfhosted starts, also for the command-line tasks.
JOOBQUI_DB_POOL_SIZE20The pool is bounded: max_pool_size=20, max_idle_pool_size=10 (or the pool size if smaller), initial_pool_size=0 (connect on first use) and checkout_timeout=5 (seconds) are added to the URL unless its query string already sets them (a value in the URL wins). Maximum connections per instance (2 to 500; default 20). Keep instances x this under the server's max_connections.
JOOBQUI_DB_IDLE_POOL_SIZE10Idle connections kept (1 to 500; default 10, or the pool size when that is smaller).
JOOBQUI_DB_CHECKOUT_TIMEOUT5.0Seconds to wait for a free connection (0.1 to 300; default 5).
JOOBQUI_BOOT_WAIT_SECONDS60How long start-up retries the migrations and the event stream while PostgreSQL or Redis does not answer (0 to 3600 seconds; default 60; pauses grow from 1 to 8 seconds). Then it prints one line naming what failed and exits with status 1.

Server (Azu) and environment ​

VariableIn the example fileWhat it does
HOST
PORT
127.0.0.1
8080
The defaults are HOST=0.0.0.0 and PORT=4000. Use HOST=127.0.0.1 for local only.
CRYSTAL_ENVdevelopment (set it)production loads config/joobq.production.yml (JoobQ's only config file; any other value starts JoobQ with its defaults), adds HSTS, turns on the SESSION_SECRET rules and the start-up checks (JOOBQUI_CLIENT_IP_HEADER, mail), and makes the second factor need JOOBQUI_SECRETS_KEY. Set it on every real deployment: the release image already does.
CRYSTAL_WORKERS4 (set it)Worker threads of the Crystal runtime.
LOG_LEVELINFO (set it)Read through Crystal's Log.setup_from_env, which JoobQ calls.
JOOBQ_CONFIG_FILE(empty)Names another JoobQ YAML file instead of config/joobq.<env>.yml (read by JoobQ itself).

Redis (JoobQ's data, the live stream, session revocations, throttles, leases, schedule state) ​

VariableIn the example fileWhat it does
REDIS_HOST
REDIS_PORT
REDIS_PASS
localhost (set it)
6379 (set it)
(empty) (set it)
JoobQ's own store reads REDIS_HOST, REDIS_PORT and REDIS_PASS (they override config/joobq.production.yml, which has no password). The rest of this block is read by JoobQUI: when REDIS_URL, REDIS_USER, REDIS_TLS/rediss:// or a unix socket is given, joobqui installs its own store so that queues, the API and the live stream all use it. Not supported: Sentinel, Cluster, and checking that the server's name matches its certificate (the chain is checked).
REDIS_URL(empty)redis://[user:password@]host[:port][/db], rediss:// for TLS, unix:///path/to.sock[?db=N]. REDIS_HOST/PORT/USER/PASS override the parts of the URL. Percent-encode special characters of a password inside the URL (REDIS_PASS takes it as it is). Any REDIS_URL is applied to JoobQ's own store as well (even one that names only a host, port and password), and JoobQ's delayed-job scheduler is rebuilt on it.
REDIS_USER(empty)ACL user (Redis 6+).
REDIS_TLSfalsetrue to connect over TLS (also implied by rediss://). true/1/yes/on or false/0/no/off; anything else stops the start.
REDIS_TLS_VERIFYtrueCheck the server certificate's chain (default true). Turning it off is logged as "tls, NOT verified".
REDIS_CA_FILE(empty)PEM file with the authorities to trust instead of the system's. Needs TLS on.
REDIS_POOL_SIZE
REDIS_POOL_TIMEOUT
500 (set it)
2.0 (set it)
Pool size and timeout of JoobQ's connections. Unless these are set, the YAML's values apply (200 and 2.0 in config/joobq.production.yml, loaded when CRYSTAL_ENV=production), also when joobqui installs its own store for the extended options below; without the file JoobQ's defaults are 500 and 2.0.

Accounts, sign-up, sign-in ​

VariableIn the example fileWhat it does
JOOBQUI_SIGNUPclosed (set it)Who may sign up through the API: open, invite (needs a one-use invite code) or closed. Anything else reads as closed. With open, anyone who can reach the server can register any email address, and a new account is a viewer (read only). Closed is the default: make the first account from the command line, with the same environment as the server: bin/joobqui accounts:create EMAIL USERNAME [--role viewer|operator|admin] (the first account is an admin by default) bin/joobqui invites:create [DAYS] [--role ROLE] (prints a one-use invite code)
JOOBQUI_ACCOUNT_PASSWORD(empty)Password for accounts:create (it asks twice, without echo, when this is unset).
JOOBQUI_SESSION_TTL_MINUTES60How long a session lasts, counted from sign-in: 5 to 1440 minutes (a value outside is clamped; not a number: 60). There is no idle timeout (JOOBQUI_SESSION_IDLE is ignored with a warning).
JOOBQUI_CLIENT_IP_HEADERX-Real-IPBehind a reverse proxy every request comes from the proxy, so the sign-in, sign-up and recovery limits would share one client. Name the header your proxy sets to the caller's address (for example X-Real-IP); only do so if clients cannot forge it. Production start-up warns when it is unset.
JOOBQUI_PUBLIC_URL(empty)The address people reach the console at, https://queues.example.com (no path). Links in password-reset and confirmation mails, and the single sign-on redirect URI, are built from it.
JOOBQUI_REQUIRE_EMAIL_VERIFICATIONfalsetrue: an account made by open sign-up (not by invite) stays inactive until the mailed link is followed. Needs SMTP_HOST, SMTP_USERNAME and JOOBQUI_PUBLIC_URL; production refuses to start with it on and any of the three unset.
SMTP_HOST
SMTP_PORT
SMTP_USERNAME
SMTP_PASSWORD
SMTP_FROM
SMTP_FROM_NAME
(empty) (set it)
587 (set it)
(empty) (set it)
(empty) (set it)
noreply@joobq.io
JoobQ
Mail (password reset, email confirmation, email alert channels, EmailJob). Mail is "configured" (for the sender and the start-up checks) only when SMTP_HOST is set to something other than smtp.example.com AND SMTP_USERNAME is not empty. STARTTLS on the submission port is the only mode.

Roles, tokens ​

VariableIn the example fileWhat it does
JOOBQUI_API_TOKENS(empty) (set it)Comma-separated SHA-256 hashes of bearer tokens for scripts: echo -n "$TOKEN" | shasum -a 256 | cut -d" " -f1 Add ":viewer", ":operator" or ":admin" to a hash to give it a role: HASH:viewer. No role = operator; an unknown word = viewer. A Prometheus scrape token wants HASH:viewer. Tokens an admin creates in the console (Access page) are kept in the database.
JOOBQUI_ALLOW_ENV_TOKEN_ADMINfalsetrue lets an admin token from JOOBQUI_API_TOKENS create tokens and change or erase users (they belong to no account, so what they create cannot be revoked with one). Off by default; exactly "true" turns it on. A risk: leave it off unless you need it.
JOOBQUI_SDK_TOKEN(empty) (set it)Bearer token of the SDK gateway (/api/v1/sdk/*): every SDK worker and producer sends it (Authorization: Bearer ...). Unset, the gateway answers 503 sdk_token_not_configured; a wrong one gets 401. A long random value: openssl rand -hex 32. Also read from JOOBQUI_SDK_TOKEN_FILE (a Docker secret). Rotating it means restarting the workers with the new one.
JOOBQUI_UI_DIRpublic/ui (set it)Where the built console is served from (under /ui/).
JOOBQUI_STREAM_PING_SECONDS25 (set it)How often (seconds, 1 to 3600) the live stream checks that a connection's session is still valid.

Secrets at rest ​

VariableIn the example fileWhat it does
JOOBQUI_SECRETS_KEY(empty)Seals notification-channel URLs and keys and two-factor secrets (AES-256-GCM). Set it to its own long random value (openssl rand -hex 32). Without it the key is SESSION_SECRET (a warning is logged), and rotating SESSION_SECRET then makes those secrets unreadable; in production the second factor cannot be turned on without it. Changing it later makes the stored secrets unreadable.
JOOBQUI_PAYLOAD_KEYS(empty)Field-level encryption of job arguments, for job classes that declare encrypted_property (JoobQ's own feature). id:key entries separated by commas, the first seals, all open; a key is 64 hex digits or base64 of 32 bytes: id:$(openssl rand -base64 32). Set it on every process that enqueues or runs such a job. A worker whose queues include such a job class refuses to start without a key, and any process refuses a malformed one.
JOOBQUI_PAYLOAD_KEY(empty)The same format, kept from earlier versions; JOOBQUI_PAYLOAD_KEYS wins when both are set. With neither, JoobQ reads its own JOOBQ_PAYLOAD_KEYS / JOOBQ_PAYLOAD_KEY.
JOOBQUI_ALLOW_PLAINTEXT_PAYLOADSfalseLet a worker run an encrypted-class job that is stored in plain text? Default off (such a job is dead-lettered), because anyone who can write to Redis could otherwise run an unsealed job. Turn on only while draining jobs written before encryption.

Two-factor authentication and single sign-on (OpenID Connect) ​

VariableIn the example fileWhat it does
JOOBQUI_MFA_REQUIRED_ROLESadminRoles that must have a second factor (viewer, operator, admin; comma-separated). Their accounts enrol at the next sign-in and can do nothing else until they have. A word that is not a role stops the start.
JOOBQUI_MFA_SSO_EXEMPTfalsetrue: a single sign-on session does not have to enrol a local factor (the provider must enforce its own). Default false.
JOOBQUI_OIDC_ISSUER
JOOBQUI_OIDC_CLIENT_ID
JOOBQUI_OIDC_CLIENT_SECRET
https://idp.example.com
(empty)
(empty)
Setting the issuer turns single sign-on on; then the client id, secret and JOOBQUI_PUBLIC_URL are required, or the start stops. The redirect URI to register at the provider is JOOBQUI_PUBLIC_URL + /api/v1/auth/oidc/callback.
JOOBQUI_OIDC_NAME(empty)Label of the sign-in button: "Sign in with <name>" (40 characters; default "Single sign-on").
JOOBQUI_OIDC_SCOPESopenid email profileScopes asked for; must include openid. Default "openid email profile".
JOOBQUI_OIDC_GROUPS_CLAIMgroupsThe ID-token claim that lists the person's groups (a list, or one string). Default "groups".
JOOBQUI_OIDC_ROLE_MAPadmins=admin,ops=operator,*=viewergroup=role pairs, highest role wins; *=role is everyone else. With no match and no *, the person is refused. Empty: every sign-in is refused (a warning is logged). The role is re-read at each sign-in and changes the account's role, unless an admin set that role by hand (it is then locked) or the ID token carries no groups claim at all.
JOOBQUI_OIDC_ALLOWED_DOMAINS(empty)Only these email domains may sign in (comma-separated; empty: any).
JOOBQUI_OIDC_AUTO_CREATEtrueMake an account on first sign-in (default true). With false, only accounts that already exist (linked) can sign in.
JOOBQUI_OIDC_LINK_BY_EMAILfalseLink a first-time sign-in to an existing account with the same (provider-verified) email, if the account's own address was confirmed. The link replaces the account's password, drops its second factor and revokes its tokens and sessions. Default false: whoever controls that address at the provider could otherwise take over the account.
JOOBQUI_OIDC_ONLYfalsetrue: passwords work for admins only (the way back in if the provider is down); everyone else signs in through the provider.
JOOBQUI_OIDC_ALLOW_PRIVATE_HOSTSfalseDevelopment only: allow a plain-http provider or console URL and a provider on the internal network. Logged as an error in production.

Alerts, retention ​

VariableIn the example fileWhat it does
JOOBQUI_ALERT_NOTIFICATIONSonoff (also false, 0, no, disabled) stops this instance from sending alert notifications. Rules are still evaluated.
JOOBQUI_ALLOW_PRIVATE_WEBHOOKSfalsetrue lets webhook channels use http and addresses inside the network (development only). Exactly "true". Single sign-on has its own switch, JOOBQUI_OIDC_ALLOW_PRIVATE_HOSTS.
JOOBQUI_AUDIT_RETENTION_DAYS365Days to keep audit events (a whole number from 1; anything else is logged and 365 is used). Purged at start and then daily.
JOOBQUI_DLQ_RETENTION_DAYS(empty)Days to keep dead letters (1 to 36500). Unset or 0 keeps them for ever; anything else is logged and they are kept.
JOOBQUI_RETENTION_BATCH
JOOBQUI_RETENTION_INTERVAL_MINUTES
500
60
Dead letters removed per step (1 to 5000) and minutes between passes (1 to 1440).
JOOBQUI_WORKFLOW_RETENTION_DAYS(empty)Days to keep finished workflows (1 to 36500). Unset or 0 keeps them for ever; anything else is logged and nothing is deleted. Deleted runs, their history and search indexes cannot be restored. Open runs are never deleted.
JOOBQUI_WORKFLOW_ARCHIVE_DIR(empty)Archive: a directory (a persistent volume; created 0700 if missing, the start stops if it cannot be written). With it, retention writes each finished run to a gzip file here BEFORE deleting it, and a run that cannot be archived stays in Redis. Unset: no archive.
JOOBQUI_WORKFLOW_ARCHIVE_MAX_RUNS
JOOBQUI_WORKFLOW_ARCHIVE_MAX_BYTES
50000
16777216
Oldest archived runs are dropped beyond this many (1 to 200000), and a run whose JSON is bigger than this many bytes (65536 to 67108864) is not archived and stays in Redis (it is reported in GET /workflow-retention).
JOOBQUI_WORKFLOW_ARCHIVE_REDACTtruetrue (the default): archived histories have secret-looking keys and error texts masked and the stored state keeps no payloads; such an archive cannot be replayed. false: payloads are archived as they were (the API still masks what it returns).
JOOBQ_PRO_BUILD_ID(empty)The build a joobq-pro worker carries (read by the worker, not by the web process): runs are pinned to a build when they start.
JOOBQUI_WORKFLOW_SCHEDULERfalsetrue: this web process also fires workflow schedules (the engine's scheduler; safe next to workers, one process leads). Without it schedules fire only in a joobq-pro Worker. true, 1, yes or on turn it on.
JOOBQUI_WORKFLOW_ATTRIBUTEScustomer:keyword,total:intWorkflow search attributes to register at start: name:type,name:type (types keyword, int, float, bool, time).

Libraries ​

VariableIn the example fileWhat it does
JOOBQ_PRO_LICENSE(empty)A JoobQ Pro key set by hand (JOOBQ_PRO_LICENSE_FILE names a file instead). Usually leave it unset: a licensed deployment gets its paid Pro key with the licence check-in, and --worker processes read that key from Redis (every 15 minutes) when they run with the same saved settings (the same JOOBQUI_DATA_DIR volume) as the web process. A key set here is used only if it was issued to this licence (in practice the 14-day trial key of the same organization); any other key is ignored with a log line. There are no developer keys.
JOOBQ_ENVtestSpecs only: they flush Redis, so the ones that touch Redis stay pending unless this is "test". Point REDIS_* and DATABASE_URL at throwaway ones. (JoobQ also reads it as an environment name.)

Licence ​

VariableIn the example fileWhat it does
JOOBQUI_DEPLOYMENT_NAMEProductionThe name the server proposes for itself when it connects (shown in the portal's list of servers).
JOOBQUI_PORTAL_URLhttps://app.joobq.ioDevelopment and CI builds only (a release build ignores it): the portal the server connects to and checks in with.

Also read ​

These are read by the server but not listed in the example file.

VariableDefaultWhat it does
JOOBQUI_API_TOKENnoneOne bearer token in plain text. Its SHA-256 is added to JOOBQUI_API_TOKENS with the role of JOOBQUI_API_TOKEN_ROLE. Prefer JOOBQUI_API_TOKENS, which holds only hashes.
JOOBQUI_API_TOKEN_ROLEadminThe role of JOOBQUI_API_TOKEN (default admin).
JOOBQ_CONFIG_PATHnoneRead by the schedule catalog when JOOBQ_CONFIG_FILE is unset: the YAML file whose schedulers: and sdk_schedules: entries are listed (default config/joobq.production.yml).
JOOBQUI_SDK_TOKEN_FILEnoneA file holding JOOBQUI_SDK_TOKEN (a Docker secret). The other *_FILE forms are listed in the example file.

JoobQ Core is MIT licensed. JoobQ Pro needs a licence key.