My login rate limiter worked perfectly in local dev and silently did the wrong thing in production. Behind Netlify’s proxy, req.ip is the proxy’s address — the same value for every visitor — so every per-IP rate-limit key collapsed into one global bucket. One user hitting the limit would lock out everyone; in practice it mostly meant the limiter throttled nobody correctly.
The fix is one middleware that restores the real client IP from the platform’s header before any limiter runs:
app.use((req, _res, next) => {
const real = req.headers["x-nf-client-connection-ip"];
if (typeof real === "string") Object.defineProperty(req, "ip", { get: () => real });
next();
});
Every proxy platform has its equivalent (CF-Connecting-IP on Cloudflare, X-Forwarded-For handling elsewhere). The lesson generalizes: any per-IP logic is broken until you’ve verified what “IP” means on your actual deployment target.