这个问题似乎经常被问到,但是我没有找到解决我所遇到问题的好方法。
我在nginx后面有一个flask应用程序。该应用程序和nginx通过uwsgi Unix套接字进行通信。该应用程序具有一个通过Route53公开的公开端点。它还通过AWS API Gateway公开。双重曝光的原因是该应用程序正在替换现有的Lambda解决方案。使用API网关,我可以支持旧式请求,直到它们可以过渡到新的公开端点。关于我的应用程序的另一个事实是,它在负载均衡器后面的Kubernetes容器中运行。
我需要访问发出请求的客户端的IP地址,以便可以使用geoIP查找并排除美国以外(GDPR)用户的数据收集。在进入应用程序的两条路径中,我有两种不同的方式来获取IP地址。
从API网关命中终结点
当我通过传统路径进入时,会得到一个X-Forwarded-For,但是我只看到注册到Amazon的IP地址。我使用的是列表中的第一个,但是我只看到一个或两个不同的IP地址。这是一个测试环境,也许是正确的,但是我不这样认为,因为当我从本地浏览器中访问它时,找不到我的IP。
直接击中终点:
在这种情况下,“ X-Forwarded-For”列表中没有数据,并且我可以找到的唯一IP地址是request.remote_addr。不幸的是,这仅具有容器或负载平衡器的IP地址。我不确定哪个是同一个类,但是两者都不匹配。无论如何,它绝对不是客户端IP地址。我在nginx中找到了描述可用变量(包括$ realip_remote_addr)的文档。但是,当我记录该值时,它与remote_addr相同。
以下是我用来获取remote_addr的代码:
def remote_addr(self, request):
x_forwarded_for = request.headers.get("X-Forwarded-For")
if x_forwarded_for:
ip_list = x_forwarded_for.split(",")
return ip_list[0]
else:
return request.remote_addr
如果有帮助,这是我的Nginx服务器配置:
server {
listen 8443 ssl;
ssl_certificate /etc/certs/cert;
ssl_certificate_key /etc/certs/key;
ssl_dhparam /etc/certs/dhparam.pem;
ssl_protocols TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA HIGH !RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS";
server_tokens off;
location = /log {
limit_except POST {
deny all;
}
include uwsgi_params;
uwsgi_pass unix:///tmp/uwsgi.sock;
}
location = /ping {
limit_except GET {
deny all;
}
include uwsgi_params;
uwsgi_pass unix:///tmp/uwsgi.sock;
}
location = /health-check {
return 200 '{"response": "Healthy"}';
}
location /nginx_status {
stub_status;
}
}
我花了整整一天的时间试图解决这个问题。我确信该解决方案是微不足道的,很可能是由于缺乏使用nginx的知识/经验造成的。