Nginx proxy_pass无法转发请求至8000端口的Docker应用
问题概况
Nginx无法将/api/路径的请求转发至运行在8000端口的Docker应用,错误日志显示recv() failed (104: Unknown error),实际对应connection reset by peer错误。但直接使用gunicorn启动API服务器时,所有请求均正常响应,且已通过docker ps确认Docker容器正常运行并映射了8000端口。
相关配置与状态信息
Nginx 配置(nginx.conf)
server { listen 80; server_name example.com; location = /favicon.ico { access_log off; log_not_found off; } location /static/ { alias /home/../staticfiles; } location /api/ { include proxy_params; proxy_pass http://127.0.0.1:8000; } }
Docker 容器运行状态
执行docker ps得到以下输出:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES f86d5f013c90 lead-hr-api-backend "bash -c ./run.sh" 18 hours ago Up 18 hours 0.0.0.0:8000->8000/tcp, :::8000->8000/tcp lbhr-backend
Nginx 错误日志片段
执行sudo tail -F /var/log/nginx/error.log得到:
2024/01/30 11:51:53 [error] 59675#59675: *283 recv() failed (104: Unknown error) while reading response header from upstream, client: 172.69.165.44, server: leadhr.alexpy.com, request: "GET /api/admin/ HTTP/1.1", upstream: "http://127.0.0.1:8000/api/admin/", host: "example.com", referrer: "https://example.com/api/admin/login/?next=/api/admin/" 2024/01/30 11:52:16 [error] 59675#59675: *283 recv() failed (104: Unknown error) while reading response header from upstream, client: 172.69.165.44, server: leadhr.alexpy.com, request: "GET /api/admin/ HTTP/1.1", upstream: "http://127.0.0.1:8000/api/admin/", host: "leadhr.alexpy.com"
问题原因分析
connection reset by peer表示上游服务主动关闭了连接,结合直接运行gunicorn正常的现象,核心原因大概率是Docker容器内应用的监听地址配置错误:
- 直接用gunicorn启动时,应用默认监听
127.0.0.1:8000,宿主机的Nginx可以直接访问; - 但在Docker容器内部,如果应用仍监听
127.0.0.1:8000,这个地址仅容器内部可见,宿主机的Nginx无法通过端口映射访问到应用,进而触发连接重置。
另外,若上游应用的路由未包含/api前缀,Nginx当前的proxy_pass配置会将/api/admin/完整转发到上游,可能导致上游返回404并关闭连接,但结合错误类型,监听地址问题的优先级更高。
解决方案
1. 修改容器内应用的监听地址
确保应用在容器内监听所有网卡(0.0.0.0)而非仅本地回环地址。以gunicorn为例,修改启动命令:
gunicorn --bind 0.0.0.0:8000 your_app.wsgi:application
修改后重启Docker容器,让应用监听容器内所有可访问的网卡,宿主机即可通过映射的8000端口正常连接。
2. 调整Nginx的proxy_pass路径(按需)
如果上游应用的路由没有/api前缀,需要修改proxy_pass配置,自动去除/api前缀后转发:
location /api/ { include proxy_params; proxy_pass http://127.0.0.1:8000/; # 末尾添加斜杠,将/api/后的路径转发到上游根路径 }
例如请求/api/admin/会被转发为http://127.0.0.1:8000/admin/,匹配上游的路由规则。
3. 验证与重启
完成配置修改后,重启相关服务:
docker restart lbhr-backend sudo systemctl restart nginx
测试/api/路径的请求,确认响应正常。
内容的提问来源于stack exchange,提问作者AlexPy

