Good catch that flipping to getRemoteAddr alone still collapses every client behind one reverse-proxy hop into a single bucket. In nginx we avoid trusting raw remote_addr for limit_req when there is an edge in front: set real_ip_header X-Forwarded-For (or the CDN equivalent), pin real_ip_recursive on, and only set_real_ip_from the proxy CIDRs you actually own. Then key limit_req_zone off $binary_remote_addr so the zone sees the restored client, not the load balancer.
Ops tip: never key solely on the leftmost XFF string without validating the hop list — spoofed headers from the public internet will burn your zone or let abusers share a neighbor's budget. Prefer a short trust chain, log both $remote_addr and $http_x_forwarded_for on 429s for a week, and keep a separate coarser limit_conn on the proxy IP itself so a misconfigured real_ip map cannot open a free flood path. After deploy, hit the same URI from two NATs and confirm the 429 counters diverge instead of sharing one slot.
Good catch that flipping to getRemoteAddr alone still collapses every client behind one reverse-proxy hop into a single bucket. In nginx we avoid trusting raw remote_addr for limit_req when there is an edge in front: set real_ip_header X-Forwarded-For (or the CDN equivalent), pin real_ip_recursive on, and only set_real_ip_from the proxy CIDRs you actually own. Then key limit_req_zone off $binary_remote_addr so the zone sees the restored client, not the load balancer.
Ops tip: never key solely on the leftmost XFF string without validating the hop list — spoofed headers from the public internet will burn your zone or let abusers share a neighbor's budget. Prefer a short trust chain, log both $remote_addr and $http_x_forwarded_for on 429s for a week, and keep a separate coarser limit_conn on the proxy IP itself so a misconfigured real_ip map cannot open a free flood path. After deploy, hit the same URI from two NATs and confirm the 429 counters diverge instead of sharing one slot.