Client IPs in logs are all 10.x private addresses and IP rate limiting counts the whole site as one person—which part of the forwarded header should I take?
Conclusion first: When client IPs in logs show 127.0.0.1, 10.x.x.x, or load balancer private addresses, in most cases the proxy did not lose the IP. Instead, the application is reading the TCP connection source address, and that connection was initiated by the proxy. The real user IP is usually written by the proxy into a forwarding header such as X-Forwarded-For (XFF for short), but it is a concatenable text string. The left end comes from the client and can be spoofed. The value should be counted from right to left according to the number of trusted proxy layers, or the ingress proxy should uniformly rewrite it into a single-value header, and the application should read only that one header. If the value position is wrong, IP-based rate limiting, risk-control blacklists, and audit attribution will all be distorted.
1. Which layer replaces the source address?
A common external request path is browser → CDN or load balancer → Nginx → application. The peer address the application sees on the socket is the machine that initiated the connection, that is, the proxy itself. If the proxy and application are on the same machine, this address is 127.0.0.1; if the proxy is in a container or private network, it is usually a private range such as 10.x.x.x or 172.16.x.x. These addresses appearing in logs are a normal result of the link structure, not a network failure.
Whether you need the real IP depends on whether the business relies on determining whether requests come from the same visitor. IP-based rate limiting, risk-control bans, region statistics, and customer support locating complaining users all fall into this category. If you keep using the connection source address, rate limiting will count all visitors as the same person, and bans may affect the entire proxy.
How the forwarding header grows layer by layer
A common Nginx directive is proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;. Its semantics are to keep the existing XFF in the request and then append the source address of the current connection to the end. After multiple proxy layers, this header becomes a string such as client-supplied value, proxy 1 address, proxy 2 address.
- The left part comes from the request header supplied by the client and can be filled in freely. If the proxy keeps it as is, the backend sees a polluted value.
- The right end is appended by proxies at each layer. The verifiable part is here, and the value should be counted from the right according to the number of trusted layers.
- When the number of proxy layers changes, for example after adding a CDN layer, the value position must be adjusted accordingly. Otherwise, a proxy may be mistaken for the real visitor.
2. Count trusted proxy layers first, then decide which segment to take
This is not as simple as choosing a header name. First confirm how many proxy layers between the visitor and the application are under your control. Align on the following three steps during review; changing the order easily causes rework.
- Count proxy layers: list the forwarding nodes between the visitor and the application. A typical setup is CDN plus internal load balancer, and the common range is 1 to 3 layers. If the layer count is uncertain, capture the headers of one real public request before deciding, rather than relying on memory.
- Draw the trusted boundary: count only proxies you control that will rewrite or append forwarding headers. Do not count the client or uncontrollable third-party nodes. This step determines which value from the right is usable.
- Define the value position: take the value from right to left according to the trusted layer count, or have the ingress proxy uniformly rewrite it into a single-value header such as X-Real-IP, and let the application read only that one. Choose one approach; do not mix them.
The three common routes can be chosen according to team conditions. The amount of change and trustworthiness differ considerably:
- Route A (take the left end of XFF directly): Minimal backend change, reading only one value; but it is not trustworthy for external services. Spoofing one header can bypass IP-based rate limiting. This is usually only for internal networks or debugging environments.
- Route B (take from right to left according to trusted layers): More common in self-hosted reverse proxy scenarios, with a clear basis for judgment; the cost is that when the proxy layer count changes, code or configuration must be updated in sync, and the layer count needs to be recorded in the same document.
- Route C (ingress proxy rewrites to a single-value header): Application-side logic is simple and recognizes only one header; it depends on correct ingress configuration. In cloud environments, follow each vendor's official documentation rather than copying another vendor's configuration.
For experience range, projects with few access nodes (1 to 2 layers) can converge easily with either B or C, usually aligning after one round of verification. For projects with many access nodes and slow cross-team changes, a common practice is to first fix ingress rewriting (C) to reduce uncertainty on the application side.
3. Logs, rate limiting, and risk control: three definitions, plus a field note
The same real IP has different requirements in these three places: logs care about whether a person can be located, rate limiting cares about whether it can be spoofed and bypassed, and risk control and audit need to leave a basis for judgment. The unified definition can be remembered as one sentence: the ingress proxy is responsible for stripping and rewriting, and the application trusts only the rewritten value.
- Logs: record the parsed trusted IP, and keep the original header when necessary for troubleshooting; the original header may contain personal information, so truncate or mask it according to compliance requirements before output.
- Rate limiting: the ingress first clears or overwrites the forwarding header supplied by the visitor, then counts by trusted IP. Otherwise, spoofing one header is like bringing your own key.
- Risk control and audit: when keeping link information, mark which hops are trusted proxies, so that months later you can still explain the value rules used at the time.
- IPv6 and storage: addresses are longer, so reserve field width for the full address. A common practice is to reserve around 45 characters, and confirm the parsing library supports it to avoid truncation at the storage layer.
A common field situation is this: the project schedule is tight, there is only one Nginx and two applications, testing reports that logs are all 10.0.0.2, and the client does not want to change the network topology. The constraints are not adding a forwarding layer and not extending the schedule. The approach is to explicitly rewrite X-Real-IP in the Nginx forwarding section, change the application to read only this header, and verify logs with one real public request before launch. The cost is that if only Nginx is changed but the application read method is not changed, another round of rework is needed, and logs still show the proxy address. Such problems often stay hidden until operations notices abnormal rate limiting.
4. Applicable and non-applicable boundaries
- Suitable: external services with CDN, load balancer, or Nginx reverse proxy; need IP-based rate limiting, bans, region statistics; have audit trace or customer support location requirements.
- Not necessary: pure internal admin backends, single-machine direct connections, systems that do not make any judgment by IP; when the proxy chain is uncontrollable and layer counts cannot be aligned, forced parsing increases the chance of taking the wrong hop.
- Common pitfalls: only adding forwarding headers without changing application read logic; not updating the layer count after multi-level proxying; treating a visitor-supplied header as real; different environments having different layer counts but sharing one set of value code.
One boundary is worth remembering: if the application and proxy are in the same trusted network, and the business does not need to distinguish visitors by IP, directly recording the connection source address is actually simpler. Extra parsing of forwarding headers only introduces the risk of taking the wrong hop. According to common 2026 delivery habits, as long as an external service has a reverse proxy or load balancer, it is usually recommended to fix the real IP definition at the ingress first. Adding rate limiting and risk control later will cost more rework than unifying the definition from the start.
Frequently asked questions
I already added X-Forwarded-For in Nginx, but why do logs still show 127.0.0.1?
In most cases, the application still reads the connection source address and does not read the forwarding header; it is also possible that proxy_set_header was written at a level where it does not take effect. Checking segment by segment along the request path usually finds it.
Can the leftmost IP in X-Forwarded-For be treated as the real user?
Not recommended. The left end comes from the request header supplied by the visitor and can be filled in arbitrarily; only values appended by trusted proxies are verifiable. The value position should be counted from right to left according to the trusted layer count.
If IP-based rate limiting directly uses the forwarding header, can it be bypassed?
Yes. The requester can spoof one header and change identity, so the ingress proxy should first strip or overwrite the visitor-supplied value, and then rate limiting should count by the reset trusted IP.
How should IPv6 visitor addresses be stored in logs?
First confirm whether the proxy passes through the full address. Reserve space for fields and parsing libraries according to the full IPv6 address. A common practice is to reserve around 45 characters to avoid location failures caused by storage truncation.
To act in an existing project, you can first uniformly rewrite the real IP at the ingress proxy, then verify logs with one real public request, and only after confirmation consider rate limiting and risk-control rules. This approach applies to services with a reverse proxy that need to make judgments by IP; systems that are pure internal direct connections and do not distinguish visitors by IP do not need to introduce extra parsing logic just to look standardized.
-
Deleted logs but df still shows 100%—if the process isn't restarted, will the space never come back?
Date: Oct 22, 2026 Read: 8
-
The backend hides the export button, but a regular account can still export everything by changing a request—is page-level permission enough?
Date: Oct 21, 2026 Read: 13
-
Excel Import Shows Phone Numbers as 1.39E+10 and Dates as 45000—Is the File Corrupted?
Date: Oct 20, 2026 Read: 16
-
Portrait photos look upright on the web but sideways in App list thumbnails—should I fix the frontend or the server first?
Date: Oct 19, 2026 Read: 18
-
The activity page shows a start time 8 hours earlier than the backend configuration, and the database stores UTC—which layer should be fixed first?
Date: Oct 18, 2026 Read: 22




