Fix rate limiting behind Render proxy (trust proxy)#50
Merged
Conversation
Render forwards the client IP via X-Forwarded-For through a single reverse proxy. With Express's default trust proxy=false, express-rate-limit throws ERR_ERL_UNEXPECTED_X_FORWARDED_FOR and cannot key requests by client IP. Trusting exactly one proxy hop resolves the error without trusting a spoofable header chain. Verified: a request with X-Forwarded-For to the rate-limited /api/login route no longer throws.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Reviewer's guide (collapsed on small PRs)Reviewer's GuideConfigures Express to trust a single proxy hop so express-rate-limit can safely use X-Forwarded-For behind Render’s reverse proxy, resolving ERR_ERL_UNEXPECTED_X_FORWARDED_FOR on rate-limited routes. Sequence diagram for request handling with trust proxy and express-rate-limitsequenceDiagram
actor Client
participant RenderProxy
participant ExpressApp
participant rateLimit
Client->>RenderProxy: HTTP /api/login
RenderProxy->>ExpressApp: Forward request
ExpressApp->>ExpressApp: app.set(trust_proxy, 1)
ExpressApp->>rateLimit: rateLimit(req, res, next)
alt before_trust_proxy
rateLimit->>rateLimit: req.ip uses remoteAddress
rateLimit-->>ExpressApp: ValidationError ERR_ERL_UNEXPECTED_X_FORWARDED_FOR
ExpressApp-->>Client: 500 or misbehaving response
else after_trust_proxy_1
rateLimit->>rateLimit: req.ip uses X-Forwarded-For (first hop)
rateLimit-->>ExpressApp: next()
ExpressApp-->>Client: 401 (normal rate-limited auth flow)
end
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - I've left some high level feedback:
- Consider making the
trust proxysetting configurable (e.g., via an environment variable) so deployments with a different proxy topology than Render can adjust the hop count or disable it without code changes.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- Consider making the `trust proxy` setting configurable (e.g., via an environment variable) so deployments with a different proxy topology than Render can adjust the hop count or disable it without code changes.Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
On Render the app boots but logs
ValidationError: ERR_ERL_UNEXPECTED_X_FORWARDED_FORon rate-limited routes:Render terminates TLS at a reverse proxy and forwards the client IP via
X-Forwarded-For. With Express's defaulttrust proxy=false,express-rate-limit(added in #48) can't determine the real client IP and throws, so rate-limited routes (/api/login,/api/register,/api/auth/*,/api/*) misbehave.Fix
One line after
const app = express():Trusting exactly one proxy hop (not
true) lets rate-limiting key on the real client IP without trusting a spoofableX-Forwarded-Forchain — the configurationexpress-rate-limitrecommends for single-proxy PaaS hosts like Render.Verification
node --check server.jspasses.X-Forwarded-For: 203.0.113.7to the rate-limited/api/login: returns a normal401and produces zeroERR_ERL_UNEXPECTED_X_FORWARDED_FOR/ValidationErrorlog entries (previously threw on every such request).https://claude.ai/code/session_01Db78Ftpd21HmNSHHi6hwYS
Generated by Claude Code
Summary by Sourcery
Bug Fixes: