LHIDC

Ubuntu 22.04 LTS 上 linux文件权限错误的排查顺序

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

Ubuntu 22.04 LTS 上 linux文件权限错误的排查顺序

从报错现场先限定故障范围

在 Ubuntu 22.04 LTS 服务器上,权限问题通常不是“某个文件突然不能用了”这么简单。常见现象包括:应用上传文件失败、Nginx 返回 403、脚本执行时报 Permission denied、日志无法写入、定时任务手动执行正常但自动执行失败。初学者容易第一时间想到 chmod 777,但这往往只是绕过问题,并可能留下更大的安全风险。

排查 linux 文件权限错误时,建议按一个固定顺序走:先确认是谁在访问哪个路径,再检查文件属主与属组,然后检查父目录是否允许进入,接着核对服务实际运行用户,最后查看 ACL 是否改变了表面权限的判断。这个顺序适用于大多数 Ubuntu 22.04 LTS 上的文件权限错误,前提是问题确实发生在本机文件系统访问层面,而不是应用配置、磁盘只读、网络挂载或程序逻辑导致的异常。

先确认:谁在访问,访问哪个路径

权限排查的第一步不是改权限,而是把“访问主体”和“目标路径”找准。很多故障看起来是同一个用户在操作,实际却不是。

例如你通过 SSH 登录后能正常读取文件,但 Web 服务仍然报错,这是因为你当前登录用户可能是 ubunturoot 或某个运维账号,而 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 能进入。即使 storageapp.log 权限正确,www-data 也到不了目标位置。

处理时不要直接对整条路径递归开放权限,而应只修正必要目录。例如 Web 根目录通常至少需要服务用户能够穿越:

sudo chmod 755 /var/www

如果某个目录只希望指定组访问,可以采用属组方式,而不是放开给所有用户:

sudo chgrp www-data /var/www/example
sudo chmod 750 /var/www/example

是否使用 750755770 要结合业务需求判断。公开静态文件目录和应用私有上传目录不应使用同一套权限。

第三层检查:服务实际运行用户是否匹配

权限排查中最常见的误判是:手动执行正常,服务执行失败。原因往往是运行用户不同。

查看 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

按顺序检查。

  1. 确认服务用户:
ps -eo user,group,comm,args | grep php-fpm | grep -v grep

假设结果显示 PHP-FPM 运行用户为 www-data

  1. 检查路径每一级权限:
namei -l /var/www/site/storage/uploads

发现 /var/www/site 属主为 deploy:deploy,权限为 750www-data 不在 deploy 组,无法进入。

  1. 检查目标目录:
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
  1. 如果 /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 文件权限错误都可以定位到具体层级,再用最小权限原则进行修复。

上一篇 海外服务器部署Next.js SSR站点,PM2、Nginx反向代理与HTTPS配置如何配合 下一篇 香港节点网站访问速度慢,性能测试应同时看TTFB、带宽与应用耗时

LHIDC 产品中心

继续查看可购买的海外服务器产品

文章用于辅助选型,最终价格、库存与配置请以产品详情页和下单页面展示为准。

查看产品 查看方案