Chapter 20 / 51
Volume 3 · Protocol Development

vhosts in practice: running a site farm in one process

Chapter 8 covered the vhost mechanism; this chapter covers its engineering organization — the blueprint being the production home repository: one XServer process, 14 vhosts, dynamic and pure-static sites mixed.

Overview

Positioning: where the config chapters (volume 2) and protocol chapters (volume 3) converge. No new mechanisms — just how to organize them into a farm you can run for years.

20.1 Intro: the production blueprint

The home repository (XServer's production deployment) in real shape: one xs.json, one server (dual 80/443 endpoints), 14 vhosts — a developer community, RPA sites in Chinese and English, an academy, blogs, a documentation farm (the XRT/XGE/XServer docs are pure static hosts with devlang=static) and test sites. Every dynamic site has its own script and certificate; static sites carry zero script. One process serves them all; one reload updates any single site.

20.2 The site-farm layout

The home repository's host layout (abstracted from production)
home/
├── xs / xs.exe / xs.json          /* the host and the master config */
├── host/
│   ├── default/                   /* host_default: the fallback site */
│   │   ├── script/main.c          /*   dynamic site: script */
│   │   ├── wwwroot/  tls/  db/
│   ├── xxdevs/                    /* community site (own script + certs) */
│   │   ├── script/main.c  wwwroot/  tls/
│   ├── xrt/                       /* docs site: pure static */
│   │   └── wwwroot/               /*   no script directory */
│   └── ...                        /* the other sites, same shape */
└── tools/ dev/                    /* ops and dev helpers */

What just happened: three layout decisions — one self-contained directory per host (wwwroot/tls/script/db side by side; whole directories are portable); the host directory name is the site identity (config name/host matches the directory; debugging needs no cross-checking); a static site is simply "a host without a script" (devlang=static, same layout shape).

20.3 Organizing the config

  • One server takes all of 80/443: every site shares the endpoints, split by Host/SNI — don't open one server per site (that hands port-management costs to the firewall)
  • Certificates live next to their site: each host's tls/ directory; the SNI table builds per host automatically (ch. 08/12)
  • List multi-domains explicitly: "a.com;www.a.com" — exact matching, no wildcards (ch. 08's trap)
  • The default site is a catch-all: host_default points at a low-risk page (a nav page / a 404 notice), never real business
  • Custom distributed per site: site-private knobs go into that host's Custom (prefixed keys, ch. 09)

20.4 Script reuse & isolation

Fourteen dynamic sites = fourteen independent script runtimes. Balancing reuse against isolation:

  • Reuse by copying modules/: home's approach copies the common modules (response helpers, database, templates) into the sites that need them — each site compiles its own copy, no cross-site symbol clashes
  • Isolation is free: one site's statics, database handles and crashes stay inside its own generation; reloading site A doesn't touch site B (the publish unit is the host's server generation, but config-level routing leaves unchanged sites completely uninvolved)
  • Cross-site sharing goes through explicit channels: the filesystem (db/) or xsServerFind topology queries — no implicit globals

20.5 Contract

  • Layout: host directories self-contained; the directory name is the identity; static sites share the shape.
  • Endpoints: one server, dual endpoints, split by Host/SNI.
  • Change: reloads submitted per host; unchanged sites take no part.

Common mistakes

An admin panel on the default site
Symptom
Scanners hitting the IP directly (no Host or a random one) land on the admin backend.
Cause
All traffic matching no vhost goes to host_default — it should be the least sensitive site you run.
New site launched without a certificate
Symptom
The new domain's TLS handshake fails or gets another site's certificate.
Cause
Every host on a TLS endpoint must carry its own certificate (the SNI table builds per host); a host with only the host field and no tls_cert/key cannot complete identity selection on 443.

Exercises

BasicA three-site farm

Build per 20.2: a default nav site + one static docs site + one dynamic site (with script and db directories).

Acceptance: three Host names each reach their site; unmatched traffic lands on the default nav page.
AdvancedHot-updating one site

Edit the dynamic site's script and submit a reload for that host only, while load-testing the other two continuously.

Acceptance: zero load-test errors; the log shows a swap only for the target site.
ChallengeA farm inspection route

Implement /status on the default site: enumerate all servers/hosts into a runtime status table (ch. 11's query APIs).

Acceptance: the output covers every site with correct states; non-default sites don't expose the route.

Summary

PointConclusion
Blueprinthome production: one process, 14 vhosts, static and dynamic mixed
Layouthost directories self-contained; the name is the identity; static sites same shape
Endpointsone server takes 80/443, split by Host/SNI
Reusemodules/ copied per site; isolation free; sharing through explicit channels
Catch-allhost_default carries the lowest-risk content
API references in this chapter
xrt further reading