Sites & domains
One binary, many sites. The ROOT settings.json holds the process blocks (server, cache, access_log, soe) and the site map: domain → site folder under www/. Each site is fully isolated — its own settings.json (tables, views, routes, admin menu), its own databases and users, templates, static files, media and MCP token. This example is the map’s localhost entry, pointing at the www/default folder.
"site": {
"example.com": {
"dir": "default",
"alias": [
{ "domain": "www.example.com", "mode": "redirect" },
{ "domain": "old-brand.com", "mode": "clone" }
],
"tls": { "acme": {} }
},
"second.com": "landing"
}| key | description |
|---|---|
| the entry itself | a bare string is shorthand for { "dir": … } — the folder name under www/ |
| alias, mode redirect | 301 to the main domain (www → apex, old domains) |
| alias, mode clone | serve the same site as-is on that domain |
| tls | per-site HTTPS — own PEM or Let’s Encrypt, picked by SNI (see the tls article) |
server.default names the site that answers when the Host header is unknown or missing — direct-IP hits, health checks.
Adding a site is a reload, not a restart: create the folder under www/ with its settings.json (start from a copy of this one), add the map entry, run cms reload. The new site comes up hot; if its users table is empty, its own admin is bootstrapped and the credentials are printed to the console. Removing the entry + reload takes the site down and drops its cached answers.
How a new site is born — the optional root block new_site, used by the site_create MCP tool (an agent creating a site for you). Absent, it behaves as written below:
"new_site": {
"template": "def-help",
"guard": false,
"mcp": false,
"tls": "off"
}| key | description |
|---|---|
| template | def-help — the example site this documentation runs on; empty — one page, no database, no admin |
| guard | hide the new site’s /cms behind a device cookie from birth. Off: the owner signs in with the password straight away, without catching a one-time link first |
| mcp | issue the site its own MCP token at creation. Off: issue it later from the site’s admin or with cms mcp token --site, when it is actually needed |
| tls | acme requests a certificate for the new domain — only if its DNS already points at this server. It does not yet? The site is created over http and the reply says so: a failed FIRST issue would stop the whole node from starting, and that is not a price for one new site |
The site_create call may pass the same four keys to deviate from the node’s policy once.
Site resolution is one hash lookup per request — hundreds of sites cost what one does. The request log is shared (every record carries the host); the cache budget is shared; everything else is per site.