From d37a9aca4e5f4a4d91222fe0249fac456ce5cdc2 Mon Sep 17 00:00:00 2001 From: Lee Hanken Date: Sun, 26 Oct 2025 11:32:42 +0000 Subject: [PATCH] Fix rate limiting behind reverse proxy (trust proxy headers) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Critical Fix: - Added app.set('trust proxy', true) to server-http.js - Fixes ValidationError about X-Forwarded-For headers - Allows rate limiting to work correctly on Render/Heroku/etc Problem: - Without trust proxy, Express doesn't recognize real client IPs - All users appear to have the same IP (the proxy's IP) - Rate limiting applied to ALL users as a single entity - One user hitting limit blocks everyone Solution: - Trust X-Forwarded-For headers from reverse proxies - Each user now has their own rate limit bucket - Rate limiting works as designed (50 req/min per IP) Documentation: - Added troubleshooting section in DEPLOYMENT.md - Explains the error and impact - Shows how to verify the fix This is required for any deployment behind a reverse proxy (Render, Heroku, AWS ELB, nginx, etc.) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- DEPLOYMENT.md | 21 +++++++++++++++++++++ server-http.js | 4 ++++ 2 files changed, 25 insertions(+) diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md index 8caa826..5fac63e 100644 --- a/DEPLOYMENT.md +++ b/DEPLOYMENT.md @@ -415,6 +415,27 @@ If legitimate users hit rate limits: - Implement authentication for higher limits - Consider using API keys +### Rate Limiting Not Working (All Users Blocked Together) + +**Error in logs**: +``` +ValidationError: The 'X-Forwarded-For' header is set but the Express 'trust proxy' setting is false +``` + +**Cause**: Server is behind a reverse proxy (Render, Heroku, etc.) but Express doesn't trust proxy headers. + +**Impact**: All users appear to have the same IP address, so they share one rate limit bucket. When one user hits the limit, everyone gets blocked. + +**Solution**: Already fixed in `server-http.js` with: +```javascript +app.set('trust proxy', true); +``` + +If you still see this error: +1. Pull latest code from repository +2. Redeploy to your hosting platform +3. Verify logs no longer show the ValidationError + ### Connection Timeouts If requests timeout: diff --git a/server-http.js b/server-http.js index ad947fe..0e692fa 100644 --- a/server-http.js +++ b/server-http.js @@ -661,6 +661,10 @@ ${match.context} // Create Express app const app = express(); +// Trust proxy headers (required for Render, Heroku, etc.) +// This allows rate limiting to work correctly behind reverse proxies +app.set('trust proxy', true); + // Enable CORS app.use(cors());