Menu
svelte-smol docs

These are the canary docs, read from main: they can describe changes no release has shipped yet. Read the v1.8.4 docs.

Reverse Proxy

Behind a proxy, the server sees the proxy's connection, not the browser's. Tell it where the real URL and client address come from.

#Request URL

SvelteKit needs the public URL for url.origin, redirects and its CSRF check on form actions. Pick one:

  • ORIGIN — simplest when the app lives at a single public URL:

    ORIGIN=https://my.site

    Read at runtime; on SvelteKit 3 it overrides paths.origin.

  • Forwarded headers — when the app answers on several hosts:

    PROTOCOL_HEADER=x-forwarded-proto
    HOST_HEADER=x-forwarded-host

With neither set, the protocol defaults to https and the host comes from the Host header.

Remote function calls (/_app/remote/…) are the exception: when the browser's Origin matches the request's host, that origin is used as-is, so they pass SvelteKit's CSRF check even when ORIGIN points elsewhere.

#Client address

event.getClientAddress() returns the socket address by default. Behind a proxy, read it from a header instead:

ADDRESS_HEADER=x-forwarded-for
XFF_DEPTH=1

XFF_DEPTH is the number of trusted proxies in front of the app: the address is taken that many entries from the right of X-Forwarded-For, so a client can't spoof it by sending its own header. With ADDRESS_HEADER set, a request missing that header throws — only set it when every request goes through the proxy.

#Unix socket

Proxies on the same host can skip TCP:

SOCKET_PATH=/run/app.sock
location / {
  proxy_pass http://unix:/run/app.sock;
  proxy_set_header Host $host;
  proxy_set_header X-Forwarded-Proto $scheme;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

#WebSockets and SSE

Both work through the proxy as long as it forwards Upgrade / keeps long-lived responses open. The server itself disables its idle timeout for text/event-stream responses.

This guide lives in the project repo: edit it there, and this page follows within a day.