Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get client IP from request inside haproxy docker container?

I am trying to get the client's IP address from the request objects in my nodejs server.

My technology structure is: I run two docker containers. One for haproxy and other for nodejs which uses expressjs framework. All incoming traffic is first received by haproxy which I use for proxying and load balancing. Haproxy forwards the requests to the appropriate backends based on the ACLs in the configuration file.

I tried accessing x-forwarded-for request header inside my nodejs but it only returned the IP for the docker network gateway interface 172.17.0.1.

Heading over to haproxy configuration and using option forwardfor header X-Client-IP in the defaults block also set the x-client-ip header to the docker network gateway interface ip. Also the debug logs also are logging the same ip.

So this is what the trouble is. Since haproxy is running inside a container it believes that the docker network gateway interface is the client.

How can I get the actual client's IP to haproxy inside the container so that it can forward it to nodejs?

This is my haproxy configuration file:

global
    debug
    maxconn 4096

defaults
    mode http
    timeout connect 5000ms
    timeout client 50000ms
    timeout server 50000ms
    timeout http-keep-alive 50000ms
    option http-keep-alive
    option http-server-close
    option forwardfor header X-Client-IP

frontend http-in
    bind *:80
    acl is_api hdr_end(host) -i api.3dphy-dev.com

    use_backend api if is_api

    default_backend default

backend default
    server s0 "${DOCKER_INTERFACE_IP}:3000"

backend api
    balance leastconn
    option httpclose
    option forwardfor
    server s1 "${DOCKER_INTERFACE_IP}:17884"

I run my haproxy container using:

docker run -d --name haproxy_1 -p 80:80 -e DOCKER_INTERFACE_IP=`ifconfig docker0 | grep -oP 'inet addr:\K\S+'` -v $(pwd)/config/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro haproxy:1.6

Note: I am not using any firewall. Also, feel free to suggest any improvements in my configuration. Keep-alive is also proving to be an issue.

like image 740
Surender Thakran Avatar asked Apr 10 '26 02:04

Surender Thakran


1 Answers

Finally managed to find a solution after scouring through the docker forum.

The solution is a two step process.

First I needed to update my haproxy configuration to this:

global
    debug
    maxconn 4096

defaults
    mode http
    timeout connect 5000ms
    timeout client 50000ms
    timeout server 50000ms
    timeout http-keep-alive 50000ms
    option http-keep-alive
    option http-server-close

frontend http-in
    bind *:80
    option forwardfor
    acl is_site hdr_end(host) -i surenderthakran-dev.com

    use_backend site if is_site

    default_backend default

backend default
    server s0 "${DOCKER_INTERFACE_IP}:3000"

backend site
    balance leastconn
    option httpclose
    option forwardfor
    server s1 "${DOCKER_INTERFACE_IP}:17884"

Notice the addition of option forwardfor in frontend http-in block. This tells the frontend part of haproxy to add the client IP to the request header.

Second, the docker run command should be updated to:

docker run -d --name haproxy_1 -p 80:80 -e DOCKER_INTERFACE_IP=`ifconfig docker0 | grep -oP 'inet addr:\K\S+'` -v $(pwd)/config/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro --net=host haproxy:1.6

Notice the addition of --net=host option in the docker run command. It tells docker to launch the new container and use the same network card as the host.

Now the original client IP is added to the request header and can be accessed in the x-forwarded-for request header in any application to which the request is forwarded.

like image 169
Surender Thakran Avatar answered Apr 12 '26 15:04

Surender Thakran