如果你看到Nginx返回403,日志里却只留下一句 Permission denied,别急着改配置文件,先想想这个“Permission”是谁在拒绝谁。我在维护服务器的头两年,遇到的Nginx故障里,至少有一半能归类到权限问题:静态资源访问不了、上传目录写不进去、反向代理莫名其妙失败、Docker挂载目录全是403……问题的表象五花八门,但根子基本都是“运行Nginx的用户没有读文件的权限”“目录缺失执行权限”或者“SELinux在背后拦截”。
这篇内容没有那么多花架子,直接说白话:先从权限模型讲清楚Nginx到底在用什么身份干活,再带你把典型问题过一遍,最后给出可以直接抄作业的解决方案和排查命令。适合刚接触Nginx的新手,也适合被权限问题折磨过几次、想彻底搞明白的运维和开发同学。
1. 先搞清楚Nginx的权限模型:运行用户、文件属主与目录权限
1.1 worker进程到底以哪个用户身份在跑?
Nginx启动时,master进程一般由root启动,因为它要绑定80、443这样的低端口;但真正处理请求的是worker进程,worker进程的权限由配置文件里的 user 指令决定。很多刚上手的朋友容易忽略这一点:你以为Nginx能读取某个文件,是因为文件属于root,可实际上worker进程可能正用着一个叫 nginx 或 nobody 的普通用户,压根没有权限打开root文件。
查看Nginx实际以什么用户运行,最直接的办法是:
bash复制ps -ef | grep nginx
你会看到类似这样的输出:
bash复制root 1234 1 0 10:00 ? 00:00:00 nginx: master process nginx
nginx 1235 1234 0 10:00 ? 00:00:00 nginx: worker process
master进程是root,worker进程是nginx,这就说明配置文件里 user nginx; 生效了。如果worker显示为nobody,那就意味着你在编译或者配置时没有指定用户,Nginx用了默认的nobody。某些发行版打包的Nginx默认用户是 nginx,有些是 www-data,还有的是 apache,建议用 nginx -V 看编译参数,再用 nginx -T 看实际生效配置。
user 指令通常写在nginx.conf主配置顶端:
nginx复制user nginx;
worker_processes auto;
这里有一个非常关键的认知:要解决Nginx权限问题,不是把文件改成root所有,而是要么让worker进程有权限,要么让文件属主匹配worker进程。搞清楚当前worker是谁,后面的一切排查才有方向。
1.2 目录执行权限比文件读权限更容易被忽视
Linux权限体系里,文件本身有读(r)、写(w)、执行(x)三组权限,目录也有这三组,但含义和文件略有区别。文件执行权限是能不能把这个文件当程序跑,目录执行权限却是能不能“穿过”这个目录去访问里面的内容。换句话说,你要让Nginx读取 /data/www/html/index.html,不仅这个文件要有读权限,/data、/data/www、/data/www/html 每一级目录都要对worker用户开放执行(x)权限。
很多新手把 chmod 644 index.html 做完了,发现还是403,就是因为其中某一级目录缺了x权限。目录的x权限常常被忽视,但它几乎是权限问题里出现频率最高的原因。你可以用 namei -l /data/www/html/index.html 一次性查看路径上每一级目录的权限:
bash复制namei -l /data/www/html/index.html
f: /data/www/html/index.html
dr-xr-xr-x root root /
drwxr-xr-x root root data
drwxr-xr-x root root www
drwx--x--x root root html
-rw-r--r-- root root index.html
如果某一级目录显示为类似 drwx--x--x,其他用户没有读权限,那Nginx就算文件本身是644,也可能因为无法读取目录内容而报403。记住一个口诀:文件要读,路径上每一级目录都得有x权限;如果目录还想被列出目录项,还需要r权限。
另外,如果你使用了root作为Nginx运行用户,确实能避开绝大多数权限报错,但这是非常危险的做法。一旦Nginx被利用,攻击者直接拿到root权限。我的建议是无论多着急,都别用 user root,把权限分配做好,比临时逃避问题靠谱得多。
1.3 SELinux和AppArmor:权限问题里的“隐形裁判”
除了文件权限,在一些Linux发行版上还有一层额外的访问控制:CentOS/RHEL上默认开启SELinux,Ubuntu/
