HTTPS and redirects
Every automatic hostname and every verified custom domain gets a valid certificate with no configuration. The minimum TLS version is 1.2. A plain HTTP request gets a308 Permanent Redirect to the https:// URL. A 308 keeps the method and body, so a client that follows it resends a POST as a POST. Your app never sees plain HTTP traffic.
Which deployment answers
The hostname decides. Each hostname points at one deployment. Promote and rollback move the hostnames that follow the live deployment, and the change reaches every region within a few seconds. So a few requests can still reach the old deployment right after you promote. Automatic domains lists which hostnames move. A hostname that doesn’t point at any deployment gets404 and config_not_found.
A request is served in the region that received it, if the deployment has running instances there. Otherwise it goes to the nearest region that does. If no region has one, the caller gets 503 and no_running_instances. See Regions.
A request only moves to another instance if the first couldn’t be reached at all. Your handler never runs twice for one request.
Policies run first
Before the request is forwarded, the deployment’s policies run. A request a policy rejects never reaches your app and doesn’t appear in the request log. See Gateway policies.Protocols, timeouts, and sizes
The gateway talks to your app over HTTP/1.1 or h2c, set by the upstream protocol in runtime settings. Responses stream to the caller as your app writes them, so server-sent events work without buffering. A request has 15 minutes to finish. After that, the caller gets504 with err:user:bad_request:request_timeout. (That code’s own page describes the Unkey API’s shorter limit and 408, which don’t apply here.) If the gateway times out waiting for your app, the caller gets 504 gateway_timeout instead. Neither limit applies to WebSockets.
There’s no limit on request or response body size. A logging policy saves at most 1 MiB of each body, but that only affects the log.
Your app’s responses pass through unchanged, including your own 4xx and 5xx responses.
Headers your app receives
Callers can’t fake the
X-Unkey-* headers, including X-Unkey-Principal: we remove any they send. Every other header arrives unchanged. To know which deployment you’re in, read the UNKEY_DEPLOYMENT_ID environment variable.
Headers the client receives
Headers your app sets are passed to the client unchanged.
Errors callers can get
When the gateway rejects a request or can’t reach your app, it responds with JSON if the client accepts it, or an HTML page if the client preferstext/html:
/errors/frontline. When the gateway can’t reach your app, the caller gets one of these:
A client that disconnects before the response starts is logged as
client_closed_request. Gateway errors lists every code.