Skip to content

Reverse Proxy & Domains

This page describes how a self-hosted Lombok instance expects to sit behind a reverse proxy, and the domain model it relies on. It is intentionally conservative: it documents the contract the application actually enforces, not a specific vendor configuration.

It does not prescribe a canonical Caddy, Traefik, or Nginx config. Lombok already ships its own internal Nginx inside the container; what an external proxy or load balancer must do is comparatively small and is described as a set of requirements below.

[!NOTE] If you only need a single-host demo on plain HTTP, you can run the demo compose files directly without an external proxy. This page is for operators putting Lombok behind their own TLS-terminating proxy or load balancer.

A Lombok instance is reached through a single base host — its PLATFORM_HOST — plus a set of subdomains of that host. Both the apex host and its subdomains must resolve to, and be routable to, the same Lombok container.

The container’s bundled Nginx routes incoming requests by their Host header (packages/api/nginx/nginx.conf). There are four request families:

Host patternPurpose
PLATFORM_HOST (apex)The platform UI, its API (/api/), Socket.IO, and the bridge paths (/_bridge/…).
app-server--<app>.PLATFORM_HOSTA running app’s UI.
api-server--<worker>--<app>.PLATFORM_HOSTAn app worker’s API endpoint (called from the app UI iframe).
<label>--tn-<id>--<app>.PLATFORM_HOSTTunnel subdomains (for example dev-server or live-reload tunnels).

These subdomain shapes are generated and parsed by the application itself. For example, getAppRequestWorkerHostname() in packages/types/src/util.ts builds api-server--<worker>--<app>.<platformHost>, and the browser SDK (packages/app-browser-sdk/src/app-browser-sdk.ts) derives the app identifier from the leading label of window.location.hostname. Operators do not construct these names; they only need to make sure traffic for all of them reaches Lombok.

[!NOTE] All subdomains are a single DNS label under PLATFORM_HOST (the -- separators are part of one label, not nested subdomains). So routing and certificates only need to cover one wildcard level: *.PLATFORM_HOST.

Because app UIs, app-worker APIs, and tunnels each live on their own subdomain of PLATFORM_HOST, an instance cannot function with only the apex host routed.

You need both:

  1. DNSPLATFORM_HOST and *.PLATFORM_HOST resolving to the instance.
  2. Reverse-proxy routing — the apex host and all of its subdomains forwarded to the Lombok container.

This requirement also shows up in the platform’s own Content-Security-Policy, which frames app subdomains explicitly:

frame-src 'self' *.{{PLATFORM_HOST}}:*;

(from packages/api/nginx/nginx.conf, where {{PLATFORM_HOST}} is substituted at startup).

If you terminate TLS in front of Lombok, the certificate must therefore cover both the apex and the wildcard — typically a SAN/wildcard certificate for PLATFORM_HOST and *.PLATFORM_HOST.

[!WARNING] A certificate or proxy rule that only covers the apex host will leave app UIs, app-worker APIs, and tunnels unreachable, even if the main platform page loads.

Lombok builds the public URLs it advertises to clients and workers from configuration, not from inbound proxy headers. The relevant variables are read in packages/api/src/core/config/core.config.ts and combined by buildPlatformOrigin() in packages/api/src/core/utils/platform-origin.util.ts:

VariableRequiredDefaultEffect
PLATFORM_HOSTYesPublic base host. The container exits on startup if this is unset (packages/api/cmd/entrypoint.sh).
PLATFORM_HTTPSNotrueSelects https vs http in generated URLs.
PLATFORM_PORTNounsetPort included in generated URLs; omitted automatically when it is 80 or 443.

The resulting origin is "{protocol}://{PLATFORM_HOST}{:PORT?}". So:

  • A standard HTTPS deployment on :443PLATFORM_HTTPS=true, PLATFORM_PORT unset → https://your.host
  • A deployment exposed on a non-standard public port → set PLATFORM_PORT to the port users actually connect to, so generated links and subdomain URLs are correct

[!IMPORTANT] Set PLATFORM_HOST, PLATFORM_HTTPS, and PLATFORM_PORT to match how users reach the instance through your proxy, not how the container is reached internally. These values drive the URLs embedded in the UI, app iframes, and worker calls. See Environment Variables.

The application validates inbound hosts against this configuration. For tunnel requests, for example, the tunnel-auth controller rejects any request whose Host does not end in PLATFORM_HOST (packages/api/src/docker/controllers/tunnel-auth.controller.ts). This is why the external proxy must preserve the original Host.

The container’s bundled Nginx already sets forwarded headers when it proxies to Lombok’s internal services (Host, X-Real-IP, X-Forwarded-For, X-Forwarded-Proto) and performs WebSocket upgrades for Socket.IO, app servers, bridge attach, and tunnels (packages/api/nginx/nginx.conf). That behavior is internal to the image and you do not configure it.

For an external proxy in front of the container, the requirements clearly supported by the source are:

  • Preserve the original Host header. Routing is done by Host, and the app validates inbound hosts against PLATFORM_HOST. Rewriting Host to the upstream/container name will break subdomain routing and tunnel auth.
  • Forward the apex and all *.PLATFORM_HOST subdomains to the container’s HTTP port. The image listens on port 8080; confirm the actual published port against your compose or runtime configuration.
  • Support WebSocket upgrades end-to-end. Live features such as Socket.IO, bridge session attach, and tunnels rely on upgrade passthrough.

[!NOTE] Lombok derives its own scheme and port from PLATFORM_HTTPS and PLATFORM_PORT, not from X-Forwarded-Proto. We did not find any trust proxy / forwarded-protocol handling in the API. In practice, this means the headers your external proxy sets do not change the URLs Lombok generates — setting PLATFORM_* correctly is what matters.

The bundled Nginx serves plain HTTP on port 8080 and contains no TLS configuration. TLS is therefore expected to terminate in front of the container — at your reverse proxy or load balancer — which then forwards plain HTTP to the container.

When TLS terminates in front:

  • set PLATFORM_HTTPS=true so generated URLs use https
  • ensure your certificate covers both PLATFORM_HOST and *.PLATFORM_HOST

[!NOTE] When PLATFORM_HTTPS is true, the tunnel-auth cookie is issued as SameSite=None; Secure (packages/api/src/docker/controllers/tunnel-auth.controller.ts). A Secure cookie is only stored by browsers over HTTPS, so cross-subdomain tunnel auth depends on real HTTPS to the browser.

Variables that are not part of the external proxy contract

Section titled “Variables that are not part of the external proxy contract”
  • APP_UI_HOST — an internal upstream that the bundled Nginx proxies app UI traffic to. It is not an external-facing setting and most operators never change it.
  • BRIDGE_TUNNEL_DOMAIN — this variable is accepted by the configuration schema, but in the inspected source it is not returned by the config object and is not read elsewhere. Treat it as having no observable effect today, and do not rely on it to host tunnels on a domain different from PLATFORM_HOST.

To stay grounded in the source, this page deliberately does not provide:

  • a canonical Caddy, Traefik, or public Nginx configuration
  • generic reverse-proxy hardening or caching advice not specifically required by Lombok’s source
  • any claim that Lombok consumes X-Forwarded-* headers to compute its own origin

If a behavior here matters for your deployment and you need certainty beyond what this page states, the authoritative sources are packages/api/nginx/nginx.conf, packages/api/cmd/entrypoint.sh, and the config modules under packages/api/src/**/config/.