Storyden

SSR Client IP Forwarding

How Storyden preserves browser IP context for SSR API requests and how to configure client IP mode.

When you use the official Storyden Next.js frontend, server-side rendering (SSR) makes API requests from the frontend server, not directly from the browser.

Without SSR client-IP forwarding, the backend only sees the frontend server address for those requests, which can break:

  • rate limiting (many users collapse into one IP key),
  • IP-based moderation controls,
  • diagnostics for proxy/header configuration.

To solve this, Storyden uses an SSR context forwarding flow:

  1. The frontend marks SSR API requests with X-Storyden-SSR: 1.
  2. The frontend forwards X-Forwarded-For unchanged.
  3. The backend resolves client IP using the configured client-IP mode, exactly as it does for browser API calls.
  4. The backend exposes client.ip_address_ssr on session info for SSR diagnostics.

Bundled Storyden Mode

Default fullstack deployment topology is:

browser -> backend -> frontend SSR -> backend

In this mode, the backend is already the edge-facing trust boundary. SSR API requests are internal subrequests that carry the existing network header context.

The frontend does not derive a separate "SSR client IP" value. It forwards standard headers and the backend resolves IP using your selected mode.

UI Settings vs Environment Variables

Client IP settings live in the Admin UI and are applied immediately:

  • client_ip_mode: remote_addr, single_header, or xff_trusted_proxies
  • client_ip_header: trusted header name for single_header
  • trusted_proxy_cidrs: trusted proxy ranges for xff_trusted_proxies

There is no separate SSR secret configuration.

For xff_trusted_proxies mode, SSR-origin API calls can also trust a separate "SSR source" peer address list:

  • SSR_TRUSTED_SOURCE_CIDRS (env): comma/newline-separated CIDRs or IPs.
  • PROXY_FRONTEND_ADDRESS (env): if host is localhost or a literal IP, Storyden auto-trusts it as an SSR source.

This is used only for SSR-marked requests (X-Storyden-SSR: 1) so bundled or externally hosted frontends can forward browser XFF chains without hard-coding loopback trust.

Reverse Proxy Guidance

When running behind proxies/CDNs:

  • ensure your edge proxy strips/overwrites forwarded-IP headers from untrusted clients,
  • configure Client IP mode in Admin settings to match your infrastructure,
  • use the Admin header/IP test tools to validate browser-origin and SSR-origin behavior.

Misconfigured proxies can cause incorrect rate-limit keys and unreliable audit/abuse signals.

Interpreting ip_address_ssr

  • On SSR-origin API calls (X-Storyden-SSR: 1), client.ip_address_ssr is populated with the backend-resolved client IP for that SSR request.
  • On browser-origin API calls, client.ip_address_ssr is always empty.

Comparing browser and SSR values helps diagnose proxy/header configuration issues.

xff_trusted_proxies

Use this mode when Storyden is behind one or more reverse proxies (e.g. Cloudflare, Nginx, Fly.io).

Storyden will use the X-Forwarded-For header to determine the client IP — but only if the request actually came through a trusted proxy.

How it works

  1. Storyden checks the request's RemoteAddr (the immediate peer).
  2. If that IP is not in your trusted proxy CIDRs, Storyden only continues for SSR-marked requests when RemoteAddr is in SSR trusted sources derived from PROXY_FRONTEND_ADDRESS and/or SSR_TRUSTED_SOURCE_CIDRS. Otherwise it is treated as direct and RemoteAddr is used.
  3. If it is trusted, Storyden reads the full X-Forwarded-For chain.
  4. It walks the chain from right to left, skipping any IPs that are also trusted proxies or unparseable.
  5. The first IP that is not a trusted proxy is selected as the client IP.
  6. If all IPs in the chain are trusted proxies (or unparseable), it falls back to RemoteAddr.

For browser-origin requests, only trusted_proxy_cidrs is considered. SSR trusted sources are only used when X-Storyden-SSR: 1 is present.

Why this is safe

  • Prevents attackers from spoofing X-Forwarded-For
  • Only trusts headers added by infrastructure you control
  • Works with multiple proxy layers automatically

Example

RemoteAddr: 10.0.0.5
X-Forwarded-For: 1.2.3.4, 203.0.113.10
trusted_proxy_cidrs:
  - 10.0.0.0/8
  - 203.0.113.0/24

Resolution:

  • 10.0.0.5 → trusted proxy ✅
  • 203.0.113.10 → trusted proxy → skip
  • 1.2.3.4 → not trusted → selected as client IP

When to use this

Use this mode if:

  • You are behind a reverse proxy or CDN
  • You control (or trust) the proxy layer
  • You want accurate per-user rate limiting and logging

When not to use this

  • Your server is directly exposed to the internet → use remote_addr
  • You don’t know your proxy IP ranges → use single_header instead

Tips

  • Always include all proxy layers in trusted_proxy_cidrs
  • Prefer CIDR ranges over individual IPs
  • If misconfigured, you may end up rate-limiting your proxy instead of users

On this page