2.3 Writing a minimal tenant config

A tenant config declares one application: its mounts and a few top-level settings. With tenantsDir: "./tenants" and tenant main, the file is ./tenants/main.json.

The smallest useful tenant

{
  "mounts": [
    { "path": "/files", "service": "file",
      "config": { "access": "open" } }
  ]
}

That's a complete, valid tenant: a streamed file store at /files. mounts is the only required top-level key. The explicit "access": "open" matters: mounts fail closed when access is absent, so public access is always a choice, never an accident. Start the node (or reload — see below) and /files is live.

A more realistic starting point

{
  "mounts": [
    { "path": "/files", "service": "file",
      "config": { "access": "open" } },
    { "path": "/data",  "service": "data",
      "config": { "access": "open" } },
    { "path": "/services", "service": "services",
      "config": { "access": "open" } }
  ]
}

This gives you file storage, a JSON record store, and the self-config API at /services — the last of which lets you edit the tenant over HTTP instead of editing the file and restarting (Part 10). Most tenants want services mounted from the start.

This is a loopback-only bootstrap config: all three mounts are open so the first-request tutorial works and rs2 auth init can create the first operator. Keep the node bound to 127.0.0.1; Part 5 adds auth, and the bootstrap command then locks the data/control mounts. Never expose this starting config directly to a network.

Anatomy of a mount

{ "path": "/data", "service": "data", "config": { "enforceSchema": true } }
  • path — the URL prefix. Routing is longest-prefix on segment boundaries, so more specific mounts win.
  • service — a prebuilt service (file, data, pipeline, wrapper, query, template, auth, proxy, sms, services, or log) or a custom code:<name>@<version>.
  • config — service-specific options plus the standard cross-cutting keys that work on any mount: access, retry, caching, schedule, named-secret grants, and agent-surface metadata (x-agent, description, …). These are introduced where they're relevant and gathered in Appendix B. Every mount should set access; no policy means no access.

Duplicate paths are rejected, and the whole config is validated before it goes live — an invalid tenant never partially loads.

Loading changes

  • Editing the file on disk takes effect on a node restart (or any PUT /services/raw round-trip that triggers a reload).
  • Editing through PUT /services/raw (the services mount) validates, dry-builds, and hot-swaps the tenant atomically with no restart — the preferred path on a running server.

For now, edit ./tenants/main.json and restart the node. With a tenant in place, let's make a real request.


Previous: 2.2 Running your first node · Manual home · Next: 2.4 Making your first request →