How do I see the real client IP on the backend?
Short answer
In an HTTP vService, the X-Forwarded-For option is enabled and the server is configured to read this header. For TR7 to connect to the server with the client's IP without depending on the header, Use Client IP is selected in the SNAT field of the Backend Service; for this, the responses must return from TR7 (the server's default gateway is TR7, or Spoofing is on). If the server supports it, the PROXY protocol is used with the Proxy field of the Backend Service, and in a Network vService, Route Mode or Direct Server Return is used as the LB Mode. If the server expects a header with a different name, a header such as X-Real-IP is added with the Add HTTP Header action.
Problem: Only TR7's IP Is in the Server Logs
Since the Backend Service receives the connection from TR7, the logs, access controls and the application cannot see the client's real address; geographic restrictions on the server do not work, per-IP request limits count all users as a single address, and security decisions are made with wrong data. Details of the cause: Why do my backend servers see all requests as coming from TR7's IP?
Solution: Five Methods
The real client IP is carried to the Backend Service in five ways. The methods are alternatives to each other; they are selected according to the network layout, the vService type and what the server supports.
| Your situation | Suitable method |
|---|---|
| HTTP vService; I don't want to change the network layout | Method 1: X-Forwarded-For |
| L7 TCP vService; the network layout is suitable for putting TR7 on the return path | Method 2: SNAT → Use Client IP |
| HTTP or L7 TCP; the server supports the PROXY protocol (Nginx, Apache, Postfix…), the network will not change | Method 3: PROXY Protocol |
| Network vService (TCP - L4 / UDP - L4) | Method 4: LB Mode in a Network vService |
| The application cannot read an HTTP header and must see the IP from the connection | Method 2: SNAT → Use Client IP |
HTTP; the server expects a header with a different name (e.g. X-Real-IP) | Method 5: Add HTTP Header Action |
| There is a CDN or another proxy in front of TR7 | First, the real IP is resolved with Trusted Proxy, then Method 1 → There is a CDN such as Cloudflare / Akamai in front of TR7; how do I get the Real client IP (trusted proxy)? |
Method 1: X-Forwarded-For Recommended
- How it works TR7 adds the
X-Forwarded-Forheader to every request it forwards to the Backend Service and writes the real client IP into it. The connection still comes from TR7. - Where it is opened vService → Details → X-Forwarded-For
- Requirement No change is required in the network. The Backend Service is configured to read the header (step 5).
- vService type Only HTTP
- If the request already has XFF It is not deleted; TR7 appends the address it sees to the end of the chain.
Step-by-Step Configuration
The Load Balancer → Load Balancer vService List steps are followed, and the HTTP vService on which X-Forwarded-For will be enabled is opened. The same form is also used when a new vService is created.
The Details button at the top of the form is clicked. This panel is closed by default; when it is clicked, the advanced options are listed on the right side.
X-Forwarded-For is enabled from the Details list. This option is a single on/off option; when it is enabled, no sub-setting or additional field opens.
The Save button is clicked. The setting takes effect as soon as it is saved.
TR7 adds the header; using the header is the job of the Backend Service. If the server is not configured to read the X-Forwarded-For value as the client IP, TR7's address still appears in the logs. Configuration for Nginx, Apache and IIS: How is X-Forwarded-For enabled; what do I need to do on the backend side (Apache / Nginx / IIS logs)? The server must take the header into account only in connections coming from TR7's IP address.
Verification
The vService is put into the Debug Mode state. The Debug Logs of the related vService are opened, the record is clicked, and the Header Info list in the Request tab is examined.
X-Forwarded-For: 198.51.100.45If the client has not sent XFF, the line appears green (added); if it has, it appears yellow (modified).
The raw content of the request coming from TR7 is captured on the server. For example, for port 80:
tcpdump -A -s0 'tcp dst port 80' | grep -i x-forwarded-forX-Forwarded-For: 198.51.100.45Method 2: SNAT → Use Client IP
- How it works When connecting to the Backend Service, TR7 uses the client's real IP as the source address. The IP is carried not with a header but with the connection itself (L4).
- Where it is openedBackend Service → Details → SNAT → Use Client IP
- Requirement The response traffic of the Backend Service must return through TR7: the default gateway is made TR7, or Spoofing is enabled (step 4). If this is not ensured, the responses bypass TR7 and the connection is not completed.
- vService typeHTTP, L7 TCP (this field is not used in a Network vService; see Method 4)
- Backend Service side No additional configuration is required; the IP appears directly.
Step-by-Step Configuration
The Load Balancer → Backend Services steps are followed, the related Backend Service is selected, and the Edit button is clicked. The button is enabled only while a single Backend Service is selected.
The Details switch at the bottom of the form is turned on. The switch is off by default; the SNAT and Spoofing fields are in this section.
Use Client IP is selected in the SNAT field. The other options: Default (default; the source address is the Interface IP of the interface the traffic to the server leaves from in the Backend Service's Route table, in the same subnet as the server (or as the gateway, if the server is reached through a gateway)) and Use Device IP (the selected TR7 IP becomes the source).
One of two ways is applied:
- Default gateway TR7: The default gateway of the Backend Service is made TR7. This change is made on the server side; no additional field is required in TR7.
- Spoofing: If the gateway cannot be changed, Spoofing is enabled in the same form (it is displayed only while Use Client IP is selected; off by default). TR7 pulls the response traffic to itself by performing ARP spoofing on the network of the Backend Service. If Spoofing IP is left empty, the default gateway of the route table is targeted. In a Cluster setup, Spoofing IP VIP Condition ensures that spoofing runs on the device where the VIP is active.
The Edit button at the bottom of the form is clicked. All the vServices that use the same Backend Service inherit this behavior.
Verification
The server's access log is checked. The source address column must now show the IP of the client, not TR7's.
198.51.100.45 - - "GET / HTTP/1.1" 200The source address of incoming connections is captured on the server. For example, for port 80:
tcpdump -n 'tcp dst port 80 and tcp[tcpflags] & tcp-syn != 0'IP 198.51.100.45.51234 > 192.0.2.20.80: Flags [S]Method 3: PROXY Protocol
- How it works At the very beginning of every connection it opens to the Backend Service, TR7 sends the client's IP and port information with a PROXY protocol header; the server reads this header and uses it as the client IP.
- Where it is opened Backend Service → Details → Proxy → Proxy (v1) or Proxy v2
- Requirement The Backend Service must support the PROXY protocol and be configured to expect it; the health check must be of the TCP type or be performed on a separate port; no change is required in the network
- vService type HTTP, L7 TCP
Step-by-Step Configuration
The Backend Service is configured to expect the PROXY protocol header (examples in the panel below). If it is enabled in TR7 before the server is prepared, the server mistakes the header for application data and the connections fail.
TR7's health checks do not send the PROXY protocol header; an HTTP-type health check is rejected on the port that expects the header, and the Backend Service appears down. For this reason, a TCP-type health check is assigned to the Backend Service, or a separate health port that does not expect the PROXY protocol is checked with Use Different IP for Health Check in step 7. If there is no TCP-type profile, Load Balancer → Profiles → Health Checks → Add is clicked (how to add); if the profile already exists, steps 2–4 are skipped.
Name is entered and Check Type = TCP is selected (the default is HTTP; the type cannot be changed after saving).
The Add button in the form is clicked.
The Load Balancer → Backend Services steps are followed, the Backend Service is selected, and the Edit button is clicked.
The Details switch at the bottom of the form is turned on; the Proxy field is in this section.
The version the server supports is selected in the Proxy field: the text-based Proxy (v1) or the binary Proxy v2. The default is No Proxy. In the Health Check field, the TCP-type profile is selected, or Different Address is selected in the Use Different IP for Health Check field and the health address and port that do not expect the PROXY protocol are entered.
The Edit button at the bottom of the form is clicked. All the vServices that use the same Backend Service inherit this behavior.
In the examples, the IP address from which TR7 connects to the Backend Service is written instead of 192.0.2.10.
server {
listen 80 proxy_protocol;
set_real_ip_from 192.0.2.10;
real_ip_header proxy_protocol;
}# mod_remoteip (Apache 2.4.31+)
RemoteIPProxyProtocol On# main.cf
smtpd_upstream_proxy_protocol = haproxyOnly in connections coming from TR7
A port that expects the PROXY protocol rejects connections coming from clients that do not send the header. This port is kept open only to TR7's connections.
Verification
The source address column in the server's access log is checked.
198.51.100.45 - - "GET / HTTP/1.1" 200Method 4: LB Mode in a Network vService
- How it works A Network vService does not terminate the connection. In Route Mode, only the destination address of the packet is changed, and in Direct Server Return, it is not changed at all; in both modes, the source address remains the client's IP.
- Where it is opened Network vService → LB Mode → Route Mode or Direct Server Return
- Requirement Route Mode: the return traffic of the Backend Service must pass through TR7 · Direct Server Return: the Backend Service must be in the same L2 segment as TR7 and be prepared to accept the vService address
- vService type Network (TCP - L4, UDP - L4)
Step-by-Step Configuration
The Load Balancer → Load Balancer vService List steps are followed, and the Network vService is opened.
Route Mode or Direct Server Return is selected in the LB Mode field. Since the SNAT mode changes the source address, the client IP is not forwarded.
In Route Mode, the default gateway of the servers is made TR7 (Why does return traffic have to flow through TR7 in Route Mode?). In Direct Server Return, the vService address is defined on the server as a local address, and the ARP response for this address is turned off (What is Direct Server Return (DSR); what preparation is needed on the server side?).
The Save button is clicked. In a Network vService, every save restarts the vService; the change is made at a low-traffic time.
Verification
tcpdump -n 'tcp dst port 80 and tcp[tcpflags] & tcp-syn != 0'IP 198.51.100.45.51234 > 192.0.2.20.80: Flags [S]Method 5: Add HTTP Header Action
- How it works The Add HTTP Header action adds a header with the desired name (e.g.
X-Real-IP) to the request; with the Smart Variable%SRCIP(Client IP address) selected with the fx button in the Header Content field, the value of the header becomes the client's IP in every request. - Where it is openedLoad Balancer → Actions → Add → Action Type: Add HTTP Header
- Requirement HTTP vService; the server must be configured to read the header (How is X-Forwarded-For enabled; what do I need to do on the backend side (Apache / Nginx / IIS logs)?)
- vService type HTTP
Step-by-Step Configuration
The Load Balancer → Actions path is followed and Add is clicked.
Action Name is entered; Action Type = Add HTTP Header and Execution Level = On Request (if not selected, it runs at the request stage) are selected, and Header to Add = X-Real-IP is written.
The fx button next to the Header Content field is clicked; in the Add variable window that opens, Connection info - Client IP address (%SRCIP) is selected from the Variable name list and written to the field with Submit.
The Add button is clicked. Since Conditions is left empty, the action is applied to all requests.
On the Load Balancer → Load Balancer vService List screen, the HTTP vService is selected and the edit form is opened with Edit.
The action is selected in the Details → Actions field.
The Save button is clicked. In a cluster, the change is transferred to the peer device automatically by default; if Manual Sync Mode is on, it is sent with Synchronize.
Verification
The client's real IP appears in the server's access log (or the header is seen with tcpdump -A).
Client IPCommon Mistakes
If there is a CDN or proxy in front of TR7
X-Forwarded-For works in the direction from TR7 to the Backend Service. If there is a CDN or proxy in front of TR7, the address TR7 sees is already the address of that intermediate layer, and XFF forwards this address. In this case, the real client IP address is first resolved with Trusted Proxy.
- Selecting Use Client IP and skipping the network condition. If the gateway is not changed and Spoofing is not enabled even though SNAT → Use Client IP is selected, connections are not completed; the site becomes unreachable.
- Not configuring the Backend Service. If the server does not read the header even though XFF is enabled, TR7's IP still appears in the logs.
- Enabling the PROXY protocol without preparing the server. The server interprets the header as application data and the connections fail.
- Using an HTTP health check with the PROXY protocol. The health check is rejected because it does not send the header, and the Backend Service appears down even though it can receive traffic.
- Changing the SNAT field of the Backend Service in a Network vService. This field is used only in HTTP and L7 TCP; in Network, the client IP is preserved with the LB mode.
- Trying to change the name of the X-Forwarded-For header. The header is always added with the name
X-Forwarded-For; if a different name is required, Method 5 is used. - It should not be confused with the option in Traffic Mirroring. The own Add X-Forwarded-For Header option of the Traffic Mirroring action concerns only the copy request sent to the mirror target.
- It is off by default. X-Forwarded-For must be enabled separately in every newly created vService.
How it is done in the documentation
