Nginx常见错误排查:实用指南
遇到Nginx错误?本实用指南助您诊断并解决常见问题。学习处理配置问题、权限拒绝错误、连接被拒绝、502/504网关错误等。我们提供清晰的解释、可操作的解决方案以及必要的Nginx命令,确保您的网站可访问且运行顺畅。
Nginx常见错误排查:实用指南
排查Nginx常见错误时,若仅将状态码视为全部问题,则难度倍增。502错误可能源于应用崩溃、套接字路径错误或后端返回了损坏的头部信息。403错误则可能由文件权限、缺少索引文件或匹配范围超出预期的拒绝规则引起。
从证据入手:错误日志、访问日志、nginx -t命令输出,以及若Nginx作为代理转发至应用时的后端日志。仅凭浏览器页面猜测只会浪费时间。
从快速检查开始
在修改配置前,先运行以下命令:
sudo nginx -t
sudo systemctl status nginx --no-pager
sudo tail -n 80 /var/log/nginx/error.log
sudo tail -n 80 /var/log/nginx/access.log
nginx -t告知配置能否被解析。服务状态显示Nginx是否在运行。日志则揭示Nginx在处理请求时所见情况。
若问题仅与某个URL相关,使用curl复现,以便清晰查看头部和状态:
curl -I https://example.com/problem/path
curl -v https://example.com/problem/path
若问题仅针对特定主机名,请包含该主机名:
curl -I -H 'Host: app.example.com' http://127.0.0.1/
此举可将Nginx路由与DNS、CDN及负载均衡器行为区分开来。
Nginx无法启动或重载
启动失败通常由语法错误、错误上下文中的重复指令、缺少包含文件或证书路径问题引起。
使用:
sudo nginx -t
sudo journalctl -u nginx -n 100 --no-pager
常见信息直接明了:
unknown directive表示拼写错误、不支持的模块或指令放在了错误的Nginx构建中。directive is not allowed here表示指令位于错误上下文,例如将仅限http的指令置于server内部。cannot load certificate表示路径错误、文件缺失或权限阻止Nginx读取。bind() to 0.0.0.0:80 failed通常意味着其他进程已占用该端口。
使用以下命令检查端口:
sudo ss -tulnp | grep ':80\|:443'
在nginx -t通过之前不要重载。重载失败通常保留旧工作进程运行,但重启失败可能导致站点宕机。
(13: Permission denied) 和 403 Forbidden
当Nginx工作进程用户无法读取文件或遍历目录时,错误日志中会出现Permission denied。浏览器可能显示403 Forbidden。
首先查找工作进程用户:
grep -R '^user ' /etc/nginx/nginx.conf
在Debian和Ubuntu上通常是www-data。在RHEL兼容系统上通常是nginx。
对于静态根目录如/var/www/html,Nginx需要对每个父目录拥有执行权限,对文件拥有读取权限:
sudo find /var/www/html -type d -exec chmod 755 {} \;
sudo find /var/www/html -type f -exec chmod 644 {} \;
避免在应用目录上盲目运行chown -R www-data:www-data。这可能使错误消失,但赋予了Web服务器不必要的写入权限。更安全的做法是保持部署所有权分离,仅授予Nginx读取权限。
如果权限看起来正确,检查请求是否针对没有索引文件的目录:
location / {
root /var/www/html;
index index.html index.htm;
}
如果/docs/没有index.html且autoindex关闭,Nginx返回403。这是正确行为。
SELinux也可能在RHEL系列系统上导致权限类错误。如果文件权限正确但Nginx仍无法读取或代理,请在禁用SELinux前检查审计日志:
sudo ausearch -m avc -ts recent
(111: Connection refused) 和 502 Bad Gateway
Connection refused表示Nginx尝试连接上游但目标主动拒绝连接。应用可能已宕机、监听在不同地址或使用的套接字路径不存在。
对于此代理配置:
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
检查:
sudo ss -tulnp | grep 3000
curl -I http://127.0.0.1:3000
sudo systemctl status your-app --no-pager
如果Nginx使用Unix套接字,检查套接字文件:
ls -l /run/gunicorn/app.sock
工作进程用户必须能够读写该套接字。
502 Bad Gateway范围更广。Nginx已到达上游,但响应无效、不完整、过早关闭或不符合Nginx预期。检查与Nginx错误时间戳相同的应用日志。时间戳匹配至关重要;否则可能追查昨天的异常。
对于PHP-FPM,验证fastcgi_pass是否与配置的池套接字或端口匹配。例如:
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
然后检查:
sudo systemctl status php8.3-fpm --no-pager
ls -l /run/php/php8.3-fpm.sock
504 Gateway Timeout
504表示Nginx等待上游响应超时。对于报表、导入或缓慢的管理操作,增加超时时间可能是合理的,但对于每次请求都缓慢的公共端点,不应仅以此作为唯一修复。
location /api/reports/ {
proxy_pass http://127.0.0.1:3000;
proxy_connect_timeout 10s;
proxy_send_timeout 60s;
proxy_read_timeout 180s;
}
然后查看后端计时。如果尚未添加,可在访问日志中加入上游计时:
log_format proxy_timing '$remote_addr "$request" $status '
'request_time=$request_time '
'upstream_time=$upstream_response_time';
如果$upstream_response_time很高,则重点可能在于应用或数据库。如果Nginx显示超时但应用日志表示响应迅速,请检查网络跳数、容器网络、主机内DNS解析或Nginx与应用之间的负载均衡器。
413 Request Entity Too Large
413通常直截了当:请求体大于Nginx允许的大小。上传、大型JSON负载和表单提交可能触发此错误。
在最小必要范围内设置client_max_body_size:
server {
server_name example.com;
location /upload/ {
client_max_body_size 100M;
proxy_pass http://127.0.0.1:3000;
}
}
设置巨大的全局限制通常不是好主意。大多数路由不需要它,且更大的允许体量会增加恶意客户端对堆栈施加的工作量。
SSL和证书错误
TLS失败的表现因观察位置而异。Nginx可能无法重载,浏览器可能警告证书问题,或客户端可能握手失败。
检查证书日期:
openssl x509 -in /etc/letsencrypt/live/example.com/fullchain.pem -noout -dates -subject -issuer
检查公共服务呈现的内容:
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null | openssl x509 -noout -dates -subject -issuer
如果这两个命令显示不同的证书,则可能是负载均衡器、CDN或其他主机在提供服务。
400 Bad Request 和头部问题
400通常表示Nginx不接受请求语法。在真实浏览器中较少见,但机器人、旧客户端、异常代理或过大的头部可能引发此错误。
查找诸如client sent too large request header的消息。如果合法的SSO或应用Cookie过大,可能需要调整头部缓冲区设置。将其视为针对性修复,而非首选方案。过大的Cookie通常更适合在应用中修复。
实用的操作顺序
当Nginx问题实时发生时,使用可重复的顺序:
- 确认确切的URL、主机、状态码和时间。
- 检查
nginx -t和服务状态。 - 在访问日志中匹配该请求。
- 在错误日志中匹配相同时间戳。
- 如果使用代理,检查上游服务状态和日志。
- 从Nginx主机直接测试上游。
- 根据证据进行最小的配置更改。
- 运行
nginx -t,重载,并在重新测试时观察日志。
一旦知道失败发生在何处:Nginx之前、Nginx内部、Nginx与上游之间或上游服务内部,大多数Nginx问题就变得平常了。