Nginx反向代理Rails应用失败:[::1]:3000连接被拒绝
这种情况我之前排查过好多次,明明Puma在3000端口正常跑着,本地curl也能通,但Nginx就是报连接被拒绝,大概率是监听地址不匹配或者系统安全策略在搞鬼,咱们一步步来捋:
1. 先确认Puma的监听地址到底是什么
你说Puma在3000端口监听,但默认情况下Puma可能只绑定IPv4的回环地址127.0.0.1:3000,而Nginx如果用IPv6的回环地址[::1]:3000去连接,自然会被拒绝。
你可以用这两个命令查Puma的监听状态:
# 旧系统用netstat netstat -tulpn | grep 3000 # 新系统更推荐用ss ss -tulpn | grep 3000
如果输出里是127.0.0.1:3000,说明只监听IPv4;如果是[::]:3000就是同时监听IPv4和IPv6。
解决方法:
- 临时启动Puma时指定绑定所有地址:
puma -b tcp://0.0.0.0:3000 - 永久配置的话,在Rails项目的
config/puma.rb里加一行:bind 'tcp://0.0.0.0:3000',这样Puma会同时监听IPv4和IPv6的3000端口。
2. 检查Nginx代理配置里的目标地址
看你HTTPS的server块(你只贴了HTTP转HTTPS的部分),proxy_pass是写的http://localhost:3000还是http://[::1]:3000?
如果Puma只监听IPv4,而localhost在你的系统里优先解析到IPv6的[::1],那Nginx就会连错地址。这时候把proxy_pass改成http://127.0.0.1:3000(强制用IPv4回环),就能解决问题。
举个正确的HTTPS代理配置示例:
server { listen 443 ssl; server_name raitrr.com www.raitrr.com; ssl_certificate /path/to/your/ssl_cert.pem; ssl_certificate_key /path/to/your/ssl_key.pem; location / { proxy_pass http://127.0.0.1:3000; # 这里指定IPv4回环,避免解析问题 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }
3. 排查SELinux/AppArmor的限制
如果是Linux系统,SELinux(比如CentOS/RHEL)或者AppArmor(Ubuntu)可能会阻止Nginx发起出站连接到非标准端口(3000不属于Web服务的默认端口)。
- 临时测试SELinux:执行
sudo setenforce 0,然后刷新页面看能不能访问。如果能通,说明是SELinux的问题,执行sudo setsebool -P httpd_can_network_connect 1永久允许Nginx发起网络连接。 - AppArmor的话,检查
/etc/apparmor.d/usr.sbin.nginx配置文件,看是否包含允许连接到3000端口的规则,没有的话需要添加对应的权限。
4. 验证Nginx运行用户的访问权限
Nginx默认用www-data用户运行,你可以模拟这个用户去访问Puma,确认是否有权限:
sudo -u www-data curl http://127.0.0.1:3000
如果curl返回Rails的页面内容,说明权限没问题;如果返回连接被拒绝,那可能是Puma有额外的权限限制(比如绑定了特定用户的端口),这时候需要调整Puma的启动用户或者权限配置。
5. 再看Puma的详细日志
有时候Puma进程虽然存在,但可能有隐性错误,比如启动时加载配置失败,或者端口被其他进程占用(但你说本地能连,这个概率低)。去看Puma的stderr日志(一般在Rails项目的log/puma.stderr.log),有没有连接拒绝相关的报错信息,能帮你定位问题。
备注:内容来源于stack exchange,提问作者uberdave

