Skip to main content

Environment variables

Applies to: SimpleTwo 0.9.x · Checked: 26.09.2026

This page is generated from the code

Names and defaults are taken from the same files the services themselves read (site/docs-gen/env-variables.py). The list is therefore complete by construction: a variable not here is a variable no service reads.

These values are normally set by the coordinator when it installs a role: it writes the service file and fills the parameters in. The reference matters in two cases — when you are working out why a service behaves the way it does, and when you install one by hand.

1. The coordinator​

The coordinator keeps a registry of its variables, and each row records what changing it costs:

ClassMeaning
restartthe value is read once at startup; editing it in a running process's environment does nothing
hotre-read while the process runs

A name that is not in the registry is not treated as an error: the coordinator warns and keeps running. That decision was bought with an outage — the first version of the registry refused to start on an unknown variable, and an installation went down because of a variable the image itself shipped. Anything that runs before the service must not be able to stop it.

VariableTypeAppliesWhat it does
ST_ADDRstringrestartHTTP listen address: the domain-validation challenge (ACME) and the redirect to HTTPS
ST_HTTPS_ADDRstringrestartHTTPS listen address; empty disables HTTPS
ST_TOKEN_TTLdurationrestartsession token lifetime. Kept short because revocation here is expiry
ST_REFRESH_TTLdurationrestartrefresh token lifetime; long, and revocable server-side
ST_GATEWAY_TTLdurationrestarthow old a VPN node's heartbeat may be before the node counts as stale
ST_TRUSTED_PROXIEScsvrestartnetworks whose X-Forwarded-For may be believed; empty means the header is ignored
ST_ACME_STAGINGboolrestartissue certificates from Let's Encrypt staging instead of production
ST_TLS_DOMAINstringrestartthe name the coordinator orders a Let's Encrypt certificate for; empty means self-signed
ST_TLS_EMAILstringrestartcontact address for the certificate authority; optional
ST_AGENT_BIN_DIRpathrestartthe directory holding agent builds for each platform: the coordinator hands them to hosts when installing roles
ST_DEPLOY_DRYRUNboolrestartprint the installation commands instead of running them. The value is parsed strictly — False and Off are false, and a typo is refused with an error rather than silently becoming enabled
ST_DB_PATHpathrestartthe coordinator's database file (SQLite); empty means an in-memory store, which is a test bench
ST_KEYSTORE_PATHpathrestartthe file holding the master encryption key. A path, never the key itself: a key in an environment variable is a key in a log. The file must live outside the data directory, or a backup of the data carries the key to it
ST_VERSIONstringrestartthe build version; supplied by the image, never set by hand
ST_TOKEN_SECRET 🔒stringrestartthe token signing secret; shared by the coordinator and the product services

2. The messaging service​

VariableDefaultWhat it does
MSG_ACME_CACHE/var/lib/simpletwo/msg-acmethe directory the issued certificate is kept in
MSG_ACME_EMAIL—contact address for the certificate authority; optional
MSG_ACME_STAGING0Let's Encrypt staging instead of production
MSG_ADDR:9090the address and port the service accepts clients on
MSG_AI_PROVIDER_KEY_FILE—the path to the file holding the model provider's key. A file only: a value in the environment ends up in logs
MSG_AI_PROVIDER_KINDanthropicthe model provider's dialect: anthropic or OpenAI-compatible
MSG_AI_PROVIDER_URL—the model provider's address; the default depends on the dialect
MSG_CONTROL_ADDR127.0.0.1:9091the control API's address. Loopback by default: it does not face outward
MSG_CONTROL_TOKEN 🔒—the control API's token; injected by the coordinator
MSG_CONVLOG_KEEP10000how many revisions of a conversation's log to keep
MSG_COORDINATOR_CERT_SHA256—the coordinator certificate's fingerprint (a pin); protects against substitution
MSG_COORDINATOR_INSECUREfalsedo not verify the coordinator's certificate. Test benches only
MSG_COORDINATOR_URL—the coordinator's address
MSG_DB_DSN—the Postgres connection string. Empty means an in-memory store, which is a test bench
MSG_DEPROVISION_RETENTION_DAYS30how many days the data of a person whose chat and calls were withdrawn in identity is kept: they are disabled at once (refused, sockets and pushes stopped), and the data is deleted afterwards. 0 deletes on the next pass; the clock runs only while access assignment is on in identity
MSG_DIRECTORY_SOURCE—not read since messaging 0.199.0: people and groups always come from the directory's feed when MSG_IDENTITY_URL is set, people's rights from the live RBAC projection. The 0.x coordinator's agent still sets it from the console switch
MSG_DOMAIN—this installation's own domain for federation; empty means federation is off
MSG_FEDERATION_ALLOW—the domains this installation accepts delivery from, comma-separated
MSG_IDENTITY_URL—identity's private address: the service reads the assignments of the chat-and-calls feature there and reports what it created or deleted. Empty means no assignments are read: everybody is admitted, nobody is deprovisioned
MSG_LIVEKIT_KEY—the media server's key — room passes are signed with it
MSG_LIVEKIT_SECRET 🔒—the media server's secret
MSG_MAX_MEMBERS10000the cap on members of one conversation
MSG_MAX_UPLOAD_MB50the size limit of a single attachment, in megabytes
MSG_MEDIA_DIR/var/lib/simpletwo/mediathe attachment directory when attachments live on disk rather than in object storage
MSG_PRESENCE_GRACE_SEC45how many seconds somebody counts as online after their last connection drops
MSG_PSTN_CDR_RETENTION_DAYS0how many days a telephone call record (CDR) is kept after the call ended; 0 takes the default, 395 days
MSG_REDIS_ADDR—the bus address; needed for the SFU pool, telephony and multiple replicas
MSG_REDIS_DB0the Redis database number
MSG_REDIS_PASSWORD 🔒—the bus password
MSG_RETENTION_DAYS0message retention in days; 0 means never delete
MSG_S3_ACCESS_KEY 🔒—the object store's access key
MSG_S3_BUCKET—the bucket for attachments
MSG_S3_ENDPOINT—the object store's address
MSG_S3_PREFIX—a key prefix inside the bucket
MSG_S3_REGION—the object store's region
MSG_S3_SECRET 🔒—the object store's secret
MSG_SFU_POOL_PATH/var/lib/simpletwo-messaging/sfu-pool.jsonthe file holding the SFU pool snapshot
MSG_TLS_ADDR:443the HTTPS listen address when the service terminates its own TLS
MSG_TLS_HOST—the service's public name, and the name in its certificate
MSG_TURN_HOST—the TURN server name handed to clients
MSG_TURN_SECRET 🔒—the TURN shared secret that temporary credentials are derived from

3. The directory service — the directory and sign-in​

VariableDefaultWhat it does
DIR_ACME_CACHE/var/lib/simpletwo/identity-acmethe certificate cache directory: without it the certificate is re-issued on every start and runs into the CA's rate limit
DIR_ACME_EMAIL—contact address for the certificate authority; optional
DIR_ACME_STAGING0Let's Encrypt staging instead of production
DIR_ADDR:8086the private HTTP listen address — the coordinator writes to identity through it
DIR_ALLOWED_ORIGINS—browser origins besides the coordinator's own that may read the directory's address book (/v1/directory/*): comma-separated, exact scheme://host[:port]. Needed when the web client is embedded in another site's page. Empty: the coordinator's origin only
DIR_APNS_KEY_ID—the APNs key identifier
DIR_APNS_KEY_P8_FILE—the path to notify's APNs key file (.p8) — iPhone and Mac pushes; the agent writes it from the coordinator's settings
DIR_APNS_SANDBOX0send pushes to Apple's sandbox instead of production (Xcode builds)
DIR_APNS_TEAM_ID—the Apple Developer team identifier
DIR_APNS_TOPIC—the iPhone app's VoIP topic (bundle id plus .voip); the alert topic is the same id without the suffix
DIR_APNS_TOPIC_MACOS—the macOS app's bundle id — its own topic; empty, no Mac is pushed to
DIR_AUDIT_ALARM_BYTES1073741824the security event log size at which /healthz raises the storage alarm; 1 GiB by default
DIR_BREACH_LIST—a file of leaked-password SHA-1s (a Pwned Passwords export), searched on disk and never loaded. Empty means the built-in list of common passwords alone; no third-party service is called
DIR_COORDINATOR_CERT_SHA256—the SHA-256 fingerprint of the coordinator's self-signed certificate
DIR_COORDINATOR_INSECURE0trust the coordinator's self-signed certificate; only together with DIR_COORDINATOR_CERT_SHA256
DIR_COORDINATOR_URL—the coordinator's address the key for the integration secrets is fetched from. Empty means no key: the secrets stay as they are and /healthz says "secrets_sealed": false
DIR_DATA_DIR/var/lib/simpletwo/directorythe directory of the store's files on the role's host: directory.db, notify.db, calendar.db (embedded SQLite). Empty refuses to start: a directory without a store has nowhere to put a group
DIR_EXPECTED_SHA256—the digest of the binary the coordinator served and the agent verified. Set, the service hashes itself at start and refuses to run on a mismatch; empty, it only reports the digest in /healthz
DIR_FCM_SA_JSON_FILE—the path to notify's Firebase service-account file (Android pushes)
DIR_MAIL_URL—a mail node's private address: sign-in codes to a person's verified external address leave through its service door. The coordinator writes it when the installation has a mail host; empty means no e-mail codes, and the policy switch will not turn them on
DIR_PLATFORM—this directory's platform (simpletwo, simplezero, simplethree): its schema extension's prefix — x-<platform>-… in LDAP and urn:ietf:params:scim:schemas:extension:<platform>:2.0:User in SCIM — under which its catalogue is seeded and a new attribute lands. Empty: simpletwo
DIR_PLATFORM_ISSUER—the issuer name of platform tokens in this installation — the primary directory's public URL, the same the coordinator hands every verifying service; a replica signs tokens with its own keys under that name, and every instance publishes every instance's keys at /oauth/jwks. Set by the coordinator; empty: the instance's own URL
DIR_PROFILES—the role's layers on this host, comma-separated: base (the line's store: accounts, groups, the installation's objects, the schema, the minimal sign-in, SCIM), simpletwo (SimpleTwo's extension: address books and the GAL, aliases, the rooms' legs, guests, bots, the move, access to the products), calendar. Empty is every one; base is always on; an unknown name refuses to start
DIR_PUBLIC_URL—the service's origin as clients reach it; the coordinator publishes it as identity_url
DIR_REPLICATION_PEERS—the other directory instances of this installation — their SCIM bases (https://<name>/scim/v2), comma-separated; the directory reads each one's feed every minute and applies the rows by the version rule (multi-master). The coordinator sets the list; empty — no peers
DIR_REPLICATION_ROLE—this instance's standing among its peers: executor runs the outbound jobs (SCIM targets, the SIEM, HRMS, the upstream LDAP, SAML metadata), replica does not; what the directory serves (LDAP, OIDC/SAML, SCIM, sign-in) every instance serves. Empty — the coordinator does not manage replication here and the settings in the store stand
DIR_SCHEMA_MASTER—the origin of the instance where the schema changes (https://<name>): the schema doors here answer 307 to it. Empty — the schema changes at this instance
DIR_TLS_ADDR:443the HTTPS listen address
DIR_TLS_HOST—the service's public name. Set, HTTPS with a certificate it obtains itself, for sign-in, the portal and the console; empty, private HTTP only
DIR_TOKEN_TTL12hthe lifetime of a session this service renews itself; kept equal to the coordinator's

4. The directory service — the calendar half​

VariableDefaultWhat it does
DIR_CAL_ADDR:8085the calendar service's address and port
DIR_CAL_CALDAV_ENABLED0allow full CalDAV access; off by default
DIR_CAL_COORDINATOR_CERT_SHA256—the SHA-256 fingerprint of the coordinator's self-signed certificate
DIR_CAL_COORDINATOR_INSECURE0trust the coordinator's self-signed certificate; only together with DIR_CAL_COORDINATOR_CERT_SHA256
DIR_CAL_COORDINATOR_URL—the coordinator's address the key for the address books is fetched from. Empty means no key: contacts are stored in the clear and /healthz says "books_sealed": false
DIR_CAL_DAV_AUTH—how a person signs in to CalDAV and CardDAV: calendar (the default) — the calendar's device password or identity's app password with the scope caldav/carddav; identity — identity's app password alone, device passwords are refused and no longer issued. Written by the agent from the coordinator's dav_auth switch; identity without DIR_CAL_DIRECTORY_URL, or any other value, refuses to start
DIR_CAL_DB_PATH—the calendar's file; by default calendar.db in the DIR_DATA_DIR directory
DIR_CAL_DEFAULT_TZUTCthe default timezone
DIR_CAL_DEPROVISION_RETENTION_DAYS—how many days the calendars and books of a person who was deleted, or whose calendar was withdrawn (steps of the coordinator's tasks), are kept, closed, before they are deleted. 0 deletes on the next pass
DIR_CAL_DIRECTORY_URL—identity's private address: the service verifies app passwords (CalDAV/CardDAV) there. Defaults to the directory's own private address. Since directory 0.58.0 it no longer reads the assignment feed
DIR_CAL_MEET_URL—the origin a meeting's guest link is built from (the coordinator's host). Empty emits no link at all
DIR_CAL_PUBLIC_URL—the base subscription links are built from; defaults to https://<DIR_TLS_HOST>/cal — the calendar answers under /cal on the directory's name. Behind a proxy it must be set, or subscriptions never refresh
DIR_CAL_S3_ACCESS_KEY—the access key of the attachments' object store
DIR_CAL_S3_BUCKETsimpletwo-calendarthe calendar's attachments bucket; simpletwo-calendar by default
DIR_CAL_S3_ENDPOINT—the object store for the calendar's attachments; empty turns attachments off, and the service says so in /healthz
DIR_CAL_S3_REGION—the attachments' object store region
DIR_CAL_S3_SECRET—the secret of the attachments' object store
DIR_CAL_SERIES_CAP_YEARS—how many years ahead a recurring series is expanded
DIR_CAL_SERVICE_KEY_DIR—the calendar half's own service-key ring for the keys mode of the service token (it signs as svc:calendar); empty, the process-wide ST_SERVICE_KEY_DIR. Written by the agent
DIR_CAL_TOKEN_TTL—the service token's lifetime
DIR_CAL_WORK_DAYS1,2,3,4,5the organisation's working days (1 is Monday), comma-separated
DIR_CAL_WORK_END18:00the end of the working day
DIR_CAL_WORK_START09:00the start of the working day
ST_SERVICE_KEY_DIR—the directory of this host's key (current.json, next.json, previous.json) and of the pinned copy of every service's keys (registry.json). The agent generates and rotates the key on the host itself and registers it with the coordinator; the key never leaves the host. In keys mode the service does not start without it

5. Mail — the mail and mx roles​

VariableDefaultWhat it does
MAIL_ACME_CACHE/var/lib/simpletwo/mail-acmethe certificate cache directory: without it the certificate is re-issued on every start
MAIL_ACME_EMAIL—contact address for the certificate authority; optional
MAIL_ACME_STAGING0Let's Encrypt staging instead of production
MAIL_ADDR:8087the HTTP listen address: JMAP, push, /healthz, the internal API
MAIL_AUDITsharedthe mailbox access audit: off, shared (shared mailboxes — the default) or all
MAIL_CALENDAR_URL—the calendar's scheduling feed: every invitation for somebody with a mailbox here arrives as mail
MAIL_COORDINATOR_CERT_SHA256—the SHA-256 fingerprint of the coordinator's self-signed certificate
MAIL_COORDINATOR_INSECUREfalsetrust the coordinator's self-signed certificate; only together with MAIL_COORDINATOR_CERT_SHA256
MAIL_COORDINATOR_URL—the coordinator's address the sealing keys are fetched from. Empty means no key can be fetched — acceptable only while encryption is off
MAIL_DB_DSN—the Postgres connection string — both hosts of the pair with target_session_attrs=read-write. Empty means the in-memory store, i.e. a test bench
MAIL_DIRECTORY_SOURCE—not read since mail 0.92.0: people and groups come from the directory alone (MAIL_IDENTITY_URL). The 0.x coordinator's agent still sets it
MAIL_DMARC_ORG—the organisation's name in the DMARC reports (the first mail domain by default)
MAIL_DMARC_REPORTStruewhether the domains that ask for DMARC aggregate reports (rua) get them: daily, one per domain (on; off sends none)
MAIL_DOMAINS—mail domains, comma-separated, for the first start: the list of accepted domains is filled from them once (the first is the primary); after that the list is kept in the console's Domains card and this variable is not read
MAIL_IDENTITY_CERT_SHA256—the SHA-256 fingerprint of identity's self-signed certificate
MAIL_IDENTITY_INSECUREfalsetrust identity's self-signed certificate; only together with MAIL_IDENTITY_CERT_SHA256
MAIL_IDENTITY_URL—identity's address: people with their addresses, groups with their address, senders and members
MAIL_INTERNAL_TOKEN 🔒—the token mx authenticates with on the internal API
MAIL_LMTP_ADDR:24where mx delivers over LMTP; answered only to the mx nodes and this host. off turns it off
MAIL_MDNoffread receipts: off, internal (inside the organisation only) or all
MAIL_MX_NODES—the mx nodes outbound mail is relayed to: comma-separated host:port, round-robin
MAIL_QUARANTINE_DAYS30how many days a held message (the filters' and the anti-virus's quarantine) is kept, then deleted without notice (30; 0 keeps it until an administrator decides)
MAIL_RECALL_ALLOW_READfalseallow recalling a copy that has already been read
MAIL_RECALL_MAX_AGE0how old a message may be to be recalled; 0 is no limit
MAIL_S3_ACCESS_KEY 🔒—the object store's access key
MAIL_S3_BUCKETsimpletwo-mailthe bucket for mail
MAIL_S3_ENDPOINTS—the object tier: primary=https://…;secondary=https://…; this version uses the primary. Empty means an in-memory tier, for development only
MAIL_S3_PREFIX—a key prefix inside the bucket
MAIL_S3_REGION—the object store's region
MAIL_S3_SECRET 🔒—the object store's secret
MAIL_TLSRPT_ORG—the organisation's name in the TLS-RPT reports (MAIL_DMARC_ORG by default, and without it the first mail domain)
MAIL_TLSRPT_REPORTStruewhether the domains that ask for TLS-RPT reports (RFC 8460) with their _smtp._tls record get them: daily, one per domain, to its mailto: addresses (on; off sends none)
MAIL_TLS_ADDR:443the HTTPS listen address
MAIL_TLS_HOST—the public name this service answers JMAP on. Set, HTTPS with a certificate it obtains itself, and the coordinator announces mail_url once the name answers
MAIL_TOKEN_TTL12hthe lifetime of a session this service renews itself
MX_ADDR127.0.0.1:8088the mx admin/health listen address; never public
MX_ARC_TRUSTED—the ARC sealers (RFC 8617) local policy trusts — comma-separated domains, each with its subdomains (lists.example,google.com); empty (the default) trusts none. A message that fails DMARC under p=reject or p=quarantine is delivered as any other only when its ARC chain verifies, every sealer from the newest down to the one that vouches is listed, and the one that vouches saw DMARC pass for this From:; Authentication-Results says dmarc=fail with the reason, the aggregate report local_policy. The chain is verified and written down (arc=) and a group's copies to its members outside are sealed whatever this says
MX_DEVICES—connectors for machines that cannot AUTH (scanners, ERP, monitoring), a JSON list: name, networks (CIDR or addresses), senders (addresses or a local @domain), relay (local/any), rate (messages a minute per source address, 60), max_size, tls (optional/require); recognised on the :25 door by the source network; a list that does not parse stops the service
MX_DKIM_DIR/etc/simpletwo/mx-dkimthe DKIM keys: <domain>/<selector>.pem, PKCS#8 or PKCS#1, owner-only; every key of the From: domain (or its parent) signs; none there and mail leaves unsigned, which /healthz shows
MX_DNSBL_ZONESzen.spamhaus.orgthe DNS block lists (RFC 5782) every client of the :25 door is checked against, comma-separated (`zone=127.0.0.2
MX_DNSWL_ZONES—the DNS allow lists: an address they list is not checked against the block lists (empty for none)
MX_FILTERS—the content filters on mail from the internet — a JSON list [{"name":"rspamd","transport":"milter","address":"inet:127.0.0.1:11332","on_error":"open"}, {"name":"av","transport":"icap","address":"icap://av:1344/respmod","on_error":"closed"}] (empty for none); the transport is milter or icap; on_error is open (the message goes on without the filter) or closed (the sender is told 451); timeout 30s, eom_timeout 300s; a milter's spam_signal is the header rules that file a message as Junk; an ICAP service's verdict is how the anti-virus says it found something (headers, header_patterns, on_modified_body, status_codes); on_virus is quarantine (ICAP's default: the message is held, the sender told 250) or reject (the sender told 550); a milter counts as an anti-virus only when on_virus is set; a list that does not parse stops the service
MX_FILTERS_FILE—a file holding the same JSON list as MX_FILTERS; when set, MX_FILTERS is not read, and a file that cannot be read stops the service. It is how the agent hands the list over: a systemd environment does not carry regular expressions with a \ intact
MX_FILTER_QUARANTINEheldwhat a filter's quarantine does: held (the default) keeps the message on the mail cluster until an administrator decides (console, Mail → Quarantine), its recipients told by a notice; junk files it as Junk. An anti-virus's find is always held
MX_HOSTNAME—the edge's name in EHLO and Received; the host's name by default
MX_INBOUND_AUTHonSPF, DKIM and DMARC on mail from the internet (on by default; off for none): the results in Authentication-Results, a refusal at DATA under p=reject, Junk under p=quarantine
MX_INTERNAL_TOKEN 🔒—the token the mail cluster gave this edge
MX_MAIL_API—the mail nodes' internal API bases, comma-separated; empty takes the MX_MAIL_NODES hosts on MX_MAIL_API_PORT
MX_MAIL_API_PORT8087the mail role's HTTP port for the internal API when MX_MAIL_API is not set (8087)
MX_MAIL_NODES—the mail cluster's nodes for LMTP and the internal API: comma-separated host:port
MX_MAX_CONNECTIONS500how many :25 connections a node holds at once; the next is told 421 (0 for no bound)
MX_MAX_CONNECTIONS_PER_IP20how many :25 connections one address may hold at once; the next is told 421 (0 for no bound); devices connectors' networks are not counted
MX_MAX_MESSAGE_BYTES52428800the largest message the MX door takes, in bytes (50 MiB)
MX_RELAY_ADDR:2525the door for the mail cluster's outbound mail (:2525; off for none): answered only to the addresses in MX_MAIL_NODES, STARTTLS required when there is a certificate
MX_SMARTHOST—where all outbound mail goes instead of the recipients' MX (comma-separated host:port); empty is MX delivery
MX_SMTP_ADDR:25the public MX door (:25); off listens on none
MX_SPOOL_DIR/var/lib/simpletwo/mx/spoolthe on-disk queue's directory; owner-only — it is mail in flight, in the clear
MX_SUBMISSION_MAX_CONNECTIONS0how many connections to the submission ports 587 and 465 together a node holds at once, counted apart from :25; the next is told 421 on 587 and closed on 465, and the refusal is in the submission refusal log (0, the default, for no bound); devices connectors' networks are not counted
MX_SUBMISSION_MAX_CONNECTIONS_PER_IP0how many connections to 587 and 465 together one address may hold at once (an IPv6 client by its /64); the next is refused as under MX_SUBMISSION_MAX_CONNECTIONS (0, the default, for no bound). Everyone behind one NAT is one address: an office sending through one public address shares the bound
MX_SUBMIT_ADDR:587SMTP submission with STARTTLS and an app password (:587; off for none); not opened without MX_TLS_CERT: AUTH is never offered in the clear
MX_SUBMIT_TLS_ADDR:465SMTP submission with TLS from the first byte (:465; off for none); not opened without MX_TLS_CERT
MX_TLS_CERT—the certificate for STARTTLS on :25; with MX_TLS_KEY
MX_TLS_KEY—the key to MX_TLS_CERT

6. The drive — the drive role​

VariableDefaultWhat it does
DRIVE_ACME_CACHE/var/lib/simpletwo/drive-acmewhere the obtained certificate is kept
DRIVE_ACME_EMAIL—the Let's Encrypt contact
DRIVE_ACME_STAGING01 — Let's Encrypt's staging directory
DRIVE_ADDR:8088the address and port the service accepts clients on
DRIVE_BIN_DAYS30how many days a deleted file waits in the bin before the sweeper takes its bytes. The same number mail keeps. 0 means there is effectively no bin: the next sweep takes everything
DRIVE_COORDINATOR_CERT_SHA256—the SHA-256 fingerprint of the coordinator's self-signed certificate
DRIVE_COORDINATOR_INSECURE—trust the self-signed certificate of the coordinator the drive asks for permissions in identity mode; only together with DRIVE_COORDINATOR_CERT_SHA256
DRIVE_DB_DSN—the Postgres connection string. Required: the drive has no in-memory mode, because a drive that loses its tree on restart is not a degraded mode
DRIVE_DEFAULT_QUOTA_GB0the default space quota, in gigabytes; 0 means no ceiling. A space's own quota is set in the console and overrides this
DRIVE_IDENTITY_URL—identity's private address: the provisioning feed that gives everybody who has the drive a personal home. Empty and nobody is provisioned, which /healthz says outright
DRIVE_MAIL_URL—a mail node's private address: the leavers' retention policy, the person responsible for the leaver's mailbox and the warning letter — the same as for the mailbox. Empty and a leaver's home is kept, read-only, for ever
DRIVE_MAX_UPLOAD_MB2048the ceiling on one file, in megabytes. Checked when an upload is opened, not after the bytes have crossed the network
DRIVE_PUBLIC_URL—the drive's public address — the name clients reach it by
DRIVE_S3_ACCESS_KEY—the object store's access key
DRIVE_S3_BUCKETsimpletwo-drivethe drive's bucket; simpletwo-drive by default
DRIVE_S3_ENDPOINT—the object store's address. Empty and the service still runs, holding only files small enough for a catalogue row, and says so in /healthz
DRIVE_S3_REGIONus-east-1the object store's region
DRIVE_S3_SECRET—the object store's secret
DRIVE_TLS_ADDR:443the HTTPS listener's address (default :443)
DRIVE_TLS_HOST—the drive's public name, and the name in the certificate it obtains itself

🔒 — the value is secret: do not print it into logs and do not pass it around in messages. Secrets that can be given as a file should be given as a file: a value in the environment is visible to anybody who can read the process's state.

6. Shared across the deployment​

ST_TOKEN_SECRET and ST_MESSAGING_URL are read by several services: the first because tokens are signed by the coordinator and verified by the others, the second because the calendar tells the messaging service about changes. Their values are the same across the installation — otherwise the services simply do not believe each other.

The platform token's variables are the same in every service with a person's door — messaging, calendars, mail, identity; the shared library shared/auth reads them, and the agent takes the values from the desired state. The coordinator does not read them: the switch is its own setting. The service token's variables ST_SERVICE_* work the same way; shared/svcauth reads them. ST_MOVE_STOPGAP_UNTIL reaches identity and the calendar only — the services whose doors the migration tool calls.

VariableWhat it does
ST_PLATFORM_TOKENwhich token the person doors take: hmac (the default) is the coordinator's session token, as before; identity is identity's platform token only, and a person's HMAC session is refused. Anything else and the service does not start. One switch for the whole installation, set at the coordinator (PUT /admin/api/settings/platform-token)
ST_PLATFORM_ISSUERthe platform token's issuer — identity's public address, exactly as it writes iss
ST_PLATFORM_JWKS_URLidentity's keys (JWKS) on its private address; an unknown kid refetches them at most every 30 seconds
ST_PLATFORM_JWKSthe pinned JWKS copy (base64url): what verifies the token when identity is unreachable, a restart included. The coordinator fetches it from identity and refreshes it when the keys rotate
ST_PLATFORM_REVOCATIONS_URLidentity's revocation feed (/v1/revocations/feed): ended sessions and disabled accounts, read every 30 seconds with a service token
ST_PLATFORM_RBAC_URLthe coordinator's RBAC projection (/v1/service/rbac): in identity mode a person's roles and permissions come from here, never from the token; read every 15 seconds, the last good copy answers through a failure
ST_PLATFORM_REVOCATIONS_STALEthe revocation feed's staleness bound in identity mode: once the feed has not been read for longer, tokens issued before the bound are refused and /healthz says revocations.stale: true; a duration from 1m to 24h, off, or empty for 10 minutes. Set in the coordinator's console (Settings → Directory, the "Moving the services to the directory" card)
ST_SERVICE_TOKENwhich token the services call each other with: hmac (the default) is the token under the shared ST_TOKEN_SECRET, as before; keys is only a token signed with the calling host's own key, and a service token under the shared secret is refused. Anything else and the service does not start. One switch for the whole installation, set at the coordinator (PUT /admin/api/settings/service-token)
ST_SERVICE_KEY_DIRthe directory of this host's key (current.json, next.json, previous.json) and of the pinned copy of every service's keys (registry.json). The agent generates and rotates the key on the host itself and registers it with the coordinator; the key never leaves the host. In keys mode the service does not start without it
ST_SERVICE_KEYS_URLthe coordinator's registry of service keys (/v1/service/keys/jwks): an unknown kid refetches it at most every 30 seconds; while the coordinator is unreachable the pinned copy verifies
ST_MOVE_STOPGAP_UNTILthe instant (RFC 3339) until which identity and the calendar take a wave-less svc:move service token — the migration tool's stopgap. Empty or absent: shut (the default); the instant passed by the service's own clock: shut; more than 72 hours ahead or unreadable: shut; in the service token's keys mode: always shut. Every use is audited on the service with reason stopgap and counted in /healthz (move.stopgap). Set by an owner in the coordinator's console (Settings → Migration tool: svc:move stopgap, PUT /admin/api/settings/move-stopgap) with a required reason

Next​