我试图从我的nodejs服务器中的请求对象获取客户端的IP地址。
我的技术结构是:
我运行两个docker容器。一个用于haproxy
,另一个用于nodejs
,使用expressjs
框架。所有传入流量都是由haproxy首先接收的,我用它来进行代理和负载均衡。 Haproxy根据配置文件中的ACLs
将请求转发到适当的后端。
我尝试在我的nodejs中访问x-forwarded-for
请求标头,但它只返回了docker网络网关接口172.17.0.1
的IP。
标题为haproxy
配置并使用option forwardfor header X-Client-IP
块中的defaults
也将x-client-ip
标头设置为docker network gateway interface ip。此外,调试日志也记录了相同的IP。
所以这就是问题所在。由于haproxy
在容器内运行,因此它认为docker网络网关接口是客户端。
如何将实际客户端的IP收集到容器内的haproxy
,以便它可以将其转发到nodejs?
这是我的haproxy
配置文件:
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"
我使用:
运行我的haproxy容器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
注意:我没有使用任何防火墙。另外,请随意建议我的配置有任何改进。保持活力也是一个问题。
答案 0 :(得分:2)
最后在通过码头论坛搜索后找到了解决方案。
解决方案分为两个步骤。
首先,我需要将haproxy
配置更新为:
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"
请注意option forwardfor
块中添加了frontend http-in
。这告诉haproxy的前端部分将客户端IP添加到请求头。
其次,docker run命令应更新为:
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
注意在docker run命令中添加了--net=host
选项。它告诉docker启动新容器并使用与主机相同的网卡。
现在,原始客户端IP已添加到请求标头中,并且可以在转发请求的任何应用程序中的x-forwarded-for
请求标头中进行访问。
答案 1 :(得分:1)
haproxy的工作方式不可行,因为当你在启动时没有连接主机时它会继续投掷,因为它需要完全解析地址。我已经尝试了很多变通办法(可能它可能),但我放弃并使用docker-compose
我发布了一个可能在帖子中提前帮助的运行示例。
要点是将容器与实际已存在的主机链接。这是由docker链接完成的。
搬运工-compose.yml
api1:
build: .
dockerfile: ./Dockerfile
ports:
- 3955
links:
- mongo
- redis
environment:
- REDIS_HOST=redis
- MONGO_HOST=mongo
- IS_TEST=true
command: "node app.js"
api2:
build: .
dockerfile: ./Dockerfile
ports:
- 3955
links:
- mongo
- redis
environment:
- REDIS_HOST=redis
- MONGO_HOST=mongo
- IS_TEST=true
command: "node app.js"
mongo:
image: mongo
ports:
- "27017:27017"
command: "--smallfiles --logpath=/dev/null"
redis:
image: redis
ports:
- "6379:6379"
haproxy:
image: haproxy:1.5
volumes:
- ./cluster:/usr/local/etc/haproxy/
links:
- "api1"
- "api2"
ports:
- 80:80
- 70:70
expose:
- "80"
- "70"
haproxy.cfg
global
log 127.0.0.1 local0
log 127.0.0.1 local1 notice
defaults
log global
mode http
option httplog
option dontlognull
timeout connect 5000
timeout client 10000
timeout server 10000
listen stats :70
stats enable
stats uri /
frontend balancer
bind 0.0.0.0:80
mode http
default_backend aj_backends
backend aj_backends
mode http
balance roundrobin
option forwardfor
http-request set-header X-Forwarded-Port %[dst_port]
http-request add-header X-Forwarded-Proto https if { ssl_fc }
option httpchk HEAD / HTTP/1.1\r\nHost:localhost
default-server inter 3s fall 5
server api1 api1:3955
server api2 api2:3955