Skip to main content

See each client's own address

Behind a load balancer, every request reaches the gateway from the load balancer's address. A limit per client address then counts every client as one, and an address list cannot tell them apart. real-ip reads each client's own address from the header the load balancer writes. That address becomes the one the route's plugins see. This guide puts real-ip on orders-api. At the end, your backend and the route's plugins see each client's own address instead of the load balancer's.

Before you start​

  • Two facts from the team that runs the load balancer: the header it writes each client's address into, X-Forwarded-For or X-Real-IP, and every address it connects to the gateway nodes from. This guide uses X-Forwarded-For and the addresses 10.0.0.21 and 10.0.0.22.
  • This guide starts from orders-api as Route requests to a backend leaves it, with no other plugin. A plugin from another guide that this page does not name can change the answers below; remove it first or work on a copy of the route.
  • The requests below call /orders/3001.
  • The host name of your gateway. In the console it is the first part of the Address line on a route's Overview tab, api.example.com in this page's examples; replace it in every request below.
  • A way to see what your backend receives: its access log, or a request echo it offers. The gateway's answer to the client does not show the address it passed on.
  • The Editor or Environment administrator role in this environment.

Steps​

1. Choose real-ip​

Open orders-api under Routes, select its Plugins tab, then Add plugin at the top right of the tab. Open the General category, or type real-ip in the search box. Select real-ip, then Configure.

2. Name the header and the load balancer's addresses​

Trusted addresses is a list: type a value and press Enter for each.

FieldValueWhy
Sourcehttp_x_forwarded_forReads the X-Forwarded-For header. For a load balancer that sends X-Real-IP, set http_x_real_ip.
Trusted addresses10.0.0.21 and 10.0.0.22The header is believed only from these addresses. List every address your load balancer connects from, and nothing else.
Recursiveleave offThe default. Take the last address of the header, the one your load balancer added.

Select Add plugin at the bottom of the panel. The plugin is saved like this:

The Add real-ip panel with the forwarded header named and the two load balancers listed as trusted addresses.
real-ip · as the console saves it
{
"source": "http_x_forwarded_for",
"trusted_addresses": [
"10.0.0.21",
"10.0.0.22"
]
}

From now on, a request from the load balancer is taken as coming from the last address in its X-Forwarded-For, and your backend receives that address in X-Real-IP. A request from any other address keeps its own, whatever header it sends.

Check it​

Send the request below through your load balancer, from a machine whose address you know, and read X-Real-IP in your backend's log. A request sent straight to a gateway node does not come from a trusted address, so the gateway ignores its header.

curl
curl -i -L 'https://<gateway host>/orders/3001' \
-H 'X-Forwarded-For: 198.51.100.66, 203.0.113.7'

The X-Forwarded-For in the request shows the header as the gateway receives it from your load balancer, with your machine's address, 203.0.113.7 here, last. The answers on limit-count and ip-restriction apply only if the route also carries limit-count from Limit requests on a route or ip-restriction from Allow a network.

What your backend receives
Your backend receives the client's address in X-Real-IP: a request your load balancer forwards with 203.0.113.7 last in X-Forwarded-For arrives with X-Real-IP: 203.0.113.7.
An address the client wrote itself
Only the last address counts: an address the client wrote into the header itself, 198.51.100.66 in X-Forwarded-For: 198.51.100.66, 203.0.113.7, is not used.
If the route carries limit-count
A limit-count on the same route that counts by client address counts each client under its own address. Once 203.0.113.7 has used its count it is answered 429, while another client behind the same load balancer still passes.
The route’s own Client addresses field
The route is matched before real-ip runs. A route whose Client addresses leave 203.0.113.7 out still takes its request, because the request arrives from the load balancer, and the backend still receives X-Real-IP: 203.0.113.7.
If the route carries ip-restriction
ip-restriction on the same route acts after real-ip: a client inside its allow list passes, and one outside it is answered 403.

What to know​

  • Leave Trusted addresses empty and the header is believed from everyone. A client that reaches a gateway node directly can then name any address, and under a limit per address it is never refused: each new address starts a fresh count.
  • The route itself is matched before its plugins run. Its Client addresses field and a condition on the client address still see the load balancer's address. An address list behind a load balancer is ip-restriction on the same route, as Allow a network shows.
  • With Recursive on, the addresses listed under Trusted addresses are skipped from the end of the header and the address in front of them is taken. Use it when a proxy stands between the client and your load balancer, and list that proxy too.
  • Your backend also receives X-Forwarded-For. The gateway adds the client's address at its end once more, so the address your load balancer wrote last stands there twice. Read the client's address from X-Real-IP, or from the last address of that header, never from the first, which a client can write itself.
  • Behind a load balancer every route needs each client's own address, so a global rule is the usual place for real-ip. Apply a plugin to every request puts it on one, so that every plugin sees each client's own address.
G8 dev