Unlock Real Client IPs in Envoy: Step‑by‑Step Configuration Guide
This article explains why backend services often see proxy IPs instead of the true client address in modern cloud‑native architectures, and provides a detailed walkthrough of configuring Envoy—including X‑Forwarded‑For handling, code snippets, testing, and security recommendations—to ensure the original client IP is correctly propagated.
In modern cloud‑native architectures, Envoy is widely used as a high‑performance edge proxy or service‑mesh data plane for traffic ingress, load balancing, and security control. A common operational issue is that backend services do not receive the real client IP.
Problem Background: Why the Real IP Is Lost
Typical request flow in a micro‑service setup: Client → LB → Envoy Gateway → Service When the request passes through multiple proxies, the original client IP is overwritten at each hop:
Client IP: 172.139.20.1
After load balancer forwarding, source IP becomes LB address: 172.139.20.92
Envoy sees 172.139.20.92, not the original IP.
If HTTP headers are not processed, the backend can never know the true source.
Solution
The industry‑standard HTTP extension header X‑Forwarded‑For records each proxy hop’s IP address. X-Forwarded-For: client, proxy1 Envoy configuration example (relevant parts highlighted):
static_resources:
listeners:
- name: listener_0
address:
socket_address:
address: 0.0.0.0
port_value: 10000
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: ingress_http
# Get real IP address
use_remote_address: true
skip_xff_append: false
http_filters:
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["*"]
routes:
- match:
prefix: "/"
route:
cluster: simple_cluster
clusters:
- name: simple_cluster
lb_policy: ROUND_ROBIN
type: STATIC
load_assignment:
cluster_name: simple_cluster
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address: { address: 172.139.20.170, port_value: 8090 }
- endpoint:
address:
socket_address: { address: 172.139.20.3, port_value: 8090 }
- endpoint:
address:
socket_address: { address: 172.139.20.92, port_value: 8090 }Tip: Envoy does not add the last proxy address (the Envoy Gateway itself) to the X‑Forwarded‑For list.
Testing Verification
After applying the configuration, the X‑Forwarded‑For header includes the client IP, confirming success.
Security Recommendation: Prevent XFF Spoofing
Because X‑Forwarded‑For can be set by the client, attackers may forge it to bypass rate limiting or access control. The recommended practice is to trust XFF only from known, trusted proxies and configure xff_num_trusted_hops so Envoy extracts the correct client IP from the header list.
Tip: In a setup with a single load balancer before Envoy Gateway, set xff_num_trusted_hops to 1.
Additional Test Results
When X‑Forwarded‑For is forged, Envoy still captures the real client address in the X-Envoy-External-Address header.
Conclusion
Retrieving the real client IP is not a hidden feature of Envoy but a fundamental capability that must be correctly configured in modern proxies. It directly impacts observability, security, and compliance of the system.
Linux Ops Smart Journey
The operations journey never stops—pursuing excellence endlessly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
