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 wasmcompile in those engines.- The standard server always wires the outbound HTTP adapter that backs
fetch/httpOutgrants; 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 →