# Server configuration

> Every environment variable nodus-server, the node agent and the CLI read.

Source: https://nodus-platform-site.pages.dev/docs/reference/server-configuration/
Build revision: 211ad9f836655b1c3a2668c4693e442471f28614

<!-- Code generated by tools/envgen from internal/platform/config (make gen). DO NOT EDIT. -->

Nodus processes read `NODUS_`-prefixed environment variables, validated at startup: a missing or invalid value stops the process with an error that names the variable. Secrets come from the environment only.

## nodus-server (roles api, controller, gateway, inference)

|Variable|Default|Required|Description|
|-|-|-|-|
|`NODUS_ASSISTANT_DOCS_INDEX_URL`|`https://nodus-compute.ai/docs/index.json`|no|The site’s runtime docs index, which the assistant searches and cites; the api role caches it for 15 minutes. Roles: api.|
|`NODUS_AUTH_ISSUER`|—|no|Expected iss claim of user access tokens (https\://.supabase.co/auth/v1); required outside NODUS_ENV=local, where empty skips the issuer check. Roles: api, gateway.|
|`NODUS_AUTH_JWKS_URL`|—|no|JWKS URL of the Auth signing keys; empty derives \<NODUS_AUTH_URL>/.well-known/jwks.json. Roles: api, gateway.|
|`NODUS_AUTH_URL`|—|no|Supabase Auth base URL (https\://.supabase.co/auth/v1; <http://127.0.0.1:19999> on compose); empty, which only NODUS_ENV=local allows, accepts only API keys and ServiceAccount tokens. Roles: api, gateway.|
|`NODUS_CORS_ORIGINS`|—|no|Comma-separated browser origins allowed to call the API: the console and admin apps (ADR-107). Roles: api, gateway.|
|`NODUS_DATABASE_MAX_CONNS`|`0`|no|Pool size override; 0 uses the role budget of ADR-070 (api 8, controller 12, gateway 6, inference 4).|
|`NODUS_DATABASE_URL`|—|yes|Postgres URL: Supavisor session mode (port 5432) in the cloud, the compose postgres locally.|
|`NODUS_ENV`|`local`|no|Deployment: local (compose, CI, tests), staging or prod.|
|`NODUS_GITHUB_APP`|—|no|GitHub App as JSON: app_id, slug, private_key (PEM), webhook_secret, client_id, client_secret; empty disables GitHub Connections. Roles: api, controller, gateway.|
|`NODUS_HTTP_ADDR`|`:8080`|no|Public HTTP listener: api, gateway client streams, inference and health.|
|`NODUS_INFERENCE_CONSOLE_ORIGINS`|—|no|Comma-separated browser origins allowed to call the data plane with a user token (the console playground). Roles: inference.|
|`NODUS_INFERENCE_REPLICAS`|`1`|no|Fleet size of the inference role; the per-replica rate limits divide by it. Roles: inference.|
|`NODUS_INFERENCE_UPSTREAMS`|—|no|Inference upstreams as JSON: groq_keys (list, at most 8), groq_base_url, wafer_key, wafer_base_url, openrelay_key, openrelay_base_url, openrelay_catalog_url, anthropic_key, anthropic_base_url, jev_key, jev_endpoint, jev_model; every field optional, URLs https; empty serves no upstream unless its dedicated key is configured. Roles: controller, inference.|
|`NODUS_INTERNAL_ADDR`|`:9090`|no|Internal stream-bridge listener. Roles: gateway.|
|`NODUS_KMS_KEY_URI`|—|no|Key-encryption key: aws-kms\://arn:aws:kms:… in the cloud, local://\<base64 32 bytes> locally; empty uses a fixed development key when NODUS_ENV=local.|
|`NODUS_LOCAL_DOCKER_HOST`|—|no|Docker endpoint the local provider creates node containers on, such as unix:///Users/me/.colima/default/docker.sock; empty keeps providers.yaml’s or unix:///var/run/docker.sock. Roles: controller.|
|`NODUS_LOCAL_NODE_BINDS`|—|no|Comma-separated Docker binds of every local node container, such as /path/to/worktree:/src. Roles: controller.|
|`NODUS_LOCAL_NODE_COMMAND`|—|no|Shell command a local node container runs (sh -c); empty keeps providers.yaml’s or the image’s default. Roles: controller.|
|`NODUS_LOCAL_NODE_ENV`|—|no|Comma-separated KEY=value pairs added to every local node container, such as NODUS_GATEWAY_URL=<http://192.168.5.2:8443>. Roles: controller.|
|`NODUS_LOCAL_NODE_IMAGE`|—|no|Image of the local provider’s node containers; empty keeps providers.yaml’s or the compose-built nodus-platform-nodusd. Roles: controller.|
|`NODUS_LOCAL_NODE_NETWORK`|—|no|Docker network the local provider’s node containers join; empty keeps providers.yaml’s or nodus-platform_default. Roles: controller.|
|`NODUS_LOCAL_NODE_OBJSTORE_ENDPOINT`|—|no|Object store endpoint written into local nodes’ storage grants when they reach the store at another address than NODUS_OBJSTORE_ENDPOINT, such as <http://minio:9000> for a host-run server; empty keeps NODUS_OBJSTORE_ENDPOINT. Roles: controller.|
|`NODUS_LOG_LEVEL`|`info`|no|Minimum log level: debug, info, warn or error.|
|`NODUS_METRICS_ADDR`|`:9100`|no|Prometheus metrics listener.|
|`NODUS_NODE_ADDR`|`:8443`|no|Node protocol listener. Roles: gateway.|
|`NODUS_NODUSD_VERSION`|—|no|nodusd release new nodes fetch, such as git-0123456789ab: the server reads nodusd///nodusd.sha256 from the releases bucket and presigns the binary per create. Required outside local. Roles: controller.|
|`NODUS_NOTIFY_CONSOLE_URL`|`http://localhost:5173`|no|Console base URL that links in emails point at. Roles: api, controller.|
|`NODUS_NOTIFY_FROM`|—|no|Sender of every notice as an RFC 5322 address, such as Nodus \<notices\@mail.>; required with NODUS_RESEND_API_KEY. Roles: api, controller.|
|`NODUS_OBJSTORE_ACCESS_KEY_ID`|—|no|Access key id; empty uses the AWS default credential chain.|
|`NODUS_OBJSTORE_BUCKET_PREFIX`|—|yes|Bucket name prefix; buckets are -data, -logs, -ephemeral, -registry and -releases.|
|`NODUS_OBJSTORE_ENDPOINT`|—|no|S3 API endpoint; empty uses AWS S3. R2: https\://.r2.cloudflarestorage.com.|
|`NODUS_OBJSTORE_R2_ACCOUNT_ID`|—|no|Cloudflare account id; set to issue R2 temporary credentials instead of STS.|
|`NODUS_OBJSTORE_R2_API_TOKEN`|—|no|Cloudflare API token allowed to create R2 temporary credentials.|
|`NODUS_OBJSTORE_REGION`|`auto`|no|S3 signing region; R2 uses auto.|
|`NODUS_OBJSTORE_SECRET_ACCESS_KEY`|—|no|Secret access key.|
|`NODUS_OPENRELAY_API_KEY`|—|no|Dedicated OpenRelay inference key. When nonempty, overrides only openrelay_key in NODUS_INFERENCE_UPSTREAMS; empty preserves the composite key and all other upstream settings. Roles: controller, inference.|
|`NODUS_OPS_ACCESS_AUDIENCE`|—|no|Deprecated; accepted for rollout compatibility and unused by admin authentication. Roles: api.|
|`NODUS_OPS_ACCESS_TEAM_DOMAIN`|—|no|Deprecated; accepted for rollout compatibility and unused by admin authentication. Roles: api.|
|`NODUS_OPS_ADDR`|`:8081`|no|Ops API listener. Roles: api.|
|`NODUS_OPS_CONSOLE_ORIGIN`|—|no|Admin console origin (<https://admin>.) allowed to call the ops API from the browser; empty allows no cross-origin caller. Roles: api.|
|`NODUS_OPS_SUPABASE_ISSUER`|—|no|Supabase Auth issuer (https\://.supabase.co/auth/v1) whose verified sessions are checked against the fixed admin email allowlist; empty refuses every ops request. Roles: api.|
|`NODUS_POOLS`|—|no|BYOC pools and cloud accounts as JSON: install_script_url (<https://api>./install/nodusd.sh), node_gateway_url (wss\://nodes., the ADR-123 carrier), api_url and inference_url (workload proxy origins; default to deployed release origins), agent_url (ARCH becomes amd64 or arm64), agent_sha256 ({arch: sha256}), agent_signer_identity (cosign certificate identity regexp), aws_observer_role_arn, aws_template_url, google_client_id, google_client_secret, google_redirect_url, consent_key (32+ characters), console_url. The installer keys replace the one the API otherwise serves from the deployed nodusd release (NODUS_NODUSD_VERSION); without either, EnrollmentTokens are refused, and without a cloud’s keys its onboarding is off. Roles: controller.|
|`NODUS_POSTHOG_READ_API_KEY`|—|no|Project-scoped PostHog query:read credential for internal aggregate reports; empty leaves analytics unavailable. Roles: api.|
|`NODUS_PROVIDER_SECRETS`|—|no|Where provider account secrets live: ssm:/nodus-platform//app/providers/ (SSM SecureString parameters, ADR-122) or secretsmanager: (a bare prefix also means Secrets Manager); each account’s secretRef is appended. Required outside local. Roles: controller.|
|`NODUS_PUBLIC_API_URL`|—|no|Public origin of the API (<https://api>.), which hosted MCP’s protected-resource metadata and 401 challenge name (RFC 9728); empty uses <http://localhost>: under NODUS_ENV=local and leaves /mcp unmounted elsewhere. Roles: api, gateway.|
|`NODUS_REGISTRY_HOST`|—|no|Host of the Nodus registry, registry. (localhost:5000 in compose); empty disables image builds, mirrors and registry tokens. Roles: api, controller.|
|`NODUS_REGISTRY_SIGNING_KEY`|—|no|P-256 private key, PEM (SEC 1 or PKCS #8), that signs registry bearer tokens; the registry trusts its public key. Roles: api, controller.|
|`NODUS_RESEND_API_KEY`|—|no|Resend API key; empty logs each email’s template and recipient count instead of sending, which only NODUS_ENV=local allows. Roles: api, controller.|
|`NODUS_SENTRY_DSN`|—|no|Sentry DSN; empty disables error reporting.|
|`NODUS_STRIPE_API_BASE`|—|no|Stripe API base URL override; the compose stack points it at stripe-mock. Empty uses api.stripe.com.|
|`NODUS_STRIPE_LIVE`|`false`|no|Whether this deployment takes live-mode payments; events whose livemode differs are rejected.|
|`NODUS_STRIPE_SECRET_KEY`|—|no|Stripe secret or restricted key (sk_test\_/rk_test\_ outside prod), agreeing with NODUS_STRIPE_LIVE; empty turns payments off.|
|`NODUS_STRIPE_WEBHOOK_SECRET`|—|no|Signing secret (whsec\_…) of the POST /webhooks/stripe endpoint; empty refuses every delivery.|
|`NODUS_STRIPE_WEBHOOK_URL`|—|no|Public URL of POST /webhooks/stripe that nodus-server seed registers as the Stripe webhook endpoint; empty leaves the endpoint alone.|
|`NODUS_TOKEN_PEPPERS`|—|no|Token HMAC peppers as :, comma-separated, KMS-encrypted in the cloud; the highest version signs new tokens. Empty uses a fixed development pepper when NODUS_ENV=local.|
|`NODUS_USERCONTENT_DOMAIN`|—|no|Registrable domain of preview URLs and Workspace browser tools, https\://-. (ADR-020); never the API’s domain, and one Nodus owns, since it receives each exchange token. Unset outside NODUS_ENV=local turns the browser tools and previews off; NODUS_ENV=local defaults it to nodus-usercontent.net. Roles: controller, gateway.|
|`NODUS_WATCH_DATABASE_URL`|—|no|Postgres URL of the watch tailer’s one connection, logged in as nodus_watch (data-model §12); empty uses NODUS_DATABASE_URL, whose login must then bypass row-level security (compose). Roles: api, gateway.|
|`NODUS_WEBHOOKS_ALLOW_PREFIXES`|—|no|Address prefixes the SSRF dialer would refuse but deliveries may reach, comma-separated; only NODUS_ENV=local allows any (compose receivers). Roles: controller.|
|`NODUS_WORKSPACE_EDGE`|—|no|Optional JSON browser ingress: domain (account.workers.dev), backend_origin (dedicated HTTPS gateway origin), key (32 random bytes, standard base64). Shared only by controller and gateway. Roles: controller, gateway.|
|`NODUS_WORKSPACE_EDGE_ACCOUNT`|—|no|Optional JSON browser endpoint provisioning: account_id and api_token with Workers Scripts edit. Controller only; required with WORKSPACE_EDGE. Roles: controller.|

## nodusd (node agent)

|Variable|Default|Required|Description|
|-|-|-|-|
|`NODUS_GATEWAY_URL`|—|yes|Node protocol endpoint the agent dials, such as <https://nodes>..|
|`NODUS_STATE_DIR`|`/var/lib/nodus`|no|Agent state directory: credentials, ring buffers, re-adoption records.|
|`NODUS_CONTAINERD_ADDRESS`|`/run/containerd/containerd.sock`|no|containerd socket.|
|`NODUS_LOG_LEVEL`|`info`|no|Minimum log level: debug, info, warn or error.|
|`NODUS_SENTRY_DSN`|—|no|Sentry DSN; empty disables error reporting.|

## nodus CLI and SDK (client environment, ADR-069)

|Variable|Default|Required|Description|
|-|-|-|-|
|`NODUS_API_KEY`|—|no|API key (nodus_sk\_…); overrides the stored login.|
|`NODUS_API_URL`|—|no|API base URL, such as <https://api>..|
|`NODUS_BASE_URL`|—|no|Deprecated alias of NODUS_API_URL, accepted with a warning for one major version.|
|`NODUS_ORG`|—|no|Organization name or id.|
|`NODUS_PROJECT`|—|no|Project name.|
|`NODUS_CONTEXT`|—|no|Named context from the config file.|
|`NODUS_CONFIG`|—|no|Config file path.|
