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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With