DomaineeDocs

Request headers

What we add to a proxied request before it reaches your origin, and how to read the visitor's IP reliably.

Every request we proxy to your origin carries a set of forwarding headers describing the original visitor and the hostname they asked for. The request body, method, path, query and your customer's own headers pass through untouched.

What we send

x-forwarded-for: 203.0.113.42
x-real-ip: 203.0.113.42
x-domainee-client-ip: 203.0.113.42
x-forwarded-host: shop.acme.com
x-forwarded-proto: https
x-domainee-edge: 1
x-domainee-incoming-host: shop.acme.com
HeaderMeaning
x-forwarded-forThe visitor's IP address.
x-real-ipThe same address, for frameworks that read this one.
x-domainee-client-ipThe same address again. Read this one. See below.
x-forwarded-hostThe hostname the visitor requested, not your origin's hostname.
x-forwarded-protoAlways https for proxied traffic.
x-domainee-edgeAlways 1. Lets you tell Domainee traffic from direct traffic.
x-domainee-incoming-hostSame value as x-forwarded-host, under a name nothing else rewrites.
x-domainee-origin-secretOnly when you turn on the origin secret.

Reading the visitor's IP

Read x-domainee-client-ip first and fall back to x-forwarded-for:

const clientIp =
  req.headers["x-domainee-client-ip"] ||
  req.headers["x-forwarded-for"]?.split(",")[0]?.trim();

The reason for the third header is that x-forwarded-for and x-real-ip are well-known names, and the platform your origin runs on may rewrite them before your application code runs. Most managed hosts terminate connections at their own edge and set these headers from the address that connected to them, which for proxied traffic is us rather than your visitor. When that happens there is nothing we can put in those two headers that your app will actually see.

x-domainee-client-ip is not a name any platform edge recognises, so it arrives intact. If your host leaves the standard headers alone, all three agree and it makes no difference which you read.

Do not trust these headers on requests that did not come from us. Any client can send a header with any name. If your origin is reachable directly as well as through Domainee, turn on the origin secret and reject requests that don't carry it. Our edge addresses change on every deploy, so an IP allowlist won't hold up.

Verifying requests came through Domainee

Turn on Origin secret in your workspace settings. From then on, every request we proxy to an origin in that workspace carries one more header:

x-domainee-origin-secret: dos_...

The value is a random secret only you and our edge know. We drop any x-domainee-origin-secret a visitor sends before forwarding, so the only way a request reaches you with the right value is through us. Check it in constant time and refuse anything else:

import crypto from "node:crypto";
 
function cameThroughDomainee(req) {
  const got = Buffer.from(req.headers["x-domainee-origin-secret"] ?? "");
  const want = Buffer.from(process.env.DOMAINEE_ORIGIN_SECRET);
  return got.length === want.length && crypto.timingSafeEqual(got, want);
}

Once a request passes, x-domainee-incoming-host tells you which of your customers' domains it was for.

The secret is per workspace, so one value covers all its domains. It is off by default; only the workspace owner can turn it on, rotate it or turn it off. Changes reach the edge within about a minute, so when you rotate, accept both the old and the new value for a minute or two before dropping the old one.

The check only works where server code sees the request. A purely static site never sees request headers; there, look up the site from the browser's hostname instead.

Host header

By default we rewrite Host to your origin's hostname so origin servers that do virtual-host routing don't reject the request. The hostname your visitor asked for is always available in x-forwarded-host.

If your application routes on Host itself and needs the original value, turn on keepHost for the domain and we will pass the visitor's hostname through unchanged. x-forwarded-host is set either way.

Apex and subdomain traffic

Both DNS paths produce identical headers at your origin. A domain connected with A records at the apex and one connected with a CNAME to edge.domainee.dev enter our network differently, but the request your origin receives is the same shape in both cases.

On this page