10.7 Infras, bootstrap, and production boundaries
Some configuration belongs to the tenant; some belongs to whoever operates the machine. Infras keep backend credentials and locked settings on the operator side while still letting a tenant choose an approved backend by name.
Operator-managed infras
serverConfig.infrasPath (default ./infras.json) points to a map of named
partial adapter configs:
{
"orders-db": {
"adapter": "code:postgres-data@<version>",
"description": "Production orders database",
"allowedTenants": ["acme"],
"config": { "host": "db.internal", "password": "…" },
"requires": ["database"],
"infraOnly": ["host"]
}
}
A tenant uses it without seeing those values:
"store": { "adapter": "infra:orders-db", "database": "acme_orders" }
At config time the runtime verifies the tenant may use the infra, requires its
open fields, rejects tenant attempts to set infraOnly fields, overlays the
operator config (operator values win), and then validates the real adapter. A
bad reference is rejected during PUT /services/raw, not deferred until a
request.
GET /services/infras lists only the infras available to that tenant, their
descriptions, required/locked field names, and which keys the operator provides.
It never returns values. The same mechanism supplies credential strategies to a
proxy or httpOut grant through inject: "infra:<name>".
Pipeline, query, and template authoring specs can use an independent
specStore:
"specStore": { "adapter": "infra:spec-store", "root": "orders-pipelines" }
That keeps instructions on an operator-approved file backend without changing a
query's execution store.adapter.
Reloading infras
Edit infras.json, then reload it without restarting:
Invoke-RestMethod -Method Post -Uri http://127.0.0.1:3100/admin/reload-infras `
-Headers @{ Authorization = "Bearer $env:RS2_ADMIN_TOKEN" }
Set the node token through RS2_ADMIN_TOKEN (preferred) or
serverConfig.adminToken. With neither, the endpoint is disabled (503). A
successful reload swaps the infra set and causes tenants to rebuild on their
next request. Removing an infra still in use intentionally makes those tenant
builds fail until their config is repointed.
Seeding the first admin at startup
In single-tenant mode, bootstrapAdmin can seed one operator directly into the
configured auth dataset:
"bootstrapAdmin": { "email": "admin@example.com" }
Supply the password through RS2_ADMIN_PASSWORD; RS2_ADMIN_EMAIL can override
the email too. Set both credentials or neither. The tenant must already have
auth.jwtSecret, and the seeded role A must be included in operatorRoles.
Seeding is if absent: an existing record is never overwritten. With the
standard durable data store, the admin therefore survives restart.
For a fresh no-auth node, rs2 auth init is the HTTP-only alternative (5.1 and
Appendix E). Do that while bound to loopback, because the user store and control
surface are briefly open during bootstrap.
The production network boundary
rs2-server speaks plain HTTP. In production, bind it to loopback and terminate
TLS at Apache, nginx, or another reverse proxy. Preserve the original Host
header — multi-tenant resolution depends on it. The repo's deploy/ directory
contains a systemd unit, Apache template, installer, and Ubuntu build runbook.
The release installer runs the node as a dedicated system user, keeps config in
/etc/rs2, data in /var/lib/rs2, and logs in /var/log/rs2; reinstalling
upgrades the binary without overwriting existing config. Choose the JS release
variant when the tenant uses JavaScript code, templates, or loadable adapters.
That completes operating a node. Part 11 covers bringing an existing v1 Restspace configuration across to RS2.
← Previous: 10.6 Secrets handling · Manual home · Next: Part 11 — 11.1 What rs2 migrate carries over →