Skip to content

Environment Variables

$DEVENV_STATE refers to <project root>/.devenv/state — this is where devenv stores runtime data.

All settings can be overridden in .env. Defaults (where appropriate) are provided in devenv.nix at low priority so .env values take precedence.

file: prefix: Any env var can be prefixed with file: to read the value from a file at runtime (e.g. KLANGK_JWT_SECRET=file:/run/secrets/jwt). The file contents are stripped of leading/trailing whitespace. This works with secret management tools like agenix/sops that write decrypted secrets to files. If the file cannot be read, an error is logged and the value is treated as unset.

cmd: prefix: Any env var can be prefixed with cmd: to resolve the value by running a shell command at runtime and using its stdout (e.g. KLANGK_JWT_SECRET=cmd:aws secretsmanager get-secret-value --secret-id klangk/jwt | jq -r .SecretString). The stdout is stripped of leading/trailing whitespace. This lets values be fetched from external sources (vault CLIs, cloud secret managers, decryption tools) without materializing them to disk or a plain env var. The command runs via the shell (so pipes work) with a short timeout; only values an operator explicitly prefixes with cmd: are ever executed. If the command fails (non-zero exit, timeout, or execution error), an error is logged and the value is treated as unset.

Note: the prefixes are applied only where the backend reads a var through resolve_env_value/resolve_file_value (the vast majority of KLANGK_* vars). A couple of values are consumed out-of-band by nginx.sh via bash expansion (KLANGK_LLM_BASE_URL, KLANGK_LLM_API_KEY) — these are run through the klangk-resolve-value console script (see below) at nginx config generation time, so the prefixes work there too. A small number of vars are read raw by design (e.g. KLANGK_TRUSTED_PROXY_CIDRS, which is a public CIDR list, not a secret).

klangk-resolve-value console script: a CLI twin of resolve_file_value (registered as klangk-resolve-value = "klangk_backend._resolve_value:main" in src/backend/pyproject.toml) that resolves a single prefixed value from its single argument and prints the result to stdout (file: → file contents; cmd: → command stdout; plain → verbatim; failure → empty + reason on stderr). It is the single source of truth consumed by nginx.sh; operators rarely need to call it directly, but it is available on the PATH wherever the backend is installed:

klangk-resolve-value 'file:/run/secrets/jwt'
klangk-resolve-value 'cmd:aws secretsmanager ... | jq -r .SecretString'
klangk-resolve-value 'plain-value'   # -> plain-value (verbatim)
Variable Default Description
KLANGK_NGINX_PORT 8995 Primary access point — nginx reverse proxy port (UI, API, WebSocket, hosted apps)
KLANGK_PORT 8997 Backend (FastAPI/uvicorn) port — proxied through nginx, not accessed directly
KLANGK_DATA_DIR $DEVENV_STATE/klangk/data Database, workspaces, Pi sessions
KLANGK_CUSTOMIZE_DIR ~/.klangk/custom Root directory for deployment customization files. Subsystems look for well-known subdirectories (certs/, branding/, email-templates/) here when their per-feature env var is unset. Missing subdirectories are silently skipped. One mount point replaces three. See Customizing a Deployment.
KLANGK_PLUGINS_DIR $DEVENV_STATE/klangk/plugins Fetched plugins (outside repo for execIfModified)
KLANGK_HOST_IMAGE klangk-host Docker image name for run-host-container
KLANGK_VARIANT Identifies a custom build (a variant) of klangk, independent of the upstream klangk version. Baked into version.json as variant by scripts/generate-version.sh at build time; surfaced at GET /api/v1/version and the debug pane's Variant row. Empty/absent = stock klangk (no variant reported, output byte-identical to a non-customized build). See Customizing a Deployment.
KLANGK_IMAGE_NAME klangk-workspace Podman image name for workspace containers
KLANGK_IMAGE_PULL_POLICY never Podman --pull policy for workspace containers (never, missing, always, newer). Default never requires the image to exist locally; missing pulls from a registry if not found
KLANGK_USERNS keep-id:uid=1000,gid=1000 Podman --userns mode for workspace containers. Maps the host user to uid/gid 1000 inside the container so bind-mounted files are owned correctly.
KLANGK_PODMAN_BIN podman Path to the podman binary
KLANGK_PORT_RANGE_START 9000 First host port for workspace app allocations. Each workspace gets 5 ports starting from this value. See Hosted Apps.
KLANGK_HOSTED_PORTS_PER_WORKSPACE 5 Server-wide ceiling on hosted-app ports per workspace. Set to 0 to disable hosted-app serving entirely — no ports are allocated, no hosting env is injected into containers, and /hosted/... returns 404. Any other value clamps each workspace down to this cap. See Hosted Apps.
KLANGK_ALLOWED_MOUNT_ROOTS Comma-separated list of allowed host path prefixes for bind mounts (e.g., /home,/data). If unset, all bind mount paths are allowed. Protected paths are always blocked.
KLANGK_DNS_SERVERS Comma-separated DNS server IPs for containers (e.g., 100.100.100.100,8.8.8.8 for Tailscale MagicDNS). If unset, containers use podman's default DNS.
KLANGK_HOSTING_HOSTNAME (auto-derived) URL authority (host[:port]) for hosted-app and user-facing URLs — the port lives here, it is never synthesized from KLANGK_NGINX_PORT (that is internal container wiring, not the public port). Auto-derived from X-Forwarded-Host or the Host header (used verbatim, including their port); set explicitly in production. Behind a real reverse proxy this must carry the public host and port.
KLANGK_HOSTING_PROTO (auto-derived) Protocol for user-facing app URLs. Auto-derived from X-Forwarded-Proto or defaults to http.
KLANGK_HOSTING_BASE_PATH (auto-derived) Base path prefix for user-facing app URLs (e.g., /klangk). Auto-derived from X-Forwarded-Prefix.
KLANGK_TRUSTED_PROXY_CIDRS 127.0.0.1,::1 Comma-separated CIDRs/IPs whose connections are trusted to supply X-Forwarded-Host/Proto/Prefix headers. klangk's nginx proxies from loopback, so the default works out of the box; requests from peers outside this set have forwarded headers ignored (preventing host poisoning if the backend port is exposed).
KLANGK_REJECT_PROXY_HEADERS Set to 1 to ignore X-Forwarded-Host/Proto/Prefix headers unconditionally (hard override; back-compat with the old opt-out).
KLANGK_IDLE_TIMEOUT_SECONDS 1800 Container idle timeout in seconds (check interval auto-computed as timeout/3, clamped 10-60s)
KLANGK_LOGIN_LOCKOUT_WINDOW 300 Time window in seconds for counting failed login attempts.
KLANGK_LOGIN_LOCKOUT_FAILURES 5 Number of failed login attempts before a lockout. Default 5 (enabled). Set to 0 to disable.
KLANGK_LOGIN_LOCKOUT_DURATION 900 Duration of lockout in seconds (only relevant when KLANGK_LOGIN_LOCKOUT_FAILURES > 0).
KLANGK_LLM_API_KEY LLM provider API key
KLANGK_LLM_BASE_URL LLM API URL — must use IP or public FQDN, not bare hostnames (see Tailscale note)
KLANGK_LLM_MODEL LLM model name
KLANGK_AGENT_EMAIL clanker@example.com Email for the chat AI agent. Used for seeding — the agent user is created or updated in the DB on each startup.
KLANGK_AGENT_HANDLE clanker @mention handle for the chat AI agent. Used for seeding — the agent user is created or updated in the DB on each startup.
KLANGK_AGENT_DISABLED Set to 1/true/yes to disable the chat agent: the pi --mode rpc subprocess is not started, so the agent never comes online. Checked each time the subprocess would start. See Chat.
KLANGK_JWT_SECRET JWT signing secret. A warning is logged at startup if unset or left as the insecure dev default.
KLANGK_PREVENT_INSECURE_JWT_SECRET Set to 1 to fail at startup if KLANGK_JWT_SECRET is unset or insecure. Recommended for production.
KLANGK_ACCESS_TOKEN_HOURS 24 Lifetime in hours for user session JWTs. Tokens are automatically refreshed before expiry.
KLANGK_WORKSPACE_TOKEN_HOURS 24 Lifetime in hours for per-workspace JWTs. Tokens are automatically renewed at 80% of their lifetime.
KLANGK_DEFAULT_USER Auto-seeded admin email on startup
KLANGK_DEFAULT_PASSWORD Auto-seeded password on startup (omit to generate random; supports file:/cmd: prefix)
KLANGK_MIN_PASSWORD_LENGTH 8 Minimum password length
KLANGK_FILE_UPLOAD_SIZE_MAX 524288000 Maximum upload size in bytes for file uploads and workspace imports (default 500 MB)
KLANGK_WS_MSG_SIZE_MAX 16777216 Maximum WebSocket message size in bytes (default 16 MB). Increase if syncing very large files via rsync over WebSocket.
KLANGK_CORS_ORIGINS Comma-separated list of allowed CORS origins (e.g., https://klangk.example.com). If unset, derived from KLANGK_HOSTING_HOSTNAME/KLANGK_HOSTING_PROTO, or defaults to http://localhost:{KLANGK_NGINX_PORT}. Set to * to allow all origins (not recommended for public deployments).
KLANGK_TRUST_OUTER_PROXY Set to 1 (or true/yes) to pass through X-Forwarded-* headers from a trusted outer reverse proxy in front of klangk's nginx. By default klangk's nginx overwrites these with authoritative values ($http_host, $scheme) to prevent host poisoning. Only enable if the outer proxy itself overwrites, not passes through, these headers.
KLANGK_GITHUB_OAUTH_CLIENT_ID GitHub OAuth App client ID for device-flow authentication. Injected into workspace containers by the git-credential plugin. When set, git push to github.com triggers the OAuth device flow automatically. No client secret needed. See GitHub Authentication.
KLANGK_DISABLE_REGISTRATION Set to any non-empty value to block new user signups and hide the registration link in the UI
KLANGK_DISABLE_INVITES Set to 1 to disable the invitation system
KLANGK_INVITE_EXPIRE_HOURS 72 How long invitation links remain valid (hours)
KLANGK_ALLOW_AUTOSTART Set to 1/true/yes to allow workspaces to be configured for auto-start on server boot. Default: disabled — the auto-start option is hidden in the UI, CLI, and API. See Auto-start.
KLANGK_ALLOW_SUDO Set to 1/true/yes to grant passwordless sudo inside workspace containers. Default: disabled — an explicit deny rule (!ALL) is written so sudo is blocked even if a password is set on the klangk user. Configured at container start via podman exec --user root.
KLANGK_DISABLE_TMUX Set to 1/true/yes to drop new terminals straight into a plain login shell instead of tmux. Only affects the default per-user terminal; shared/joined terminals always use tmux.
KLANGK_OIDC_CONFIG Path to OIDC provider config file (YAML or JSON). Enables OIDC authentication when set. See OIDC Configuration.
KLANGK_OIDC_LOGIN_HOOK File path to a Python login hook script (e.g., /etc/klangk/login_hook.py). Optionally append :func_name (defaults to on_login). Called on each OIDC login to enforce custom policies. See OIDC Configuration.
KLANGK_AUTH_MODES both (if OIDC configured) Auth modes: password, oidc, or both. Defaults to password when no OIDC config.
KLANGK_SMTP_HOST SMTP server hostname (if set, uses SMTP; otherwise uses sendmail)
KLANGK_SMTP_PORT 587 SMTP server port
KLANGK_SMTP_USER SMTP auth username
KLANGK_SMTP_PASSWORD SMTP auth password
KLANGK_SMTP_FROM Email sender address (falls back to SMTP_USER, then noreply@localhost)
KLANGK_SMTP_USE_TLS true Use STARTTLS for SMTP
KLANGK_SENDMAIL_PATH sendmail Path to sendmail binary (used when KLANGK_SMTP_HOST is not set)
KLANGK_SSL_CERT_DIR Deprecated — use <KLANGK_CUSTOMIZE_DIR>/certs/ instead. Directory of .pem/.crt CA certificate files to trust at runtime. When unset, falls back to <KLANGK_CUSTOMIZE_DIR>/certs/. See Custom CA Certificates.
KLANGK_EMAIL_TEMPLATES_DIR Deprecated — use <KLANGK_CUSTOMIZE_DIR>/email-templates/ instead. Directory of Jinja2 email template overrides. When unset, falls back to <KLANGK_CUSTOMIZE_DIR>/email-templates/. See Email Templating.
KLANGK_PRODUCT_NAME Klangk White-label product name shown in the browser tab title, app-bar logo, and outgoing emails. Supports file:/cmd: prefix. See Customizing a Deployment.
KLANGK_LOGIN_BANNER_TITLE Title shown on the consent banner page (e.g., company name). If empty, no title is displayed.
KLANGK_LOGIN_BANNER Consent banner text shown before login. Blocks all access until accepted. Supports file:/cmd: prefix. If empty, no banner is shown.
KLANGK_TERMS_URL Terms of Service link rendered on the login/registration screens and in email footers. Plain value (no file:/cmd: resolution — it is public, shown pre-auth). Empty hides it. See #1177.
KLANGK_PRIVACY_URL Privacy Policy link. Same semantics as KLANGK_TERMS_URL (plain value, hidden when empty).
KLANGK_AUP_URL Acceptable Use Policy link. Same semantics as KLANGK_TERMS_URL.
KLANGK_SUPPORT_URL Support/help link shown as a help icon in the app bar (authenticated) and on the auth screens. Plain value; hidden when empty and no KLANGK_SUPPORT_EMAIL is set.
KLANGK_SUPPORT_EMAIL Support email address; shown as a mailto: when KLANGK_SUPPORT_URL is unset. Plain value; hidden when empty.
KLANGK_TERMINAL_BANNER Text displayed in every terminal session on shell init. Supports file:/cmd: prefix. If empty (default), no banner is shown.
KLANGKC_DEBUG_SSH_AGENT Set to any non-empty value to enable verbose debug logging for SSH agent forwarding on both the backend and CLI side. Useful for diagnosing relay issues.
KLANGK_WS_DEBUG Set to any non-empty value to enable verbose WebSocket message logging on the backend. Useful for diagnosing connection issues.
LOGFIRE_TOKEN Pydantic Logfire write token (opt-in)
LOGFIRE_BASE_URL https://logfire-api.pydantic.dev Logfire API base URL (for self-hosted instances)
LOGFIRE_ENVIRONMENT Logfire environment tag (e.g., production, staging) — filters traces in the dashboard.