Skip to main content

Virtual hosts

Put host blocks inside a binding to dispatch by the Host header on a single shared socket. Each host block matches one or more host patterns and has its own routes; a request whose host matches no block falls back to the binding's direct routes — the default vhost.

binding ":443" {
tls cert="./cert.pem" key="./key.pem"

host "app.example.com" {
route "/*" {
proxy {
upstream "http://127.0.0.1:9000"
}
}
}

host "*.static.example.com" {
route "/*" {
files root="./public"
}
}

// default vhost: unmatched hosts (and Host-less requests)
route "/*" {
redirect "https://example.com" status=308
}
}

Host patterns

A host block takes one or more patterns as arguments. Matching is case-insensitive and ignores any port in the Host header.

PatternMatches
example.comexactly that host
*.example.comany single-or-multi-label subdomain
*any host

A block can list several:

host "example.com" "www.example.com" {
route "/*" {
files root="./public"
}
}

The default vhost

The binding's direct route blocks (those not inside any host) serve as the fallback for any request whose Host matches no block. This also catches requests with no Host header — for example HTTP/1.0 clients. A binding with no host blocks is just a plain set of routes (the behavior described in Routing).

This works uniformly across HTTP/1.1, HTTP/2, and HTTP/3: the gateway resolves the host from the Host header or, for h2/h3, the :authority pseudo-header.

Per-host TLS (SNI)

A host block can carry its own tls certificate, selected by the TLS ClientHello's SNI on the shared socket. The binding-level tls (if present) is the fallback for unmatched SNI.

binding ":443" {
// fallback certificate for unmatched SNI
tls cert="./default.pem" key="./default-key.pem"

host "a.example.com" {
tls cert="./a.pem" key="./a-key.pem"
route "/*" {
files root="./site-a"
}
}

host "b.example.com" {
tls cert="./b.pem" key="./b-key.pem"
route "/*" {
files root="./site-b"
}
}
}

The same certificate resolver feeds both the rustls acceptor and (with the h3 feature) the QUIC/HTTP/3 listener, so per-host certificate selection works identically on HTTP/1.1, HTTP/2, and HTTP/3.

Routing and certificates are independent

SNI selects the certificate during the TLS handshake; the Host header (or :authority) selects the routes after the connection is established. They usually name the same host, but they're resolved separately — a binding-level fallback certificate can still terminate TLS for a request that then falls through to the default vhost.