xs.json in depth · host level & vhosts
Multiple sites in one server: host_default catches everything unmatched, hosts[] splits traffic precisely by domain. This chapter explains the three routing sources and per-host certificate dispatch.
Overview
8.1 Intro
Many sites on one machine is the server norm: the main site, the API, an admin backend and several customer sites sharing one process. XServer's model is two levels: server (endpoint) × host (site): one server listens on the port, and each request is routed to a host by "which site is it for"; every host has its own static root, script and certificates.
8.2 Host-level fields
| Field | Constraint | Description |
|---|---|---|
name | unique within the server, non-empty | host name; duplicates / empty fail fast |
host | semicolon-separated domains | required and non-empty for http/ws hosts with vhosts enabled; e.g. "a.com;www.a.com" |
path | directory must exist | static root; missing fails fast |
devlang / devfile | — | c / static / custom; with static, devfile may be empty |
tls_ca / tls_cert / tls_key | PEM paths | host-level certs → the SNI table's data source (see 8.4) |
A domain binds to exactly one host (double binding fails fast); one host may bind several domains (semicolon-separated; matching follows domain case rules).
8.3 The three routing sources
The "target host" of an HTTP request can appear in three places; XServer consults them in order:
| Source | Shape | Typical scenario |
|---|---|---|
| Host header | Host: a.com:8080 | the vast majority of everyday requests (the port suffix is stripped) |
| absolute-form | GET http://a.com/x HTTP/1.1 | proxy-style clients |
| authority-form | CONNECT a.com:443 | tunnel requests |
- HTTP/1.1 mandates Host: missing or duplicated is a protocol error (400) — behavioral correctness, not an optional check
- Matching no hosts[] entry → fall back to host_default; a keep-alive connection switching Host per request still routes correctly per request
- On a TLS endpoint, identity selection happens in the handshake (SNI, next section); HTTP-layer routing happens after decryption — the two layers agree
8.4 Host-level certificates & SNI
Every http/ws host may carry its own tls_ca/tls_cert/tls_key. At assembly they enter the SNI table; during the TLS handshake the client names its target domain in the ClientHello (SNI), and the server picks the matching certificate — domain-to-certificate matching completes in the handshake, before any HTTP request begins. The server-side cookie binds the ClientHello's identity selection and the Accept to the same generation, eliminating cross-generation handshake races.
8.5 Contract
- Routing: three Host sources → hosts[] exact match → host_default fallback; HTTP/1.1 without Host is a 400.
- Certificates: host-level certs dispatch by SNI; a host without certificates cannot complete handshake identity selection on a TLS endpoint.
- Scripts: every devlang=c host gets an independent script runtime — reloads publish as the complete generation of the host's server.
Common mistakes
- Symptom
- Configured "api.com", expected "www.api.com" to match too — it lands in default.
- Cause
- host binding is exact matching (each entry of the semicolon list compared whole); no wildcards, no prefixes.
"host": "api.com"
/* expecting www.api.com to match too */"host": "api.com;www.api.com"- Symptom
- Startup fails: the host field is required and non-empty for http/ws hosts with vhosts enabled.
- Cause
- A vhost with an empty domain has no routing meaning — "catch everything" is host_default's job, not an empty host.
Exercises
Configure one server with host_default (site A) + hosts[] (site B bound to test.local); put different index.html files in the two wwwroots.
curl -H "Host: test.local" and a request without a Host header each hit their own site.Use curl's --resolve and the absolute form (curl -x http://127.0.0.1:8080 http://test.local/, proxy style) to trigger the Host-header and absolute-form routing sources respectively.
Write a script that sends two requests with different Host values over one keep-alive connection and verify per-request routing.
Summary
| Point | Conclusion |
|---|---|
| Two-level model | server = endpoint; host = site (static root / script / certs) |
| Routing | Host header / absolute-form / authority-form, exact matching |
| Fallback | host_default always exists; unmatched traffic goes there |
| Certificates | host level → SNI table, dispatched at handshake; hot-swappable |
- xrt reference · tls_server — the underlying SNI selector and server-side cookie implementation
- xrt reference · http1 — protocol details of Host-header parsing and absolute-form