10.1 Server config in depth

The serverConfig.json is the operator layer: it configures the process — where it listens, how it resolves tenants, where files and logs physically live. This is distinct from tenant config, which configures an application (2.3).

The full shape

{
  "listen": "127.0.0.1:3100",
  "tenancy": { "mode": "single", "tenant": "main" },
  "fileRoot": "./data",
  "dataRoot": "./data-store",
  "tenantsDir": "./tenants",
  "logging": { "sink": "file", "level": "info",
               "file": { "path": "./logs", "maxBytes": 8388608, "backups": 5 } },
  "catalogueHosts": ["catalogues.example.com", "*.cdn.example.com"],
  "infrasPath": "./infras.json",
  "bootstrapAdmin": { "email": "admin@example.com" }
}
Key Meaning
listen Address/port to bind
tenancy single (one tenant) or multi (resolve from Host — 10.2)
fileRoot Local-fs root for the default file store; each tenant gets a prefixed subdirectory
dataRoot Separate root for the default, durable file-backed data store
tenantsDir Directory of <tenant>.json configs
logging Where logs physically go (10.3); optional, defaults to a file sink at ./logs
catalogueHosts Operator allowlist for external catalogue and bundle fetches; empty disables them
infrasPath Operator-managed adapter/credential definitions (default ./infras.json)
adminToken Optional token for node admin endpoints; RS2_ADMIN_TOKEN takes precedence
bootstrapAdmin Optional first-admin seed in single-tenant mode; prefer env for its password (10.7)

fileRoot and tenant isolation

fileRoot is the base directory the local file store writes under. The host scopes every tenant to its own prefixed subdirectory — a tenant can't address another tenant's files (the path-safety rules in 3.2 ensure no escape). dataRoot is deliberately separate: records may include password hashes and must not become browsable merely because the tenant also has a file mount. Other backends are selected through store.adapter (4.7, 8.9, 10.7).

All relative filesystem paths in this document — including log and infra paths — are resolved against the directory containing serverConfig.json, not the process working directory.

tenantsDir

<tenant>.json files here are loaded lazily — a tenant is built the first time it's addressed, and rebuilt atomically on a config change (10.4). An invalid tenant config never partially loads.

Engine features are a build-time choice

Whether a node can run JS or Wasm code: mounts depends on how the server was built, not on config:

  • --features js / --features wasm compile in those engines.
  • The standard server always wires the outbound HTTP adapter that backs fetch/httpOut grants; embedders decide whether to supply their own.

A node built without an engine still accepts config that references it (the config stays valid) but answers requests to such a mount with 501 engine_unavailable at request time. Build the node with the features you intend to run.

Health endpoints

GET /healthz (liveness) and GET /readyz (readiness) are tenant-independent and are what an orchestrator should probe (2.5).

Next: turning a node into a multi-tenant deployment.


Part 9 — HTTP API & Cross-Cutting · Manual home · Next: 10.2 Single- vs. multi-tenant →