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
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
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
- 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.
- 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
Build per 20.2: a default nav site + one static docs site + one dynamic site (with script and db directories).
Edit the dynamic site's script and submit a reload for that host only, while load-testing the other two continuously.
Implement /status on the default site: enumerate all servers/hosts into a runtime status table (ch. 11's query APIs).
Summary
| Point | Conclusion |
|---|---|
| Blueprint | home production: one process, 14 vhosts, static and dynamic mixed |
| Layout | host directories self-contained; the name is the identity; static sites same shape |
| Endpoints | one server takes 80/443, split by Host/SNI |
| Reuse | modules/ copied per site; isolation free; sharing through explicit channels |
| Catch-all | host_default carries the lowest-risk content |
- xrt reference · tls_server — building multi-certificate SNI services at the library level