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:
- The frontend marks SSR API requests with
X-Storyden-SSR: 1. - The frontend forwards
X-Forwarded-Forunchanged. - The backend resolves client IP using the configured client-IP mode, exactly as it does for browser API calls.
- The backend exposes
client.ip_address_ssron 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, orxff_trusted_proxiesclient_ip_header: trusted header name forsingle_headertrusted_proxy_cidrs: trusted proxy ranges forxff_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 islocalhostor 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_ssris populated with the backend-resolved client IP for that SSR request. - On browser-origin API calls,
client.ip_address_ssris 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
- Storyden checks the request's
RemoteAddr(the immediate peer). - If that IP is not in your trusted proxy CIDRs, Storyden only continues for SSR-marked requests when
RemoteAddris in SSR trusted sources derived fromPROXY_FRONTEND_ADDRESSand/orSSR_TRUSTED_SOURCE_CIDRS. Otherwise it is treated as direct andRemoteAddris used. - If it is trusted, Storyden reads the full
X-Forwarded-Forchain. - It walks the chain from right to left, skipping any IPs that are also trusted proxies or unparseable.
- The first IP that is not a trusted proxy is selected as the client IP.
- 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/24Resolution:
10.0.0.5→ trusted proxy ✅203.0.113.10→ trusted proxy → skip1.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_headerinstead
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