Operator guide

Configuration reference

Every environment variable Nosdesk reads, grouped by area, with defaults and what each one does.

Nosdesk is configured entirely through environment variables. In a Docker Compose install they live in the .env file beside your compose.yaml; running the backend directly, they come from the process environment.

Only a handful of variables are required. Everything else has a sensible default. Variables marked required must be set for a production boot.

Boolean values accept true/false, 1/0, yes/no, and on/off, case-insensitive.

Core secrets

These protect sessions and encrypt data at rest. Generate fresh values; never reuse the examples.

VariableDefaultDescription
JWT_SECRETrequiredSigning key for session tokens. Generate with openssl rand -base64 32.
MFA_KEK_V1requiredKey-encryption key for at-rest encryption of MFA secrets, channel credentials, and plugin secrets. 64 hex characters (32 bytes); generate with openssl rand -hex 32.
MFA_KEK_V{n}(unset)Additional keyring generations for zero-downtime key rotation. Provision MFA_KEK_V2, point new writes at it, re-wrap, then retire V1.
MFA_KEK_VERSIONhighest loadedSelects which keyring generation new writes use. Single-key installs can omit it.
ALLOW_INSECURE_DEFAULT_SECRETSfalseLets the stack boot with the example Postgres/Redis passwords. Test environments only. Never set in production.

The single-key ENCRYPTION_KEY / MFA_ENCRYPTION_KEY variables are a legacy path superseded by the MFA_KEK_* keyring. New installs should use the keyring.

Server and networking

VariableDefaultDescription
HOST127.0.0.1Bind address the backend listens on. Code default is loopback, but in the Docker image you set HOST=0.0.0.0 so the published port can reach the container. Host exposure stays restricted to loopback by the 127.0.0.1:8080:8080 port mapping in compose.yaml, not by this value.
PORT8080Port the backend listens on.
ENVIRONMENTdevelopmentDeployment environment. Anything other than development/dev makes session cookies Secure (fail-closed). Set to production.
FRONTEND_URLhttp://localhost:3000Public URL of the app. Drives CORS and cookie scope. Set to your HTTPS origin.
ADDITIONAL_CORS_ORIGINS(unset)Comma-separated extra origins allowed through CORS.
TRUSTED_PROXIES(unset)Comma-separated CIDR ranges whose X-Forwarded-For Nosdesk will trust. Unset means the header is ignored (the safe default with no proxy). Set it when running behind a reverse proxy so rate limiting and audit logs see the real client IP — see the Reverse proxy + TLS guide.
NOSDESK_TENANT_DOMAIN(unset)Hosted-mode only. Suffix that lets every <slug>.<domain> origin pass CORS. Leave unset for self-hosted.
NOSDESK_DEPLOYMENT_MODEself-hostedSwitches between single-tenant (self-hosted) and subdomain-routed multi-tenant (hosted). Leave at the default for self-hosting.

Database

VariableDefaultDescription
DATABASE_URLrequiredPostgreSQL connection string. In Compose: postgres://nosdesk:<password>@postgres:5432/nosdesk.
POSTGRES_DBnosdeskDatabase name.
POSTGRES_USERnosdeskDatabase user.
POSTGRES_PASSWORDrequiredDatabase password. Must match the credentials in DATABASE_URL.
DB_MAX_CONNECTIONS10Maximum pooled connections.
DB_MIN_CONNECTIONS1Minimum idle connections kept warm.
DB_CONNECTION_TIMEOUT30Seconds to wait for a connection before erroring.

SSL mode is not a separate variable — set it in the DATABASE_URL query string (e.g. ?sslmode=require) when the database is on a separate host. Migrations run automatically on backend startup; there is no separate migrate step.

Redis and rate limiting

VariableDefaultDescription
REDIS_URLrequired (production)Redis connection string. In Compose: redis://:<password>@redis:6379. Redis is a hard dependency in production — it backs distributed rate limiting, the collaborative-editing cache, and the readiness probe. A production instance with REDIS_URL unset refuses to boot; there is no in-memory fallback. Only development/dev mode falls back to redis://localhost:6379.
REDIS_PASSWORDrequired (Compose)Redis password. Must match the credentials in REDIS_URL.
RATE_LIMIT_PER_MINUTE60Max requests per IP per minute for unauthenticated callers.
AUTH_RATE_LIMIT_PER_MINUTE600Max requests per minute for authenticated callers.

Storage and uploads

VariableDefaultDescription
STORAGE_TYPElocalStorage backend: local or s3. An unrecognised value fails loudly at startup.
STORAGE_PATH / UPLOAD_DIR/app/uploadsFilesystem path for uploaded files (local backend). The Compose backend_uploads volume persists this.
MAX_FILE_SIZE_MB50Maximum upload size in megabytes.

For STORAGE_TYPE=s3, Nosdesk reads BUCKET_NAME, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_ENDPOINT_URL_S3, and AWS_REGION (with STORAGE_S3_* equivalents for non-AWS S3-compatible stores). Any required value missing fails at startup. With the default local backend, uploaded files are captured by the application backup (and you can also snapshot the uploads volume directly) — see the Backup & restore guide.

Authentication and sessions

VariableDefaultDescription
REQUIRE_ADMIN_MFAtrueRequire administrators to set up MFA. Disable only for local development.
REQUIRE_PASSWORD_COMPLEXITYtrueEnforce password complexity rules on local accounts.
MFA_MAX_ATTEMPTS(internal default)Failed-attempt cap before an MFA lockout.
MFA_WINDOW_SECONDS(internal default)TOTP acceptance window in seconds.

Session lifetime is fixed and not operator-configurable: access tokens last 15 minutes and are transparently refreshed from a 7-day session, so sign-ins survive a working day without re-authenticating.

Passkeys (WebAuthn)

VariableDefaultDescription
WEBAUTHN_RP_IDhost of FRONTEND_URLRelying-party ID. Usually your bare domain (nosdesk.example.com).
WEBAUTHN_RP_NAMENosdeskHuman-readable relying-party name shown in the passkey prompt.
WEBAUTHN_RP_ORIGINFRONTEND_URLFull origin (scheme + host) passkeys are bound to. Must be HTTPS in production.

Bootstrap admin

Optional. Pre-seeds the first administrator for headless provisioning instead of using the browser first-run screen.

VariableDefaultDescription
INITIAL_ADMIN_NAME(unset)Display name for the seeded admin.
INITIAL_ADMIN_EMAIL(unset)Email for the seeded admin.
INITIAL_ADMIN_PASSWORD_HASH(unset)Pre-hashed password for the seeded admin.
BOOTSTRAP_TOKEN_TTL_SECONDS1800 (30 min)Lifetime of the one-time token that authorises first-run setup. After it lapses, restart the server to mint a fresh setup link.

Single sign-on

Microsoft Entra ID

VariableDefaultDescription
MICROSOFT_CLIENT_ID(unset)Application (client) ID.
MICROSOFT_TENANT_ID(unset)Directory (tenant) ID.
MICROSOFT_CLIENT_SECRET(unset)Client secret.
MICROSOFT_REDIRECT_URI(unset)OAuth callback, e.g. https://your-domain/auth/microsoft/callback.

Generic OIDC

Works with Keycloak, Auth0, Okta, Google, Authentik, Authelia, and other compliant providers.

VariableDefaultDescription
OIDC_CLIENT_ID(unset)OIDC client ID.
OIDC_CLIENT_SECRET(unset)OIDC client secret.
OIDC_ISSUER_URL(unset)Issuer URL for endpoint auto-discovery (recommended).
OIDC_AUTH_URI / OIDC_TOKEN_URI / OIDC_USERINFO_URI(unset)Manual endpoints if the provider lacks discovery.
OIDC_REDIRECT_URI(unset)OAuth callback, e.g. https://your-domain/auth/oidc/callback.
OIDC_DISPLAY_NAMEOpenIDLabel on the SSO login button.
OIDC_SCOPESopenid profile emailRequested scopes.
OIDC_USERNAME_CLAIMpreferred_usernameClaim used as the username.
OIDC_LOGOUT_URI(unset)Provider logout URL for single logout.

Email (SMTP)

Outbound email powers password resets, invitations, and notifications.

VariableDefaultDescription
SMTP_ENABLEDfalseMaster switch for outbound email.
SMTP_HOST(required when enabled)SMTP relay hostname.
SMTP_PORT587Relay port. 587 for STARTTLS, 465 for implicit TLS.
SMTP_SECURITYstarttlsTransport security: starttls, tls (implicit, port 465), or plaintext (local test servers only).
SMTP_USERNAME(required when enabled)Auth username.
SMTP_PASSWORD(required when enabled)Auth password or app-specific password.
SMTP_FROM_NAMENosdeskDisplay name on sent mail.
SMTP_FROM_EMAILSMTP_USERNAMEFrom address.

Logging and observability

VariableDefaultDescription
RUST_LOGinfo,tantivy=warn,...Log level and per-crate filters. Use debug for troubleshooting.
LOG_FORMATtextSet to json for structured logs with request-correlation fields, suited to log aggregation.

Data retention

Background jobs prune aged records on these schedules.

VariableDefaultDescription
AUDIT_LOG_RETENTION_DAYS540 (18 months)How long to keep audit_log partitions.
SYNC_ACTIONS_RETENTION_DAYS90How long to keep the sync_actions change-event log.
NOSDESK_USER_PURGE_GRACE_DAYS(internal default)Grace period before a soft-deleted user is hard-purged.
WORKSPACE_HARD_DELETE_GRACE_DAYS(internal default)Grace period before an archived workspace is hard-deleted.

Session geolocation

VariableDefaultDescription
GEOIP_DB_PATH(unset)Path inside the container to a MaxMind-format .mmdb database. Adds a coarse “City, Country” to each active session. Fully offline; no IP leaves the server. Leave unset to disable. You supply the database (DB-IP Lite, MaxMind GeoLite2, or a commercial DB).

Plugins and registry

VariableDefaultDescription
NOSDESK_ROOT_PUBKEYbaked into official imagesEd25519 root public key the binary uses to verify official registry plugins. Compiled in at build time, so the official ghcr.io image already carries it; you do not set this at runtime. It only matters if you build your own image.
NOSDESK_REGISTRY_URLhttps://nosdesk.com/registryPlugin registry base URL. Set to empty to disable registry sync (air-gapped).
NOSDESK_ALLOWED_PLUGIN_TIERSofficial,localComma-separated trust tiers permitted to run: official, verified, community, local. Verified and community run third-party code in-process, so they stay off until the sandbox ships.
NOSDESK_ALLOW_WEB_SIDELOADfalseAllow admins to upload a signed plugin zip through the browser. CLI install always works regardless.
PLUGIN_SANDBOX_ORIGIN(unset)Separate origin that will serve the cross-origin iframe sandbox for community plugins.
NOSDESK_PLUGINS_DIR/app/pluginsDirectory scanned for filesystem-provisioned signed plugin zips.

Microsoft Graph sync

Used when importing users and devices from Microsoft Intune / Entra.

VariableDefaultDescription
MSGRAPH_CONCURRENT_USER_PROCESSING5Concurrent user-processing workers during a sync.
MSGRAPH_USER_BATCH_SIZE10Users fetched per batch.
MSGRAPH_SKIP_DISABLED_ACCOUNTStrueSkip disabled accounts during sync.
MSGRAPH_SYNC_SECURITY_GROUPS / MSGRAPH_SYNC_M365_GROUPS / MSGRAPH_SYNC_DISTRIBUTION_LISTS / MSGRAPH_SYNC_DYNAMIC_GROUPSvariesToggles for which group types to sync.
MSGRAPH_BACKGROUND_PHOTOS(default)Fetch user profile photos in the background.

Advanced and security toggles

Most installs never touch these.

VariableDefaultDescription
NOSDESK_STATE_DIR(default)Base directory for runtime state (search index, etc.).
SEARCH_INDEX_PATHunder state dirPath to the Tantivy full-text search index.
CSP_REPORT_ONLYfalseRun the Content-Security-Policy in report-only mode (logs violations without blocking). Useful when tuning a custom proxy.
NOSDESK_OUTBOUND_ALLOWED_HOSTS(unset)Allowlist for server-side outbound requests (SSRF guard) where applicable.
NOSDESK_ALLOW_INSECURE_TLSfalseSkip TLS verification on outbound connections. Debugging only.
NOSDESK_ALLOW_FRONTEND_DEBUG_LOGSfalsePermit verbose frontend debug logging in production builds.
NOSDESK_WS_HEARTBEAT_MS / NOSDESK_WS_CLIENT_TIMEOUT_MS(defaults)WebSocket heartbeat interval and client timeout for collaborative editing.