目录不可写几乎从来不是 CMS 的 bug,而是「跑 PHP 的进程用户」和「目录属主」不是同一个人:安装前半程只读(探环境、连数据库),到写配置文件、建缓存目录那一步才需要写权限,所以才会卡在一半。结论:先查 PHP 进程以哪个用户运行,再把该用户设为安装目录的属主,而不是无脑 chmod 777。
为什么安装到一半才提示目录不可写?
结论:因为安装流程分两段,前一段只读、后一段写入,报错点正好卡在两段的分界线上。
典型 PHP CMS 的安装流程是:环境检测(PHP 版本、扩展、函数是否被禁用)→ 填写数据库信息 → 连接数据库、建表 → 写入 config.php/database.php 等配置文件 → 创建 uploads/、cache/、runtime/、data/ 等目录 → 生成 install.lock。前 3 步只需要「读」,第 4 步起才开始「写」。所以你会看到环境检测全绿、数据库连接成功,一切到「写入配置文件」就红字报错。
另一个常见触发点是上传解压:用面板或 unzip 解压的压缩包,文件属主可能是 root 或面板用户(如 www、nobody),而 Web 服务跑在 www-data 下,两边对不上,写入自然失败。
怎么确认是哪个用户在跑 PHP?
结论:用 ps 看进程属主最直接,别猜 nginx 的配置。
执行:
ps aux | grep -E 'php-fpm|php-cgi|apache2|httpd' | grep -v grep
第一列就是实际运行用户,常见的是 www-data(Debian/Ubuntu)、nginx 或 apache(CentOS/RHEL)、www(宝塔面板)。再对照目录属主:
ls -ld /www/wwwroot/你的站点
ls -l /www/wwwroot/你的站点/config.php
看第 3、4 列(属主:属组)。两边不一致,问题就定位完了。Note:PHP-FPM 的用户由 php-fpm.conf 或 pool 配置里的 user/group 决定,跟 nginx 的 user 指令不一定是同一个。
目录不可写怎么改?chmod 和 chown 该用哪个?
结论:优先 chown 改属主,权限位保持 755/644 即可;只有确实需要组内多用户共写时才用 775。
推荐命令(把 www-data 和路径换成你实际的值):
chown -R www-data:www-data /www/wwwroot/你的站点
find /www/wwwroot/你的站点 -type d -exec chmod 755 {} \;
find /www/wwwroot/你的站点 -type f -exec chmod 644 {} \;
如果安装程序明确要求某几个目录可写(uploads、cache、runtime、data、config),单独放宽:
chmod -R 775 /www/wwwroot/你的站点/{uploads,cache,runtime,data}
注意点:config.php 这类配置文件在上面的 find 之后是 644,对属主仍可写,够用;不要单独给它 777。
为什么给了 777 还是提示目录不可写?
结论:777 只解决 Unix 权限位,解决不了 SELinux、挂载只读、open_basedir 和容器卷这四类问题。
按顺序排查:
- SELinux 未放行:
getenforce 返回 Enforcing 时,用 chcon -R -t httpd_sys_rw_content_t /www/wwwroot/你的站点 授权,或临时 setenforce 0 验证。CentOS 系上这一条命中率很高。
- 目录被挂载为只读:
mount | grep 你的路径,出现 ro 就是只读挂载,改权限无效,需重新以 rw 挂载。
open_basedir 限制:phpinfo() 里搜 open_basedir,若安装目录不在白名单内,PHP 的 is_writable() 会直接返回 false。
- 容器/宝塔等面板:宿主机改了权限,容器内映射卷的属主仍可能是 root,要在容器内执行 chown,或调整
UID/GID 映射。
另外,Windows/IIS 环境下没有 chmod 这一说,要在目录属性的「安全」页给 IIS_IUSRS 或 IUSR 授予「修改」权限。
安装完成后权限要不要改回去?
结论:要,config.php 安装后建议收回为 644,安装锁文件不要删。
安装成功后,配置文件里已含数据库账号密码,把它设成 644(属主可读写、其他只读)即可,不必再留 775。同时保留 install.lock,它的作用是阻止他人重跑安装程序覆盖你的站点。上传目录 uploads/ 则长期保持可写,否则后台上传图片会继续报同样的错。
一句话总结:这个报错只说明「当前进程用户」对「目标路径」没有写权限,定位路径是 ps 看进程用户 → ls -ld 看目录属主 → 用 chown 对齐 → 再依次排除 SELinux、只读挂载、open_basedir 和容器卷这四种例外。