Skip to main content

Server configuration

Most of what you'll ever change about a RapidMX server is set in the admin console or by the installers. Underneath, the server has a configuration tree of a few hundred settings: database connections, scanner addresses, job schedules, rate limits, plugin installation rules. You reach for it when you need something the console and the Helm values don't cover, for example pointing message storage at S3, turning on DNSSEC validation, or raising the upload size limit.

This page explains how settings are read and how to set them in each deployment, then lists every setting the server itself defines. The Helm chart reference covers the chart's own values, which set many of these for you.

How settings are read​

The server uses nconf with four layers. The first one that has a value wins:

  1. Plugin settings saved in the admin console. Only keys a plugin's manifest declares, and never one of the server's own protected keys (below).
  2. Command-line arguments.
  3. Environment variables.
  4. The defaults in the server's config.mongo.ts or config.sql.ts, listed on this page.

Environment variable names​

A setting's path is written with : in this documentation (mail:scan:av:clamav:host). As an environment variable, each : becomes a double underscore, and the case stays as it is:

mail__scan__av__clamav__host=clamav
datastores__mongo__url=mongodb://mongo

Values are parsed, so true, false and numbers become booleans and numbers, and a JSON value becomes an array or object. Set the most specific path you can: mail__basic_auth__enabled=false changes one value and leaves the rest of mail:basic_auth at its defaults.

Setting them in each deployment​

DeploymentWhere
Docker ComposeThe environment: list of the server service, in an override file like the docker-compose.prod.yml of the production steps
Kubernetes, k3s, AWSThe chart value service.config, for example --set service.config.mail__dns__resolver=doh-dnssec. Each key is rendered into the server's ConfigMap as an environment variable, and the pods restart when it changes.

service.config is a ConfigMap, not a Secret. Put credentials in a Secret instead (the chart's own secrets, OpenBao, or an IAM role for AWS services) rather than in service.config.

What a plugin can't change​

A plugin's saved settings can never set the server's own configuration. These keys, and everything under them, are protected: trusted_roles, trusted_proxies, auth, cookie_secret, cookies, session, cors, ssl, datastores, base_path, rateLimit, telemetry_services, service_name, version, max_body_size, shutdown, system, metrics, diagnostics, class_loader, cluster_url, react, static_assets, giphy, logs, mail:transport, mail:internal, mail:escrow, mail:pki, mail:auth_server_url, mail:basic_auth, mail:security, mail:blob, mail:scan, mail:dns, mail:dkim, mail:domains, mail:auto_provision, mail:default_quota_bytes, mail:compose, mail:search, mail:preferences, mail:branding, and the schedules of the server's built-in jobs under mail:jobs.

Secrets checked at startup​

Unless NODE_ENV is exactly dev or development, the server refuses to start while any of these is empty or still its publicly known development default:

SettingEnvironment variable
cookie_secretcookie_secret
auth:secretauth__secret
mail:transport:ingest:secretmail__transport__ingest__secret

NODE_ENV=test does not skip this check. The server also logs an error at startup when mail:escrow:audit_hmac_key is empty, or when the ingest secret is shorter than 16 characters, and a warning when mail:security:trusted_authserv_id is empty.

Variables outside the configuration tree​

VariableWhat it does
NODE_ENVproduction for real use. dev, development or test turn on development behaviour, such as skipping an unreachable spam or virus scanner. Only dev and development allow the development secrets.
PORTThe HTTP port (3000 in the image)
SENDMAIL_RELAY_HOSTWhere outgoing mail is relayed (the image's default is postfix). The chart sets it from mail.relay.host.
SENDMAIL_RELAY_PORTRelay port (default 25)
SENDMAIL_RELAY_TLSon or off (default off)
SENDMAIL_FROM_ADDRESSEnvelope sender of relayed mail (default mailer@localhost; the chart sets mailer@<mail host>)
ssl__key, ssl__certPaths of a TLS key and certificate. Set, the server serves HTTPS itself. The chart sets them with global.gateway.tlsTermination=pod.

Reference​

The defaults below are the server's own. @rapidmx/restapi, the library that implements mail, calendars and the other features, reads further settings with defaults of its own (for example most mail:jobs:* schedules). The Diagnostics page's Configuration table in the admin console shows the effective value of every setting, with secrets withheld. See Monitoring.

General​

SettingDefaultWhat it does
max_body_size104857600 (100 MiB)Largest request body, buffered in memory. Raise it for very large mailbox imports.
cookie_secretdevelopment defaultSigns cookies. Required in production.
trusted_roles["admin"]Roles with administrative rights
trusted_proxies[]Proxies whose X-Forwarded-For is believed. Accepts CIDR ranges for rate limiting. The chart sets it from global.trustedProxies.
cors:origins["http://localhost:3000"]Origins allowed credentialed cross-origin requests. The chart sets it.
cluster_urlhttp://localhostThe deployment's base URL
logger:levelinfo in production, debug otherwiseLog level
logger:fileunsetA file to log to
metrics:authRequiredtrueRequire a trusted role for /api/metrics
giphy:api_keyplaceholderGiphy API key for GIF search. The placeholder leaves GIF search off.
shutdown:drain_delay_ms5000On SIGTERM, how long /api/status answers 503 before the server stops
shutdown:timeout_ms25000How long stopping may take before the process exits anyway
telemetry_services:token_roles["telemetry"]Roles of the token telemetry events are sent with
telemetry_services:token_ttl_seconds3600That token's lifetime

Datastores​

On MongoDB the datastores are acl and mongo; on PostgreSQL they are acl and sql.

SettingDefaultWhat it does
datastores:acl:typemongodb / postgresAccess control lists datastore type
datastores:acl:hostlocalhostHost
datastores:acl:databaserrst_aclsDatabase name
datastores:acl:urlunsetConnection URL, used instead of host and database
datastores:acl:synchronizetrueCreate and update the schema at startup
datastores:mongo:typemongodbMain datastore (MongoDB)
datastores:mongo:hostlocalhostHost
datastores:mongo:databaserrst_authDatabase name
datastores:mongo:urlunsetConnection URL
datastores:mongo:synchronizetrueCreate and update collections and indexes at startup
datastores:sql:typepostgresMain datastore (PostgreSQL)
datastores:sql:synchronizetrueCreate and alter tables at startup. See the warning in Upgrading.
datastores:sql:invalidWhereValuesBehavior{ "null": "sql-null" }Required on every SQL datastore (also set on acl)
datastores:cache:type, :urlredis, redis://localhostCache
datastores:events:type, :urlredis, redis://localhostLive events. Also copied to datastores:notifications unless that is set.
datastores:logs:type, :urlredis, redis://localhostLogs

Static files​

SettingDefaultWhat it does
static_assets:compresstrueSend brotli and gzip variants of the browser bundles
static_assets:memory_cache_bytes67108864 (64 MiB)Memory for cached files and compressed variants
static_assets:brotli_quality9Brotli quality of variants made on the fly
react:manifestPathdist/public/.vite/manifest.jsonThe browser build's manifest

Sign-in tokens​

SettingDefaultWhat it does
auth:secretdevelopment defaultVerifies tokens from the auth-server. Must equal the auth-server's. Required in production.
auth:options:audiencemydomain.comExpected token audience
auth:options:issuerapi.mydomain.comExpected token issuer
auth:allowQueryParamfalseAccept a token in the query string
auth:cookie:enabledtrueRead the token from the jwt cookie
auth:strategyauth.JWTStrategyToken verification strategy
mail:auth_server_urlhttp://localhost:3001The auth-server's URL, as browsers reach it. The server also calls it to check app passwords.

App passwords (Outlook and ActiveSync)​

SettingDefaultWhat it does
mail:basic_auth:enabledtrueAccept a user name and app password on the paths below
mail:basic_auth:paths["/mapi","/Microsoft-Server-ActiveSync"]Where HTTP Basic is accepted
mail:basic_auth:realmRapidMXThe realm a 401 names
mail:basic_auth:cache_ttl_ms300000How long a successful sign-in is remembered
mail:basic_auth:cache_max_entries5000Size of that cache
mail:basic_auth:failure_limit10Failures per client address and user name before a 429
mail:basic_auth:ip_failure_limit50Failures per client address, any user name
mail:basic_auth:name_failure_limit50Failures per user name from any address, after which attempts are slowed down
mail:basic_auth:name_delay_ms1000Delay per failure past that limit, up to ten times this
mail:basic_auth:failure_window_ms900000The window the failures are counted in

Mailboxes and mail​

SettingDefaultWhat it does
mail:default_quota_bytes5000000000Initial default quota of the mailbox policy
mail:auto_provision:enabledtrueInitial "create a mailbox on first sign-in" setting of the mailbox policy
mail:auto_provision:quota_bytes5000000000Quota of such a mailbox
mail:auto_provision:timeout_ms10000Time limit for creating it
mail:compose:max_attachment_bytes25000000Combined attachments of one message
mail:preferences:background_max_bytes8388608 (8 MiB)Largest background image a user may upload
mail:search:mongo:datasourcemongoSearch datastore (MongoDB). On PostgreSQL: mail:search:postgres:datasource, sql.
mail:branding:public_url/api/systemBase of self-hosted logo and stylesheet URLs
mail:autodiscover:public_url""The https:// address Autodiscover advertises. Empty: Autodiscover answers nothing.
mail:booking:public_url""The booking pages' address, for links in booking e-mails
mail:jobs:scheduled_send:concurrency4Messages scanned and relayed at once by background and scheduled send
mail:jobs:scheduled_send:drain_ms15000How long a shutdown waits for sends in flight
mail:jobs:meeting_scheduling:schedule*/10 * * * * *How often meeting invitations and updates are sent (cron, with seconds)
mail:jobs:acme_enrollment_driver:schedule0 */5 * * * *How often pending signing-certificate requests are checked
mail:jobs:acme_enrollment_driver:expiry_warning_days30Warn about signing certificates expiring within this many days
mail:jobs:acme_enrollment_driver:failure_audit_after3Failed CA checks in a row before an audit log entry

Message storage​

SettingDefaultWhat it does
mail:blob:backendlocallocal (a directory) or s3
mail:blob:local:root./data/blobsDirectory of message bodies and attachments (/app/data/blobs in the image)
mail:blob:s3:bucket""S3 bucket
mail:blob:s3:region""Its region
mail:blob:s3:prefix""Key prefix, to share a bucket
mail:blob:s3:endpoint""Endpoint of an S3-compatible service other than AWS (MinIO, R2, Spaces)
mail:blob:s3:force_path_stylefalsePath-style requests, needed by MinIO and most self-hosted services
mail:blob:s3:access_key_id""Static access key. Empty: the AWS credential chain (an IAM role). Set both or neither.
mail:blob:s3:secret_access_key""Its secret

Mail transport​

SettingDefaultWhat it does
mail:transport:providerpostfixpostfix or ses
mail:transport:ses:region""SES region. Empty: the SDK's own resolution.
mail:transport:ses:configuration_set""SES configuration set
mail:transport:ingest:secretdevelopment defaultThe /internal/mta bearer secret. Required in production, 16 characters or more.
mail:transport:sendmail:path/usr/sbin/sendmailThe sendmail binary the Postfix transport runs
mail:dkim:key_dir/var/lib/rspamd/dkimWhere DKIM private keys are written
mail:dkim:selectormailDKIM selector
mail:dns:mx_hostnameunsetThe MX host name in the DNS checklist. The chart and Compose set it.
mail:dns:resolvernodenode, or doh-dnssec to validate DNSSEC through a DNS-over-HTTPS resolver
mail:dns:doh:endpointhttps://cloudflare-dns.com/dns-queryThe DoH resolver
mail:dns:doh:require_adtrueTreat a domain that fails or lacks DNSSEC as a lookup failure
mail:dns:doh:timeout_ms5000DoH timeout
mail:security:trusted_authserv_id""authserv-id of trusted Authentication-Results. Empty: no sender is DKIM-verified. See Mail transport.

Spam and virus scanning​

SettingDefaultWhat it does
mail:scan:spam:rspamd:urlhttp://localhost:11333rspamd's scan worker
mail:scan:spam:rspamd:controller_url""rspamd's controller. Empty: url with port 11334.
mail:scan:spam:rspamd:controller_password""Controller password
mail:scan:spam:rspamd:controller_timeout_ms10000Timeout of a learn request
mail:scan:spam:learn:enabledtrueTeach rspamd from users' junk reports
mail:scan:av:clamav:host127.0.0.1ClamAV host
mail:scan:av:clamav:port3310ClamAV port

Encryption certificates​

SettingDefaultWhat it does
mail:pki:backendlocalEncryption CA: local (a key on disk) or openbao (an OpenBao PKI mount)
mail:pki:local_ca:dir/var/lib/rapidmx/pkiThe local CA's directory
mail:pki:local_ca:subjectCN=RapidMX Local Encryption CAThe local CA's subject
mail:pki:local_ca:validity_days397Certificate validity
mail:pki:openbao:addresshttp://127.0.0.1:8200OpenBao address
mail:pki:openbao:mountpkiPKI mount
mail:pki:openbao:rolerapidmxIssuing role
mail:pki:openbao:token""Token that may sign and revoke
mail:pki:openbao:timeout_ms5000Request timeout
mail:pki:openbao:serial_map_path/var/lib/rapidmx/pki/openbao-serials.jsonSerial number map
mail:pki:signing_enrollment:backendmanualSigning certificates: manual or rfc8823. The chart's auto picks one.
mail:pki:manual_enrollment:store_path/var/lib/rapidmx/pki/manual-enrollments.jsonPending manual requests
mail:pki:rfc8823:directory_urlhttps://acme.castle.cloud/acme/directoryRFC 8823 ACME directory
mail:pki:rfc8823:contact_email""ACME account contact
mail:pki:rfc8823:store_dir/var/lib/rapidmx/pki/rfc8823ACME account key and request state
mail:pki:rfc8823:poll_interval_seconds300How often a pending request is checked
mail:pki:rfc8823:max_pending_hours168How long a request may wait on the CA
mail:escrow:audit_hmac_keyunsetKeys the escrow audit log. Never change it once set.

Diagnostics​

SettingDefaultWhat it does
diagnostics:namespace""Kubernetes namespace to inspect. Empty: the pod's own.
diagnostics:timeout_ms5000Time limit of one Kubernetes API request

Rate limits​

The top-level limits apply to anonymous requests, authenticated to signed-in users.

SettingDefaultWhat it does
rateLimit:enabledtrueRate limiting
rateLimit:ipv6_prefix_length64IPv6 clients are counted per network of this size
rateLimit:maxAttempts100Requests per endpoint
rateLimit:windowSeconds60In this window
rateLimit:ip:enabledtrueAlso count per source address
rateLimit:ip:maxAttempts100Requests per address
rateLimit:ip:windowSeconds300In this window
rateLimit:authenticated:maxAttempts10000Requests per user and endpoint
rateLimit:authenticated:windowSeconds300In this window
rateLimit:authenticated:ip:enabledtrueAlso count signed-in requests per address
rateLimit:authenticated:ip:maxAttempts20000Requests per address
rateLimit:authenticated:ip:windowSeconds300In this window

Plugins​

SettingDefaultWhat it does
system:plugins:defaultsActiveSync, Autodiscover, Booking pages, MAPI and Meet, latestInstalled the first time a server starts against an empty database
system:plugins:registryhttps://registry.npmjs.orgnpm registry
system:plugins:registry_token""Token for a private registry
system:plugins:namespaces["@rapidmx"]npm scopes the admin console searches and allows
system:plugins:allowed_packages["@rapidmx/*"]Other packages an administrator may add
system:plugins:dir<server directory>/pluginsWhere plugins are installed (/app/plugins in the image)
system:plugins:sources{}Package name to a local .tgz, installed instead of the registry version
system:plugins:require_integritytrueRequire the registry's integrity hash
system:plugins:npm_timeout_ms600000Time limit of an npm install
system:plugins:max_install_bytes524288000Largest total installed size. 0 disables the check.
system:plugins:uploads:enabledtrueAllow installing an uploaded npm pack file
system:plugins:uploads:max_bytes52428800Largest uploaded pack
system:plugins:restart:drain_delay_ms15000How long a copy reports not ready before restarting for a plugin change
system:plugins:restart:lock_release_delay_ms15000How long a restarted copy holds the restart lock once serving
system:plugins:restart:lock_ttl_ms60000Restart lock expiry
system:plugins:restart:jitter_ms30000Random wait before restarting, without a cache datastore
system:plugins:restart:install_retry_ms60000Retry delay after a failed npm install, doubling
system:plugins:restart:install_retry_max_ms600000Longest retry delay
system:plugins:restart:install_retry_max_attempts6Failed installs in a row before retrying stops
system:plugins:restart:safe_mode_retry_ms300000Retry delay in safe mode (running without plugins after failed starts), doubling
system:plugins:restart:safe_mode_retry_max_ms3600000Longest safe mode retry delay
system:plugins:restart:max_lock_hold_ms900000Longest a starting copy may hold the restart lock
system:plugins:purge:check_ms30000How often unfinished plugin data deletions are checked
system:plugins:purge:initial_delay_ms10000Delay before the first check
system:plugins:purge:grace_ms180000Wait for servers that were starting when a plugin was uninstalled
system:plugins:purge:lease_ms120000How long a deletion's claim lasts
system:plugins:purge:hook_timeout_ms60000Time limit of a plugin's own clean-up hook

Plugins also read settings of their own, under their own names, such as mail:videoconf:* for Meet. Those are edited in the plugin's settings in the admin console. See Plugins.