How is X-Forwarded-For enabled; what do I need to do on the backend side (Apache / Nginx / IIS logs)?
Short answer
In TR7, X-Forwarded-For is turned on in the Details list of the HTTP vService (off by default); TR7 adds the X-Forwarded-For header carrying the client's IP to every request going to the Backend Service. The header name is fixed; to replace the chain sent by the client with a single value, the Set HTTP Header action is used, and for a header with a different name, the Add HTTP Header action is used, and the content is written by selecting the Client IP address Smart Variable with the fx button. On the server side, the client IP is taken from the header with ngx_http_realip_module in Nginx and with mod_remoteip in Apache; in IIS, the header is added to the log as a custom field with Enhanced Logging.
Problem: The Header Arrives but the Logs Do Not Change
The X-Forwarded-For header carries the client IP to the server, but web servers log the source of the connection (TR7) by default. For the client IP to be visible, the header must be added in TR7 and the server must also read this header. If the server trusts the header unconditionally, a fake value sent by the client itself can also be taken as the client IP; therefore, trust is limited to TR7's address only.
Solution: 3 Methods
The three methods are alternatives to each other; whichever is chosen, the server-side configuration (Server-side configuration) is done separately.
| Your situation | Suitable method |
|---|---|
The standard X-Forwarded-For header is enough | Method 1: X-Forwarded-For |
| I want to delete the chain sent by the client and write a single value | Method 2: Set HTTP Header |
The server expects a header with a different name (e.g. X-Real-IP) | Method 3: Add HTTP Header |
Method 1: X-Forwarded-For Recommended
- How it works TR7 adds the
X-Forwarded-Forheader to every HTTP request going to the Backend Service and writes the client's IP into it. If the request already has an X-Forwarded-For, it is not deleted; the value added by TR7 comes at the end of the chain. If there is a CDN in front and Trusted Proxy is defined, the value written is the real client IP resolved by Trusted Proxy. - Where it is opened HTTP vService → Details → X-Forwarded-For
- Requirement The server reads the header (web server or application setting)
- vService type HTTP
Step-by-Step Configuration
On the Load Balancer → Load Balancer vService List screen, the HTTP vService is selected and the edit form is opened with Edit.
The Details button in the form is clicked; the panel is closed by default.
In the Details list, X-Forwarded-For is enabled (off by default). No additional field opens; the header name is fixed.
The Save button is clicked; the setting takes effect as soon as it is saved. 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.
The server is configured to read the client IP from the header or to write it to the log (Server-side configuration).
Verification
While the vService is in Debug mode, the headers going to the Backend Service are seen in the Request tab of the Debug Mode Logs record.
X-Forwarded-For: 198.51.100.45After the server is configured, the client's IP appears in the access log.
198.51.100.45 - - "GET / HTTP/1.1" 200Method 2: Set HTTP Header
- How it works The Set HTTP Header action writes the
X-Forwarded-Forheader as a single value; the previous values sent by the client are removed. The value is the Client IP address (%SRCIP) Smart Variable selected with the fx button in the Header content field. - Where it is openedLoad Balancer → Actions → Add → Action Type: Set HTTP Header
- Requirement HTTP vService; the X-Forwarded-For option on the vService is off
- vService type HTTP
Step-by-Step Configuration
The Load Balancer → Actions path is followed and Add is clicked.
The Action Name is entered; Action Type = Set HTTP Header, Execution Level = On Request, and Header to Edit = X-Forwarded-For are entered.
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.
On the Load Balancer → Load Balancer vService List screen, the HTTP vService is selected and Edit is clicked.
The action is selected in the Details → Actions field.
The Save button is clicked; then the server side is configured (Server-side configuration).
Verification
When the client sends a request with its own X-Forwarded-For value, the Request tab of the Debug Mode Logs record shows that the header carries a single value.
X-Forwarded-For: 198.51.100.45Method 3: Add HTTP Header
- How it works The Add HTTP Header action forwards the client IP with a header that has a different name (e.g.
X-Real-IP). The value is the Client IP address (%SRCIP) Smart Variable selected with the fx button in the Header content field. - Where it is openedLoad Balancer → Actions → Add → Action Type: Add HTTP Header
- Requirement HTTP vService
- vService type HTTP
Step-by-Step Configuration
The Load Balancer → Actions path is followed and Add is clicked.
The Action Name is entered; Action Type = Add HTTP Header, Execution Level = On Request, and Header to Add = X-Real-IP are entered.
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 (Scenario 1: transmitting the client IP information).
The Add button is clicked.
On the Load Balancer → Load Balancer vService List screen, the HTTP vService is selected and Edit is clicked.
The action is selected in the Details → Actions field.
The Save button is clicked; then the server is configured to read the header (X-Real-IP).
Verification
The new header is seen in the Request tab of the Debug Mode Logs record.
X-Real-IP: 198.51.100.45Server-Side Configuration
Instead of 192.0.2.5 in the examples, the IP address with which TR7 connects to the server is written: with SNAT Default, the Interface IP of the interface through which the traffic to the server leaves in the Backend Service's Route table, in the same subnet as the server (or as the gateway, if it is reached through a gateway); with Use Device IP, the selected SNAT IP. In a cluster, the Interface IPs of both devices are added.
# ngx_http_realip_module (requires --with-http_realip_module at build time)
set_real_ip_from 192.0.2.5;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
# To only write it to the log, inside log_format:
# $http_x_forwarded_for# mod_remoteip
RemoteIPHeader X-Forwarded-For
RemoteIPInternalProxy 192.0.2.5
# In LogFormat, %a is used instead of %h (the resolved client IP).
# To only write it to the log without the module: %{X-Forwarded-For}i
LogFormat "%a %l %u %t \"%r\" %>s %b" commonIIS Manager → site → Logging → Format: W3C → Select Fields...
W3C Logging Fields → Add Field...
Field Name : X-Forwarded-For
Source Type: Request Header
Source : X-Forwarded-For
OK → OK → Actions: ApplyTrust only TR7
TR7 does not delete the X-Forwarded-For value sent by the client; it adds its own value to the end of the chain. In Nginx, set_real_ip_from, and in Apache, RemoteIPInternalProxy, is given only TR7's address; with real_ip_recursive on, Nginx takes the last untrusted address in the chain, that is, the value added by TR7 (ngx_http_realip_module, mod_remoteip). In IIS, this setting only adds a log column; the application must read the client IP from the header separately (Enhanced Logging for IIS 8.5).
Common Mistakes
- Not limiting trust to TR7 on the server. TR7 does not delete the X-Forwarded-For sent by the client; if the application reads the leftmost value of the chain, it may see a fake IP written by the client. The server trusts only the value coming from TR7.
- Using the X-Forwarded-For option together with an action that writes the same header. If
X-Forwarded-Foris added with Add HTTP Header, a duplicate X-Forwarded-For header is created; if Set HTTP Header is used, the option on the vService is kept off. One of the two is chosen. - Confusing it with the "Add X-Forwarded-For Header" option of Traffic mirroring. That option is only for the mirrored copy traffic.
- Looking for X-Forwarded-For on an L7 TCP or Network vService. The header is added only on an HTTP vService; on the other types, the PROXY protocol or Use Client IP is used (How do I pass the real client IP for non-HTTP TCP services?).
- Entering only one device's address as trusted in a cluster. When the peer device is active, the header is ignored and TR7's address appears in the logs.
How it is done in the documentation
