fix: 修复项目目录和静态文件权限

This commit is contained in:
kuaifan 2026-07-24 16:20:10 +08:00
parent b914a99b62
commit 08da0b8976
2 changed files with 110 additions and 44 deletions

View File

@ -1,64 +1,79 @@
---
name: dootask-fix-permission
description: 修复 DooTask 可写目录bootstrap/cache、docker、public、storage的属主/权限chown 回当前用户 + 目录 chmod 775对齐 install 的赋权逻辑,赋权不删数据。
description: 修复 DooTask 整个项目的目录和文件权限:根目录 chmod 755bootstrap/cache、docker、public、storage chown 回调用用户且目录 chmod 775public 文件补充所有用户读权限。用于 Nginx 静态文件 403/Permission denied、install/build EACCES 或可写目录检测失败;优先使用 sudo ./cmd permission,赋权不删数据。
---
# DooTask 目录权限修复
容器内进程常以 **root** 写入挂载目录(`storage``public/uploads``bootstrap/cache` 等),导致宿主机当前用户对这些文件**没有写权限**,进而触发
项目根目录如果缺少 `x` 穿越权限Nginx 即使看到 `public` 中的文件也无法访问。容器内进程常以 **root** 写入挂载目录(`storage``public/uploads``bootstrap/cache` 等),导致宿主机当前用户没有写权限。常见现象
- `./cmd install` 报「目录【xxx】权限不足」/ 目录权限检测失败
- `./cmd build`vite`EACCES: permission denied, copyfile`(复制 `public/uploads/...` 时)
- Nginx 日志出现 `stat() failed (13: Permission denied)`,静态文件请求被回退到 Laravel 首页
- `./cmd install` 报「目录【xxx】权限不足」/目录权限检测失败
- `./cmd build`vite`EACCES: permission denied, copyfile`
- Laravel 运行时写 `storage`/`bootstrap/cache` 失败
本技能**对齐 `./cmd install` 的目录赋权逻辑**:对四个可写目录做 `chmod 775`(目录)+ `chown` 回当前用户
对齐 `./cmd permission`/`./cmd install` 的赋权逻辑:项目根目录设为 `755`;四个可写目录做 `chmod 775`(仅目录)+ `chown` 回调用 sudo 的用户;`public` 普通文件用 `a+r` 补充 Nginx 所需读权限
## 适用目录
与 install 一致的四个:
```
```text
. # 项目根目录,只修本层为 755
bootstrap/cache
docker
public # 含 public/uploads真实上传数据
public # 目录 775普通文件 a+r含真实上传数据
storage
```
## 核心原则:赋权,不删数据
`public/uploads` 含真实上传文件(头像、附件等)**永远优先 `chown` 改属主,不要删数据。** 即便用户说"清理一下",也只允许清临时目录 `public/uploads/tmp`**切勿**删 uploads 下其他内容。
`public/uploads` 含真实上传文件。永远优先 `chown` 改属主,不要删数据。即便用户说“清理一下”,也只允许清理临时目录 `public/uploads/tmp`,切勿删除 uploads 下其他内容。
## 前置检查
1. **工作目录**:在项目根(存在 `cmd` 且这四个目录在)
2. **sudo**:改属主需 root当前文件多为 root 属主)。本机一般可免密 sudo不行则经 docker 以 root 改权限
3. 确认要修的范围:默认四个目录全修;若用户只想解 build 报错,也可只针对 `public`(含 `public/uploads`
1. 在项目根目录执行,确认存在 `cmd` 和上述四个目录。
2. 用 `ls -ld .` 检查项目根目录是否缺少组/其他用户的 `x` 穿越权限。
3. 确认可使用 sudo改 root 属主的文件或目录需要 root 权限。
4. 用 `find public -type f ! -perm -004 -print` 检查 Nginx 用户可能无法读取的静态文件。
5. 默认修复项目根目录、四个可写目录和 `public` 文件;若用户只想解决 build 的 uploads 报错,可只处理 `public/uploads`
检查通过后汇报将执行的命令,**向用户确认一次**再执行。
检查通过后汇报将执行的命令,向用户确认一次再执行。
## 执行
确认后执行(属主修回当前用户,目录权限 775
确认后优先执行独立权限修复命令(不依赖 Docker 正在运行
```shell
# 1) 属主修回当前用户(递归)
sudo chown -R "$(id -u):$(id -g)" bootstrap/cache docker public storage
# 2) 目录权限 775仅目录对齐 install 的 `find -type d -exec chmod 775`
find bootstrap/cache docker public storage -type d -exec chmod 775 {} \;
sudo ./cmd permission
```
> 只想解 build 的 uploads 报错时,可只对 `public`
> ```shell
> sudo chown -R "$(id -u):$(id -g)" public/uploads
> ```
旧版 `cmd` 没有 `permission` 命令时,手动执行:
执行后报告:改了哪些目录、属主/权限现状(可 `ls -ld` 抽查),并提示用户可重试之前失败的 install/build/update。
```shell
# 1) 保证 Nginx 可穿越项目根目录(不递归)
sudo chmod 755 .
# 2) 可写目录属主修回当前用户(递归)
sudo chown -R "$(id -u):$(id -g)" bootstrap/cache docker public storage
# 3) 可写目录权限 775仅目录
find bootstrap/cache docker public storage -type d -exec chmod 775 {} \;
# 4) public 普通文件只补充读权限,保留现有写入/执行位
find public -type f -exec chmod a+r {} \;
```
只想解决 build 的 uploads 报错时,可只执行:
```shell
sudo chown -R "$(id -u):$(id -g)" public/uploads
```
执行后用 `ls -ld . bootstrap/cache docker public storage` 抽查目录,并用 `find public -type f ! -perm -004 -print` 确认不再有缺少 others 读权限的静态文件。然后重试之前失败的静态文件访问、install/build/update。
## 失败处理
- `chown` 报权限不足 → 当前用户无 sudo 权限,提示用户用有 root 权限的账户,或经 docker 以 root 执行;不要静默跳过
- 任何步骤失败立即停止报告,不自动重试
- `chmod`/`chown` 报权限不足:立即停止,提示使用有 root 权限的账户,或经 docker 以 root 执行;不要静默跳过
- 任何步骤失败立即停止报告,不自动重试
## 禁止项
@ -66,11 +81,15 @@ find bootstrap/cache docker public storage -type d -exec chmod 775 {} \;
|---------|---------|
| build 报 uploads EACCES 就 `rm` 删文件 | `chown` 修属主,保留数据 |
| 删整个 `public/uploads` 清场 | 最多清 `public/uploads/tmp`,别碰真实上传数据 |
| 对文件无差别 `chmod 777` | 目录 `chmod 775` + `chown` 回当前用户即可 |
| 对文件无差别 `chmod 777` | 可写目录 `chmod 775` + `chown` 回当前用户 |
| 把 `public` 所有文件强制改为 `644` | 用 `chmod a+r` 只补读权限,保留现有权限位 |
| 递归 `chmod 755` 整个项目 | 只对项目根目录执行 `chmod 755 .` |
| 不加 sudo 直接 chown root 文件 | 改属主需 root |
## Red Flags —— 出现这些念头立即停下
## Red Flags
- "uploads 复制失败,删掉再 build" → 不,`chown` 赋权,不丢数据
- "777 一把梭最省事" → 不,按 install 的 775目录+ chown
- "权限不够就跳过这个目录" → 不,报告交用户处理 sudo
- “uploads 复制失败,删掉再 build” → 不,`chown` 赋权,不丢数据。
- “777 一把梭最省事” → 不,按 install 的 775目录+ chown。
- “根目录不可穿越,递归 chmod 全仓库” → 不,只修项目根目录为 755。
- “静态文件 403给整个项目所有文件加读权限” → 不,只对 `public` 普通文件执行 `a+r`
- “权限不够就跳过这个目录” → 不,报告交用户处理 sudo。

71
cmd
View File

@ -63,6 +63,8 @@ msg() {
"端口 (*) 已被占用,请指定其他端口") out="Port (*) is already in use, please specify another port" ;;
"目录权限检测失败!请检查目录权限设置") out="Directory permission check failed! Please check directory permissions" ;;
"目录【(*)】权限不足!") out="Directory [(*)] is not writable!" ;;
"项目权限修复失败") out="Failed to repair project permissions" ;;
"项目权限修复完成") out="Project permissions repaired" ;;
"安装依赖失败") out="Failed to install dependencies" ;;
"安装依赖失败,请重试!") out="Failed to install dependencies, please retry!" ;;
"生成密钥失败") out="Failed to generate app key" ;;
@ -227,6 +229,49 @@ check_sudo() {
fi
}
# 修复项目权限
permission_fix() {
local owner_uid="${SUDO_UID:-$(id -u)}"
local owner_gid="${SUDO_GID:-$(id -g)}"
volumes=(
"bootstrap/cache"
"docker"
"public"
"storage"
)
chmod 755 "${WORK_DIR}"
if [ $? -ne 0 ]; then
error "$(msg '项目权限修复失败')"
exit 1
fi
for vol in "${volumes[@]}"; do
tmp_path="${WORK_DIR}/${vol}"
mkdir -p "${tmp_path}"
if [ $? -ne 0 ]; then
error "$(msg '项目权限修复失败')"
exit 1
fi
chown -R "${owner_uid}:${owner_gid}" "${tmp_path}"
if [ $? -ne 0 ]; then
error "$(msg '项目权限修复失败')"
exit 1
fi
find "${tmp_path}" -type d -exec chmod 775 {} \;
if [ $? -ne 0 ]; then
error "$(msg '项目权限修复失败')"
exit 1
fi
done
find "${WORK_DIR}/public" -type f -exec chmod a+r {} \;
if [ $? -ne 0 ]; then
error "$(msg '项目权限修复失败')"
exit 1
fi
}
# 检查docker、docker-compose
check_docker() {
docker --version &> /dev/null
@ -585,6 +630,7 @@ DooTask 管理脚本
install 安装 DooTask (支持 --port <端口> --relock)
update 更新 DooTask (支持 --branch <分支> --force --local)
uninstall 卸载 DooTask
permission 修复整个项目的权限
⚙️ 配置管理:
port <端口> 修改服务端口
@ -621,6 +667,7 @@ DooTask 管理脚本
示例:
./cmd install --port 8080 安装并指定端口 8080
./cmd update --branch dev 切换到 dev 分支并更新
./cmd permission 修复整个项目的权限
./cmd mysql backup 备份数据库
./cmd artisan migrate 执行数据库迁移
EOF
@ -634,6 +681,7 @@ Usage: ./cmd <command> [options]
install Install DooTask (supports --port <port> --relock)
update Update DooTask (supports --branch <branch> --force --local)
uninstall Uninstall DooTask
permission Repair permissions for the whole project
⚙️ Configuration:
port <port> Change service port
@ -670,6 +718,7 @@ Usage: ./cmd <command> [options]
Examples:
./cmd install --port 8080 Install on port 8080
./cmd update --branch dev Switch to dev branch and update
./cmd permission Repair permissions for the whole project
./cmd mysql backup Back up database
./cmd artisan migrate Run database migration
EOF
@ -714,20 +763,12 @@ handle_install() {
rm -rf node_modules package-lock.json vendor composer.lock
fi
# 目录权限设置
volumes=(
"bootstrap/cache"
"docker"
"public"
"storage"
)
# 目录和静态文件权限设置
permission_fix
cmda=""
cmdb=""
for vol in "${volumes[@]}"; do
tmp_path="${WORK_DIR}/${vol}"
mkdir -p "${tmp_path}"
find "${tmp_path}" -type d -exec chmod 775 {} \;
rm -f "${tmp_path}/dootask.lock"
cmda="${cmda} -v ${tmp_path}:/usr/share/${vol}"
cmdb="${cmdb} touch /usr/share/${vol}/dootask.lock &&"
@ -962,8 +1003,8 @@ if [[ "$1" == "help" ]] || [[ "$1" == "--help" ]] || [[ "$1" == "-h" ]] || [[ $#
exit 0
fi
# 非electron命令需要检查Docker环境
if [[ "$1" != "electron" ]]; then
# 非electron和permission命令需要检查Docker环境
if [[ "$1" != "electron" ]] && [[ "$1" != "permission" ]]; then
check_docker
env_init
fi
@ -982,6 +1023,12 @@ case "$1" in
shift 1
handle_uninstall
;;
"permission")
shift 1
check_sudo
permission_fix
success "$(msg '项目权限修复完成')"
;;
"port")
shift 1
check_port "$1" "$(env_get APP_PORT)"