Trust proxy
When Ingenium sits behind a reverse proxy (nginx, Caddy, a CDN, a load balancer), ctx.ip defaults to the socket peer - which is the proxy, not the client. The trustProxy option tells Ingenium how far down the X-Forwarded-* chain to trust.
Configuring
const app = ingenium({ trustProxy: 'loopback' })
// Then in handlers:
ctx.ip // real client IP after walking the X-Forwarded-For chain
ctx.protocol // 'https' if X-Forwarded-Proto: https
ctx.hostname // X-Forwarded-Host (if set), else Host header
This mirrors Express's app.set('trust proxy', ...):
| Value | Behavior |
|---|---|
false (default) | Never trust XFF - ctx.ip is the socket peer |
true | Trust the entire chain - leftmost XFF entry wins |
number n | Trust n upstream hops |
'loopback' | Trust 127.0.0.0/8, ::1 |
'linklocal' | Trust 169.254.0.0/16, fe80::/10 |
'uniquelocal' | Trust 10/8, 172.16/12, 192.168/16, fc00::/7 |
'10.0.0.0/8' (CIDR) | Trust matching addresses |
string[] | Multiple of any of the above |
(ip, hopIdx) => boolean | Custom predicate |
Note: The default
ingenium.rateLimitkeygen readsX-Forwarded-Forviactx.ip. Make suretrustProxyis set correctly before relying on rate limiting in production, or attackers can spoof the header.
What gets affected
When trustProxy is enabled, the following ctx fields become XFF-aware:
ctx.ip- the resolved client IP after walking the chain.ctx.ips- the full forwarded chain (read-only array).ctx.protocol-'https'ifX-Forwarded-Protosays so.ctx.secure- boolean shortcut forctx.protocol === 'https'.ctx.hostname-X-Forwarded-Host(if set), else theHostheader.
ctx.remoteAddress always reports the immediate socket peer, regardless of trustProxy. ctx.baseProtocol reports the underlying transport (http vs https).
Where to next?
- IngeniumContext - where all of these fields live.
- Rate limit - why
trustProxymatters for the default keygen. - Production hardening - wiring trust-proxy in production.
- CORS - origin checks against
ctx.protocol/ctx.hostname.