一次 Nginx 502 问题的深度排查:从 SELinux 到容器网络

一次 Nginx 502 问题的深度排查:从 SELinux 到容器网络
作者donoot日期2026-07-07关键词Nginx、502 Bad Gateway、SELinux、Docker、反向代理、故障排查一、背景我有一台 CentOS 9 服务器其中运行了一个 Docker 容器wechat-article-exporter该容器提供一个 Web 服务监听在3000/tcp端口。为了对外提供安全的 HTTPS 访问我在宿主机上部署了 Nginx将外部13000端口HTTPS的请求反向代理到容器的3000端口HTTP。然而当我通过浏览器访问https://服务器IP:13000时始终收到502 Bad Gateway错误且 Nginx 返回nginx/1.20.1版本信息。二、问题现象浏览器访问返回502 Bad Gateway。容器日志显示服务正常启动监听0.0.0.0:3000。直接在宿主机上用curl http://127.0.0.1:3000可以正常获取页面200 OK。Nginx 错误日志中出现大量类似如下记录text2026/07/07 14:33:51 [crit] 1328#1328: *71 connect() to 127.0.0.1:3000 failed (13: Permission denied) while connecting to upstream, client: 192.168.1.3, server: _, request: GET / HTTP/1.1, upstream: http://127.0.0.1:3000/, host: 192.168.1.91:13000关键信息connect() to 127.0.0.1:3000 failed (13: Permission denied)。三、排查过程3.1 确认容器服务状态bashsudo docker ps sudo docker logs wechat-article-exporter容器正常运行日志显示Listening on http://0.0.0.0:3000说明容器内服务已启动。3.2 直接访问容器绕过 Nginxbashcurl -v http://127.0.0.1:3000返回正常 HTML证实容器服务工作正常问题出在 Nginx 与容器之间的通信。3.3 检查 Nginx 配置Nginx 配置如下精简nginxserver { listen 13000 ssl; server_name _; ssl_certificate /path/to/cert.pem; ssl_certificate_key /path/to/key.pem; location / { proxy_pass http://127.0.0.1:3000; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }配置看起来无异常。3.4 查看 Nginx 错误日志错误日志明确指出Permission denied而不是Connection refused或Connection timed out。这说明端口可达但权限不足。3.5 怀疑 SELinuxCentOS 9 默认启用 SELinux。Nginx 进程通常带有httpd_t或nginx_t安全上下文其默认策略可能禁止向其他端口发起网络连接即使是本地。检查 SELinux 布尔值bashgetsebool httpd_can_network_connect输出为off证实了猜想。四、根本原因SELinux 策略布尔值httpd_can_network_connect控制 HTTP 服务包括 Nginx是否可以作为客户端连接到任意 TCP 端口。默认关闭off导致 Nginx 无法连接到本机的3000端口即使127.0.0.1:3000是监听状态。直接使用curl访问成功因为curl运行在用户 shell 上下文不受此限制。五、解决方案启用httpd_can_network_connect布尔值并永久保存bashsudo setsebool -P httpd_can_network_connect 1验证bashgetsebool httpd_can_network_connect输出应为httpd_can_network_connect -- on。执行后无需重启 Nginx再次访问网站502 立即消失页面正常加载。六、原理分析6.1 SELinux 简述SELinuxSecurity-Enhanced Linux是 Linux 内核的安全模块提供强制访问控制MAC。每个进程和文件都有安全上下文类型策略定义了它们之间的交互权限。Nginx 进程的类型通常是httpd_t或nginx_t其策略允许监听端口、读取静态文件但默认限制向外发起 TCP 连接以避免被入侵后作为跳板攻击内网。6.2 相关布尔值httpd_can_network_connect是专门为 HTTP 服务准备的开关作用允许 httpd 相关进程连接到任意远程主机和端口。默认关闭安全考虑。风险开启后 Nginx 可以访问外部网络但一般场景下如代理本机端口风险较低。如果只允许 Nginx 连接特定端口如 3000可以使用更精细的semanage port命令将端口加入http_port_t但实践上大多数运维直接开启上述布尔值。七、经验与总结7.1 排查 502 的通用思路确认上游服务是否运行正常直接访问上游端口。检查 Nginx 错误日志通常能提供具体原因。检查网络连通性ping、telnet、nc 等。检查防火墙和 SELinuxCentOS/RHEL 系尤其常见。检查 Nginx 配置中的代理头和超时设置。7.2 预防与建议在 CentOS/RHEL 系列服务器上部署 Nginx 反向代理时优先检查 SELinux 布尔值。使用audit2why等工具分析 SELinux 拒绝日志快速定位策略问题。生产环境建议保持 SELinux 开启根据需求启用对应布尔值而非直接禁用 SELinux。7.3 后续优化本次排障中还发现容器内部存在一个额外的业务问题请求192.168.1.91:443超时但这不直接影响 502仅影响部分 API 功能。根据业务需要后续可通过修改容器内代码或配置环境变量解决。八、结语一次看似简单的 502 错误却牵涉到 SELinux 这个容易被忽视的环节。希望本文的复盘能帮助读者在遇到类似问题时少走弯路快速定位并解决问题。技术栈CentOS 9、Nginx 1.20.1、Docker、Node.js、SELinux核心命令setsebool -P httpd_can_network_connect 1本文首发于个人技术博客欢迎交流指正。