---
title: "Explanation: Serving a World on a Custom Hostname"
description: "Why a creator's own hostname can reach a published world's runtime without ever carrying deployment or content authority, and how the edge Worker, resolution API, and origin admission cooperate to prove it per request."
engineVersion: v1.0.234
date: 2026-09-28
license: "(c) Gessa, proprietary. Cite with attribution to https://gessa.ai/docs/. Terms: https://gessa.ai/terms/."
canonical: https://gessa.ai/docs/explanation/public-world-custom-runtime/
---

# Explanation: Serving a World on a Custom Hostname

{% version engineVersion="v1.0.232" coordinate="docs-public.v0" /%}

_Last verified 2026-09-03 against engine v1.0.232._

This page awaits re-extraction under decision D26 of the docs program; treat every number on it as provisional until its dossier receipt is stamped.

A creator can point their own hostname, for example `play.example.com`, at a published Gessa world so players reach it without a Gessa URL in the address bar. The design principle behind the **public world custom runtime** is a single sentence: a hostname is a label, never an authority. The custom hostname selects nothing about which deployment runs, which content version serves, or who owns the publication. Every one of those facts is re-derived, per request, from the canonical publication authority, and the hostname is only allowed to name a world that is already ready to serve.

This page explains why authority is kept off the hostname, how the request travels three hops to reach the one shared runtime host, and what this unit deliberately does not do. Detailed source evidence remains in the repository's `docs/spec/dossiers/public-world-custom-runtime/dossier.yaml`; a dedicated public reference has not been published. The broader rule it follows is [backend authority](backend-authority.md): the server holds the truth and every edge is a non-authoritative projection of it.

## Why a hostname must not carry authority

If a custom hostname carried its own routing target, a creator (or anyone who could influence a request header) could aim a friendly-looking domain at content it does not own, or keep serving a deployment that has since been retired. The engine refuses that shape. The resolution join in `CanonicalCustomRuntimeResolver` reads exactly one publication-owned hostname binding and then asks the sole `PublicWorldRuntimeResolver.resolveSlug` for the runtime, and it returns a servable result only when the freshly resolved runtime is ready and its publication and slug coordinates agree with the binding. The runtime authority identifier is taken from the runtime resolution, never copied from the hostname binding. A hostname can therefore never introduce a deployment or a content authority of its own; it can only ride one that the publication already owns.

## The three hops

A request to a custom hostname travels a fixed path, and each hop narrows what the next may assume.

```text
browser (world.creator.com)
   -> Cloudflare custom-hostname routing
   -> edge Worker            (resolves the hostname, mints a signed assertion)
   -> internal resolution API (bearer-authorized, re-resolves authority)
   -> fixed origin listener   (a dedicated kernel socket, mTLS-fronted)
   -> shared runtime host      (reuses the resolution, serves the world)
```

The **edge Worker** (`createCustomRuntimeEdgeWorker`) is the only component that chooses a destination, and both of its destinations are constructor configuration validated to exact credential-free HTTPS origins, so no request header can point it anywhere else. It resolves the hostname through the internal **resolution API**, checks that the response echoes the hostname it asked about, strips the incoming proxy and identity headers, and mints a short-lived signed **assertion** that names the hostname, the publication, the generation, the HTTP method, and a digest of the request target. It then forwards to a single fixed origin.

The **origin** does not trust the assertion on its face. `CustomRuntimeOriginAdmission` runs a fail-closed ladder: it requires transport evidence that the dedicated listener produced, an exact origin match, the absence of forwarding headers, the shared route allowlist, WebSocket-upgrade agreement, a browser `Origin` that matches the asserted hostname, and then it re-resolves the current authority and requires the freshly resolved tuple to equal the assertion before finally consuming the assertion's nonce so it can never be replayed. Only a full pass hands the request to the runtime.

## Two independent credentials

The path uses two credentials that protect different hops. The **bearer service token** authorizes the Worker to call the internal resolution API, and it is checked in constant time against a small keyring. The **assertion** is the edge-to-origin credential: a compact HS256 token whose payload is bound to the request method and a digest of the path and query, so a captured assertion cannot be re-aimed at a different route. The origin verifies the assertion against a key ring, enforces its short lifetime and time window, and then still re-resolves authority from the database, so a valid signature alone is never sufficient. The resolution secret and the assertion secret are required to be distinct at both the Worker and the origin.

## The dedicated listener is the trust anchor

The origin's transport evidence is not read from a header, which a client controls, but from kernel socket state that a client cannot forge. The hosted composition derives it purely from whether the request arrived on the dedicated listener's local port. `createCustomRuntimeOriginListener` binds a second Node server onto the same Fastify route graph, on a port that must differ from the public application port, and relays WebSocket upgrades to the same handler. In production that listener sits behind a mutual-TLS front; from this module's point of view, arrival on that socket is the proof, and the boundary also refuses a malformed `Host` that merely mentions the owned origin rather than letting it fall through to ordinary application routes.

## What this unit does not do

Being honest about the boundaries matters as much as the mechanism.

- **There is no per-host origin.** Only one fixed origin is representable; the Cloudflare projection in `projectCustomRuntimeCloudflareConfiguration` sets client-host forwarding off, Authenticated Origin Pull on, and the workers.dev subdomain off. A creator's hostname cannot select a different backend.
- **Custom aliases never redirect.** A 3xx from the origin is converted to a `502` so that no internal origin can leak through a `Location` header.
- **The route surface is only the shared runtime allowlist.** Control-plane paths are denied before resolution even runs, so a custom hostname cannot reach account or authoring routes.
- **The whole origin path is off by default.** It is a hosted-only composition, gated by an environment master switch that defaults to off, and it requires PostgreSQL and the canonical runtime resolver; pool-less local fixtures do not take this path at all.
- **Transport enforcement is an infrastructure contract, not something this module verifies.** The module trusts the dedicated listener as its evidence; the mutual-TLS termination that fronts it lives in the Cloudflare and load-balancer configuration, outside this code.

The custom runtime is a serving path, not a catalog surface: it is not one of the versioned engine catalogs, so its documentation stands on named conformance tests and the runtime modules rather than on a generated reference. The repository dossier records the surfaces, invariants, and supporting checks. For how it relates to the room runtime it ultimately serves, see the [Netcode Model](netcode-model.md).
