Ubuntu 22.04 LTS 上 linux文件权限错误的排查顺序
面向初学者梳理 Ubuntu 22.04 LTS 中 Permission denied、403、日志写入失败等权限问题的排查方法,按访问主体、属主属组、父目录、服务用户和 ACL 顺序定位并验证。

从报错现场先限定故障范围
在 Ubuntu 22.04 LTS 服务器上,权限问题通常不是“某个文件突然不能用了”这么简单。常见现象包括:应用上传文件失败、Nginx 返回 403、脚本执行时报 Permission denied、日志无法写入、定时任务手动执行正常但自动执行失败。初学者容易第一时间想到 chmod 777,但这往往只是绕过问题,并可能留下更大的安全风险。
排查 linux 文件权限错误时,建议按一个固定顺序走:先确认是谁在访问哪个路径,再检查文件属主与属组,然后检查父目录是否允许进入,接着核对服务实际运行用户,最后查看 ACL 是否改变了表面权限的判断。这个顺序适用于大多数 Ubuntu 22.04 LTS 上的文件权限错误,前提是问题确实发生在本机文件系统访问层面,而不是应用配置、磁盘只读、网络挂载或程序逻辑导致的异常。
先确认:谁在访问,访问哪个路径
权限排查的第一步不是改权限,而是把“访问主体”和“目标路径”找准。很多故障看起来是同一个用户在操作,实际却不是。
例如你通过 SSH 登录后能正常读取文件,但 Web 服务仍然报错,这是因为你当前登录用户可能是 ubuntu、root 或某个运维账号,而 Nginx、Apache、PHP-FPM、Node.js、Java 服务可能使用另一个用户运行。
可以先记录当前登录用户:
whoami
id
再确认出错路径是否真实存在,并查看完整路径上的权限:
ls -ld /var /var/www /var/www/example /var/www/example/storage
namei -l /var/www/example/storage/app.log
namei -l 很适合做权限排查,因为它会把路径中的每一级目录展开。只看最终文件是不够的,父目录没有执行权限时,即使文件本身是可读的,服务也无法进入该目录。
如果错误来自服务进程,应继续确认进程身份,而不是用当前 SSH 用户代替判断。
ps -eo user,group,comm,args | grep -E 'nginx|apache2|php-fpm|node|java' | grep -v grep
对于 systemd 管理的服务,也可以查看服务配置:
systemctl status 服务名 --no-pager
systemctl cat 服务名
注意:不同部署方式下服务运行用户可能不同。即使在 Ubuntu 22.04 LTS 上,Nginx、Apache、PHP-FPM 常见用户是 www-data,但容器、手工编译、面板环境、自定义 systemd unit 都可能改变运行身份,因此必须以实际进程和服务配置为准。
第一层检查:文件属主、属组和基础权限
Linux 基础权限由三部分组成:属主权限、属组权限、其他用户权限。排查文件权限错误时,先看目标文件或目录的属主、属组和权限位。
ls -l /var/www/example/storage/app.log
stat /var/www/example/storage/app.log
典型输出可能类似:
-rw-r----- 1 root root 1024 Jul 3 10:20 /var/www/example/storage/app.log
这表示:
- 文件属主是
root - 属组是
root - 属主可读写
- 同组用户可读
- 其他用户无权限
如果应用服务实际以 www-data 运行,那么它既不是属主,也不在 root 组内,就无法写入该文件。
文件和目录的权限含义不同
初学者常把文件权限和目录权限混在一起。需要特别注意:
| 权限位 | 对文件的含义 | 对目录的含义 |
|---|---|---|
| r | 读取文件内容 | 列出目录文件名 |
| w | 修改文件内容 | 在目录中创建、删除、重命名文件 |
| x | 执行文件 | 进入或穿越该目录 |
目录的 x 权限非常关键。没有目录执行权限,就不能访问目录内部的文件;没有目录写权限,就不能在目录中创建或删除文件。
例如应用需要写入 /var/www/example/storage/app.log,通常需要:
- 对
/var/www/example/storage有进入权限,即目录x - 如果要创建新文件,对
/var/www/example/storage有写权限,即目录w - 如果要追加日志,对
app.log文件有写权限,即文件w
第二层检查:父目录权限是否拦截访问
很多权限错误并不在最终文件,而在父目录。比如文件本身是 -rw-rw-r--,看起来允许同组写入,但上层目录没有执行权限,服务仍然会报 Permission denied。
使用下面命令逐级检查:
namei -l /var/www/example/storage/app.log
可能看到类似结果:
f: /var/www/example/storage/app.log
drwxr-xr-x root root /
drwxr-xr-x root root var
drwx------ root root www
drwxr-xr-x root root example
drwxrwxr-x www-data www-data storage
-rw-rw-r-- www-data www-data app.log
这里的问题在 /var/www:权限是 drwx------ root root,只有 root 能进入。即使 storage 和 app.log 权限正确,www-data 也到不了目标位置。
处理时不要直接对整条路径递归开放权限,而应只修正必要目录。例如 Web 根目录通常至少需要服务用户能够穿越:
sudo chmod 755 /var/www
如果某个目录只希望指定组访问,可以采用属组方式,而不是放开给所有用户:
sudo chgrp www-data /var/www/example
sudo chmod 750 /var/www/example
是否使用 750、755、770 要结合业务需求判断。公开静态文件目录和应用私有上传目录不应使用同一套权限。
第三层检查:服务实际运行用户是否匹配
权限排查中最常见的误判是:手动执行正常,服务执行失败。原因往往是运行用户不同。
查看 systemd 服务用户
如果应用通过 systemd 启动,先查看 unit 文件:
systemctl cat myapp.service
关注这些字段:
[Service]
User=www-data
Group=www-data
WorkingDirectory=/var/www/example
如果 User= 没有配置,服务可能以 root 或启动脚本内指定的用户运行;如果使用了进程管理器、容器或面板,还需要继续到对应配置中确认。
再用进程列表核实:
ps -o user,group,pid,comm,args -p $(pgrep -f myapp | head -n 1)
常见 Web 组件的用户位置
在 Ubuntu 22.04 LTS 中,常见组件可按以下位置核对,但不要假设所有环境都完全一致:
| 组件 | 常见运行用户 | 常见配置位置 |
|---|---|---|
| Nginx | www-data | /etc/nginx/nginx.conf 中的 user |
| Apache | www-data | /etc/apache2/envvars |
| PHP-FPM 8.1 | www-data | /etc/php/8.1/fpm/pool.d/www.conf |
| 自定义 systemd 服务 | 以 unit 为准 | /etc/systemd/system/*.service |
例如检查 PHP-FPM 池配置:
grep -E '^(user|group|listen.owner|listen.group)' /etc/php/8.1/fpm/pool.d/www.conf
如果 PHP 程序需要写入 Laravel 的 storage 目录,而 PHP-FPM 用户是 www-data,那么目录属主或属组就应允许 www-data 写入。
可以用服务用户模拟访问,避免用 root 测试造成误判:
sudo -u www-data test -r /var/www/example/storage/app.log && echo "can read"
sudo -u www-data test -w /var/www/example/storage/app.log && echo "can write"
sudo -u www-data test -x /var/www/example/storage && echo "can enter directory"
如果要测试目录写入,建议只创建临时测试文件,确认路径无误后再执行:
sudo -u www-data sh -c 'touch /var/www/example/storage/.perm_test && rm /var/www/example/storage/.perm_test'
第四层检查:ACL 是否改变了表面权限
有时 ls -l 看起来权限正常,但用户仍然不能访问;或者表面权限很严格,某个用户却能访问。这时要检查 ACL。
如果文件权限后面带有 +,表示存在 ACL:
ls -l /var/www/example/storage
示例:
drwxrwx---+ 2 root www-data 4096 Jul 3 10:30 storage
使用 getfacl 查看详细规则:
getfacl /var/www/example/storage
可能看到:
# file: var/www/example/storage
# owner: root
# group: www-data
user::rwx
user:deploy:rwx
group::rwx
mask::r-x
other::---
这里容易忽略 mask。在 POSIX ACL 中,mask 会限制命名用户和组的有效权限。即使 user:deploy:rwx 写着 rwx,如果 mask::r-x,实际写权限仍可能无效。
如果确实需要给某个服务用户写入权限,可以明确设置 ACL:
sudo setfacl -m u:www-data:rwx /var/www/example/storage
如果还希望新创建的文件和子目录继承默认 ACL,可以设置 default ACL:
sudo setfacl -d -m u:www-data:rwx /var/www/example/storage
修改 ACL 前建议先备份当前 ACL,便于回滚:
getfacl -R /var/www/example/storage > /tmp/storage.acl.backup
ACL 适合处理“多个用户或服务共享同一目录”的场景,但也会增加排查复杂度。对于简单部署,优先用清晰的属主、属组和目录权限管理即可。
按结果分支处理,不要默认 chmod 777
定位到问题后,再选择最小范围的修复方式。下面是常见判断分支:
| 检查结果 | 常见原因 | 建议处理 |
|---|---|---|
| 文件属主是 root,服务用户无法写入 | 部署或解压时使用了 root | 将文件或目录属主调整给服务用户,或调整属组 |
| 最终文件权限正确,但服务仍无法访问 | 父目录缺少 x 权限 | 使用 namei -l 找出拦截目录,只修正该级目录 |
| SSH 用户可写,服务不可写 | 登录用户和服务用户不同 | 核对 systemd、Nginx、PHP-FPM 等运行身份 |
ls -l 看不出问题,但访问异常 |
ACL 或 ACL mask 影响 | 使用 getfacl 查看有效权限 |
| 新文件创建后权限又不对 | umask 或默认 ACL 不匹配 | 检查服务启动环境、部署脚本或 default ACL |
如果确认目录应由 Web 服务写入,例如上传目录或缓存目录,可以采用属组协作方式:
sudo chown -R deploy:www-data /var/www/example/storage
sudo chmod -R 775 /var/www/example/storage
这类递归命令会影响目录下所有文件,执行前应确认路径准确,避免把权限改到系统目录或错误项目目录。更稳妥的做法是先查看将要修改的范围:
find /var/www/example/storage -maxdepth 2 -ls
如果是共享目录,希望后续新文件自动继承属组,可以给目录设置 SGID 位:
sudo chgrp -R www-data /var/www/example/storage
sudo find /var/www/example/storage -type d -exec chmod g+s {} \;
SGID 位会让目录中新建文件继承目录属组,适合部署用户和服务用户通过同一个组协作的场景。它不能替代写权限,也不能解决父目录不可进入的问题。
结合日志确认权限错误发生点
权限错误最终应回到日志中验证。不同服务日志位置不同,常见检查方式如下:
journalctl -u 服务名 -n 100 --no-pager
Nginx 可查看错误日志:
sudo tail -n 100 /var/log/nginx/error.log
Apache 可查看:
sudo tail -n 100 /var/log/apache2/error.log
应用自身也可能有独立日志,例如:
sudo tail -n 100 /var/www/example/storage/logs/app.log
如果日志中出现类似内容:
open() "/var/www/example/public/index.html" failed (13: Permission denied)
重点检查 Nginx worker 用户对该路径的读取权限,以及每一级父目录的执行权限。
如果是:
failed to open stream: Permission denied
通常需要确认 PHP-FPM 用户对目标文件或目录是否具有写入权限。
如果是:
EACCES: permission denied, mkdir '/var/www/example/cache'
说明程序尝试创建目录或文件失败,应检查目标父目录是否具备写权限,而不是只看 cache 目录本身是否存在。
一个完整的排查示例
假设 Ubuntu 22.04 LTS 上某个站点上传图片失败,应用日志提示:
Permission denied: /var/www/site/storage/uploads
按顺序检查。
- 确认服务用户:
ps -eo user,group,comm,args | grep php-fpm | grep -v grep
假设结果显示 PHP-FPM 运行用户为 www-data。
- 检查路径每一级权限:
namei -l /var/www/site/storage/uploads
发现 /var/www/site 属主为 deploy:deploy,权限为 750,www-data 不在 deploy 组,无法进入。
- 检查目标目录:
ls -ld /var/www/site/storage /var/www/site/storage/uploads
getfacl /var/www/site/storage/uploads
如果没有特殊 ACL,且业务允许 PHP-FPM 写入 storage,可把协作组调整为 www-data:
sudo chgrp -R www-data /var/www/site/storage
sudo chmod -R 775 /var/www/site/storage
- 如果
/var/www/site也需要被服务穿越,可以只赋予目录进入权限,而不是开放写权限:
sudo chmod 750 /var/www/site
sudo usermod -aG deploy www-data
这里要注意,给用户追加组后,已有进程通常需要重新登录或重启相关服务才能生效。对于 PHP-FPM,可在确认配置无误后重启服务:
sudo systemctl restart php8.1-fpm
重启服务会影响正在处理的请求,生产环境应选择低峰期或先评估业务影响。
修复后验证与持续观察项
权限修复后,不要只看报错是否暂时消失。建议按访问主体再次验证:
sudo -u www-data test -x /var/www/site/storage && echo "directory enter ok"
sudo -u www-data sh -c 'touch /var/www/site/storage/.perm_test && rm /var/www/site/storage/.perm_test'
再观察服务日志是否还有新的 Permission denied:
journalctl -u php8.1-fpm -n 50 --no-pager
sudo tail -n 50 /var/log/nginx/error.log
后续重点关注几类变化:
- 新部署后文件属主是否又变成
root - 上传、缓存、日志目录中新文件权限是否符合预期
- 服务升级或迁移后运行用户是否发生变化
- ACL 是否被部署脚本、备份恢复或面板操作覆盖
- 多人协作目录是否需要 SGID 或默认 ACL 来保持一致性
只要按“访问主体 → 文件属主属组 → 父目录权限 → 服务运行用户 → ACL”的顺序检查,大多数 Ubuntu 22.04 LTS 上的 linux 文件权限错误都可以定位到具体层级,再用最小权限原则进行修复。