From d435aaf4a8b97bf5c3b7467b5c58783c3811e1be Mon Sep 17 00:00:00 2001 From: ZF sun <34314687@qq.com> Date: Mon, 5 Jan 2026 15:55:11 +0800 Subject: [PATCH] =?UTF-8?q?chore(docker):=20=E4=B8=8D=E9=9C=80=E8=A6=81?= =?UTF-8?q?=E7=9A=84docker=E8=AE=BE=E7=BD=AE=E5=8F=96=E6=B6=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env | 1 - .env.development | 1 - .env.example | 1 - .env.production | 24 + .env.staging | 24 + .env.local => .env.test | 15 +- docker-compose.local.yml | 118 ----- docker-compose.yml | 9 +- docker/mysql/init/init.sql | 2 +- docker/mysql_db_data/.gitignore | 15 +- docker/nginx/Dockerfile | 48 +- docker/nginx/entrypoint.sh | 18 + docker/php/entrypoint.sh | 411 ++++++++++++++---- docker/php/supervisord.conf | 15 +- docker/redis_data/.gitignore | 15 +- src/{.env.local => .env.staging} | 2 +- src/.env.test | 24 + .../think-cron/src/cron/command/Schedule.php | 2 +- 18 files changed, 464 insertions(+), 281 deletions(-) create mode 100644 .env.production create mode 100644 .env.staging rename .env.local => .env.test (68%) delete mode 100644 docker-compose.local.yml create mode 100644 docker/nginx/entrypoint.sh rename src/{.env.local => .env.staging} (87%) create mode 100644 src/.env.test diff --git a/.env b/.env index 3f0ce1603..bfb9c9de4 100644 --- a/.env +++ b/.env @@ -21,5 +21,4 @@ REDIS_PORT=6399 # Nginx 配置 NGINX_PORT=8010 -NGINX_SSL_PORT=8012 diff --git a/.env.development b/.env.development index 2be4c5f1f..b0685bf60 100644 --- a/.env.development +++ b/.env.development @@ -21,5 +21,4 @@ REDIS_PORT=6499 # Nginx 暴漏端口 NGINX_PORT=8050 -NGINX_SSL_PORT=8052 diff --git a/.env.example b/.env.example index bc9c1a52a..f40b6d225 100644 --- a/.env.example +++ b/.env.example @@ -21,4 +21,3 @@ REDIS_PORT=6399 # Nginx 配置 NGINX_PORT=8010 -NGINX_SSL_PORT=8012 diff --git a/.env.production b/.env.production new file mode 100644 index 000000000..b1bced426 --- /dev/null +++ b/.env.production @@ -0,0 +1,24 @@ +# 项目配置, 请根据实际情况修改 +PROJECT_NAME=newshop + +# ThinkPHP 6.x 配置, 请根据实际情况修改 +APP_ENV=production + +# PHP/PHP-FPM 配置 +PHP_VERSION=7.4 +PHP_FPM_VERSION=7.4-fpm + +# 数据库配置 +MYSQL_ROOT_HOST=% +MYSQL_DATABASE=shop_mallnew +MYSQL_USER=shop_mallnew +MYSQL_PASSWORD=shop_mallnew +MYSQL_PORT=3926 + +# Redis 绑定端口及密码 +REDIS_PASSWORD=luckyshop123!@# +REDIS_PORT=6829 + +# Nginx 暴漏端口 +NGINX_PORT=8858 + diff --git a/.env.staging b/.env.staging new file mode 100644 index 000000000..9a1abbca9 --- /dev/null +++ b/.env.staging @@ -0,0 +1,24 @@ +# 项目配置, 请根据实际情况修改 +PROJECT_NAME=newshop + +# ThinkPHP 6.x 配置, 请根据实际情况修改 +APP_ENV=staging + +# PHP/PHP-FPM 配置 +PHP_VERSION=7.4 +PHP_FPM_VERSION=7.4-fpm + +# 数据库配置 +MYSQL_ROOT_HOST=% +MYSQL_DATABASE=shop_mallnew +MYSQL_USER=shop_mallnew +MYSQL_PASSWORD=shop_mallnew +MYSQL_PORT=3826 + +# Redis 绑定端口及密码 +REDIS_PASSWORD=luckyshop123!@# +REDIS_PORT=6809 + +# Nginx 暴漏端口 +NGINX_PORT=8854 + diff --git a/.env.local b/.env.test similarity index 68% rename from .env.local rename to .env.test index 9613e477c..f424f79bc 100644 --- a/.env.local +++ b/.env.test @@ -2,7 +2,7 @@ PROJECT_NAME=newshop # ThinkPHP 6.x 配置, 请根据实际情况修改 -APP_ENV=local +APP_ENV=test # PHP/PHP-FPM 配置 PHP_VERSION=7.4 @@ -10,16 +10,15 @@ PHP_FPM_VERSION=7.4-fpm # 数据库配置 MYSQL_ROOT_HOST=% -MYSQL_DATABASE=shop_dev +MYSQL_DATABASE=shop_mallnew MYSQL_USER=shop_mallnew MYSQL_PASSWORD=shop_mallnew -MYSQL_PORT=3316 +MYSQL_PORT=3346 -# Redis 配置 +# Redis 绑定端口及密码 REDIS_PASSWORD=luckyshop123!@# -REDIS_PORT=6399 +REDIS_PORT=6799 -# Nginx 配置 -NGINX_PORT=8010 -NGINX_SSL_PORT=8012 +# Nginx 暴漏端口 +NGINX_PORT=8360 diff --git a/docker-compose.local.yml b/docker-compose.local.yml deleted file mode 100644 index 8401e4e0a..000000000 --- a/docker-compose.local.yml +++ /dev/null @@ -1,118 +0,0 @@ -# 特别说明,本地local环境,方便操作,所以未使用的统一的docker-compose.yml文件,只保留了local环境的配置 - -x-shared-env: &shared-api-env - MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-rootpassword} - MYSQL_ROOT_HOST: ${MYSQL_ROOT_HOST:-'%'} # 允许root从任何主机连接 - MYSQL_DATABASE: ${MYSQL_DATABASE:-shop_mallnew} - MYSQL_USER: ${MYSQL_USER:-shop_mallnew} - MYSQL_PASSWORD: ${MYSQL_PASSWORD:-shop_mallnew} - - REDIS_PASSWORD: ${REDIS_PASSWORD:-luckyshop123!@#} - REDIS_PORT: ${REDIS_PORT:-6379} - -# 将服务归类到目录 A 中 -services: - php-fpm: - build: - context: ./docker/php - dockerfile: Dockerfile - container_name: ${PROJECT_NAME}_php - restart: always - extra_hosts: - - "host.docker.internal:host-gateway" # 支持主机名解析 - environment: - PHP_ENV: ${PHP_ENV:-development} - # 环境变量, APP_ENV 应用于 ThinkPHP 6.x 框架, .env.local 要想启用,需要在项目根目录下创建 .env.local 文件,并将 APP_ENV 设置为 local - # 同理,如果要启用开发环境,则将 APP_ENV 设置为 development,如果要启用生产环境,则将 APP_ENV 设置为 production - # 不然,ThinkPHP 6.x 系列,会只加载 .env 文件,而不会加载 .env.local 文件,导致 .env.local 文件中的配置不会生效 - APP_ENV: ${APP_ENV:-local} - APP_DEBUG: ${APP_DEBUG:-true} - volumes: - - ./:/var/www/all_source - - ./src:/var/www/html - # 更新下载源列表以加速apt-get - - ./docker/debian/sources.list:/etc/apt/sources.list:ro - - ./docker/php/php.ini:/usr/local/etc/php/php.ini:ro - depends_on: - - db - healthcheck: - test: ["CMD", "bash", "-c", "curl -f http://localhost:9000/status"] - interval: 30s - timeout: 10s - retries: 3 - start_period: 60s - networks: - - sass-platform-net - labels: - - "com.docker.compose.project.working_dir=${PROJECT_NAME}" - - nginx: - build: - context: ./docker/nginx - dockerfile: Dockerfile - container_name: ${PROJECT_NAME}_nginx - restart: always - ports: - - "${NGINX_PORT:-80}:80" - - "${NGINX_SSL_PORT:-443}:443" - volumes: - # 挂载项目代码到 Nginx 容器中 - - ./src:/var/www/html:rw - # 更新下载源列表以加速apt-get - - ./docker/debian/sources.list:/etc/apt/sources.list:ro - # 创建临时目录 - - /var/www/server/nginx/proxy_temp_dir - - /var/www/server/nginx/proxy_cache_dir - depends_on: - - php-fpm - networks: - - sass-platform-net - labels: - - "com.docker.compose.project.working_dir=${PROJECT_NAME}" - - db: - image: mysql:5.7.44 - container_name: ${PROJECT_NAME}_mysql - environment: - <<: *shared-api-env - volumes: - - mysql_db_data:/var/lib/mysql - - ./docker/mysql/init:/docker-entrypoint-initdb.d - - ./docker/mysql/my.cnf:/etc/mysql/conf.d/custom.cnf - ports: - - ${MYSQL_PORT:-3306}:3306 - networks: - - sass-platform-net - restart: unless-stopped - command: - - --character-set-server=utf8mb4 - - --collation-server=utf8mb4_unicode_ci - - --innodb_buffer_pool_size=256M - labels: - - "com.docker.compose.project.working_dir=${PROJECT_NAME}" - - # Redis 服务(可选) - redis: - image: redis:8.2 - container_name: ${PROJECT_NAME}_redis - environment: - REDIS_PASSWORD: ${REDIS_PASSWORD:-luckyshop123!@#} - REDISCLI_AUTH: ${REDIS_PASSWORD:-luckyshop123!@#} - ports: - - "${REDIS_PORT:-6379}:6379" - volumes: - - redis_data:/data - - ./docker/redis/redis.conf:/etc/redis/redis.conf - networks: - - sass-platform-net - restart: unless-stopped - labels: - - "com.docker.compose.project.working_dir=${PROJECT_NAME}" - -volumes: - mysql_db_data: - redis_data: - -networks: - sass-platform-net: - driver: bridge \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index e86b54f85..bfd6b3427 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -25,9 +25,13 @@ services: # 不然,ThinkPHP 6.x 系列,会只加载 .env 文件,而不会加载 .env.local 文件,导致 .env.local 文件中的配置不会生效 APP_ENV: ${APP_ENV:-development} APP_DEBUG: ${APP_DEBUG:-true} + # PHP应用根目录(可选,默认 /var/www/html) + PHP_APP_ROOT: ${PHP_APP_ROOT:-/var/www/html} + # 用户ID映射(可选,用于解决挂载权限问题) + USER_ID: ${USER_ID:-33} + GROUP_ID: ${GROUP_ID:-33} volumes: - - ./:/var/www/all_source - - ./src:/var/www/html + - ./src:/var/www/html:rw # 更新下载源列表以加速apt-get - ./docker/debian/sources.list:/etc/apt/sources.list:ro - ./docker/php/php.ini:/usr/local/etc/php/php.ini:ro @@ -52,7 +56,6 @@ services: restart: always ports: - "${NGINX_PORT:-80}:80" - - "${NGINX_SSL_PORT:-443}:443" volumes: # 挂载项目代码到 Nginx 容器中 - ./src:/var/www/html:rw diff --git a/docker/mysql/init/init.sql b/docker/mysql/init/init.sql index 85ba331ce..5c01ec271 100644 --- a/docker/mysql/init/init.sql +++ b/docker/mysql/init/init.sql @@ -4231,7 +4231,7 @@ CREATE TABLE `lucky_member_label` ( `sort` int(11) NOT NULL DEFAULT '0' COMMENT '排序', INDEX IDX_nc_member_label_label_id (`label_id`), PRIMARY KEY (`label_id`) USING BTREE, - KEY `IDX_nc_member_label_label_id` (`label_id`) USING BTREE + KEY `IDX_nc_member_label_label_id_key` (`label_id`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='会员标签'; /*!40101 SET character_set_client = @saved_cs_client */; diff --git a/docker/mysql_db_data/.gitignore b/docker/mysql_db_data/.gitignore index 650a912c6..bd33cd36e 100644 --- a/docker/mysql_db_data/.gitignore +++ b/docker/mysql_db_data/.gitignore @@ -1,10 +1,9 @@ -# 忽略目录下所有文件和子目录 +# 忽略所有文件 * -# 忽略所有子目录 -*/ -# 但不忽略 .gitkeep 文件 -!.gitkeep -# 不忽略 .gitignore 文件自身 + +# 只保留指定的 .gitkeep 文件 !.gitignore -# 不忽略 development/.gitkeep 文件 -!development/.gitkeep \ No newline at end of file +!development/.gitkeep +!test/.gitkeep +!production/.gitkeep +!staging/.gitkeep \ No newline at end of file diff --git a/docker/nginx/Dockerfile b/docker/nginx/Dockerfile index 4a9e7d831..6a504e405 100644 --- a/docker/nginx/Dockerfile +++ b/docker/nginx/Dockerfile @@ -1,29 +1,21 @@ -FROM nginx:alpine - -# 删除默认配置 -RUN rm /etc/nginx/conf.d/default.conf - -# -# - ./.docker/nginx/conf.c:/etc/nginx/conf.c:ro -# - ./.docker/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro -# - ./.docker/nginx/sites-enabled:/etc/nginx/sites-enabled:ro -# 将本地 nginx 配置复制到镜像中并设置为只读 -COPY ./conf.c /etc/nginx/conf.c -COPY ./default.conf /etc/nginx/conf.d/default.conf -COPY ./sites-enabled /etc/nginx/sites-enabled - -# 设置只读权限(文件 0444,目录及其内容 0555) -RUN chmod 0444 /etc/nginx/conf.c \ - && chmod 0444 /etc/nginx/conf.d/default.conf \ - && chmod -R 0555 /etc/nginx/sites-enabled - -# 设置工作目录 -WORKDIR /var/www/html - -# 创建日志目录 -RUN mkdir -p /var/log/nginx - -# 暴露端口 -EXPOSE 80 443 - +FROM nginx:alpine + +# 删除默认配置 +RUN rm /etc/nginx/conf.d/default.conf + + +# 将本地 nginx 配置复制到镜像中 +COPY ./conf.c/ /etc/nginx/conf.c/ +COPY ./default.conf /etc/nginx/conf.d/default.conf +COPY ./sites-enabled/ /etc/nginx/sites-enabled/ + +# 暴露端口 +EXPOSE 80 443 + +# 添加在Dockerfile末尾,CMD命令之前 +COPY ./entrypoint.sh /usr/local/bin/ +RUN chmod +x /usr/local/bin/entrypoint.sh +ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] + +# 启动nginx CMD ["nginx", "-g", "daemon off;"] \ No newline at end of file diff --git a/docker/nginx/entrypoint.sh b/docker/nginx/entrypoint.sh new file mode 100644 index 000000000..eb3a2d224 --- /dev/null +++ b/docker/nginx/entrypoint.sh @@ -0,0 +1,18 @@ +#!/bin/bash +set -e + +echo "=== NGINX Docker 权限初始化 ===" + +# 设置权限 +chmod -R 0444 /etc/nginx/conf.c +chmod 0444 /etc/nginx/conf.d/default.conf +chmod -R 0755 /etc/nginx/sites-enabled + + +# 创建日志目录 +mkdir -p /var/log/nginx + +echo "=== NGINX Docker 权限初始化完成 ===" + +# 执行原有的启动命令 +exec "$@" \ No newline at end of file diff --git a/docker/php/entrypoint.sh b/docker/php/entrypoint.sh index 7dbcf6075..a55ef76a7 100644 --- a/docker/php/entrypoint.sh +++ b/docker/php/entrypoint.sh @@ -1,112 +1,343 @@ #!/bin/bash -set -e +# 移除 set -e 以便更好的错误控制 -echo "=== ThinkPHP Docker权限初始化 ===" +echo "=== Web应用权限初始化 ===" -# 定义应用根目录 -APP_ROOT="/var/www/html" +# 定义应用根目录,优先使用环境变量,否则使用默认值 +APP_ROOT="${PHP_APP_ROOT:-/var/www/html}" -# 获取正确的用户和组 -if [ -n "$USER_ID" ] && [ -n "$GROUP_ID" ]; then - # 如果指定了用户ID,修改www-data - usermod -u $USER_ID www-data - groupmod -g $GROUP_ID www-data +echo "使用应用根目录: $APP_ROOT" + +# 如果应用根目录不存在,则跳过权限设置 +if [ ! -d "$APP_ROOT" ]; then + echo "❌ 应用根目录:'$APP_ROOT'不存在,跳过权限设置" + exit 1 fi +# 创建统一的Web组并配置所有用户(最高效的权限管理) +configure_web_users() { + # 常见Web服务器用户列表 + WEB_USERS=("www-data" "www" "apache" "nginx") + + # 获取环境变量中的用户ID + TARGET_UID=${USER_ID:-33} + TARGET_GID=${GROUP_ID:-33} + + echo "配置统一Web组权限,目标UID:GID = $TARGET_UID:$TARGET_GID" + + # 创建统一的Web组(增强错误处理) + WEB_GROUP="webaccess" + if ! getent group "$WEB_GROUP" &>/dev/null; then + echo "创建统一Web组: $WEB_GROUP" + + # 尝试使用指定GID创建组 + if groupadd -g $TARGET_GID "$WEB_GROUP" 2>/dev/null; then + echo "✅ 统一Web组创建成功,GID: $TARGET_GID" + else + echo "⚠️ GID $TARGET_GID 已被占用,尝试自动分配GID" + + # 尝试不指定GID创建组 + if groupadd "$WEB_GROUP" 2>/dev/null; then + ACTUAL_GID=$(getent group "$WEB_GROUP" | cut -d: -f3) + echo "✅ 统一Web组创建成功,自动分配GID: $ACTUAL_GID" + else + echo "❌ 创建 $WEB_GROUP 组失败,尝试使用备用方案" + + # 备用方案:使用现有的www-data组 + if getent group "www-data" &>/dev/null; then + WEB_GROUP="www-data" + echo "🔄 使用现有的www-data组作为统一组" + else + echo "❌ 备用方案也失败,权限配置可能不完整" + WEB_GROUP="" + fi + fi + fi + else + ACTUAL_GID=$(getent group "$WEB_GROUP" | cut -d: -f3) + echo "✅ 统一Web组 $WEB_GROUP 已存在,GID: $ACTUAL_GID" + fi + + # 最终验证组是否存在 + if [ -z "$WEB_GROUP" ] || ! getent group "$WEB_GROUP" &>/dev/null; then + echo "❌ 无法创建或找到可用的Web组,权限配置将受限" + return 1 + fi + + # 只将已存在的Web用户加入统一组(增强错误处理) + success_count=0 + total_users=0 + + for web_user in "${WEB_USERS[@]}"; do + total_users=$((total_users + 1)) + + if id "$web_user" &>/dev/null; then + echo "📝 处理Web用户: $web_user" + + # 获取用户当前组信息(安全的变量处理) + current_groups=$(id -Gn "$web_user" 2>/dev/null | tr '\n' ' ' | sed 's/ *$//') + echo " 当前所属组: ${current_groups:-无}" + + # 尝试将用户加入统一组(使用-a参数保留现有组,只添加新组) + if usermod -a -G "$WEB_GROUP" "$web_user" 2>/dev/null; then + echo " ✅ 成功将 $web_user 添加到统一组 $WEB_GROUP" + success_count=$((success_count + 1)) + else + echo " ⚠️ 无法将 $web_user 添加到统一组,尝试设置主组" + + # 备用方案:设置主组 + if usermod -g "$WEB_GROUP" "$web_user" 2>/dev/null; then + echo " ✅ 成功将 $web_user 主组设置为 $WEB_GROUP" + success_count=$((success_count + 1)) + else + echo " ❌ 无法配置 $web_user 的组权限" + fi + fi + else + echo "⚭ Web用户 $web_user 不存在,跳过" + fi + done + + echo "📊 用户配置汇总: $success_count/$total_users 个Web用户配置成功" + + # 至少要有一个用户配置成功 + if [ $success_count -eq 0 ]; then + echo "⚠️ 没有Web用户被成功配置,但继续执行" + fi + + echo "统一Web组配置完成" +} + +# 错误处理:如果配置失败,不要终止整个脚本 +configure_web_users || echo "⚠️ Web用户配置出现问题,但继续执行权限设置" + echo "当前用户: $(whoami)" echo "UID: $(id -u), GID: $(id -g)" -# 修复目录所有权和权限 -fix_directory_permissions() { - local dir=$1 - echo "修复PHP目录权限: $dir" +# 修复所有目录权限(使用统一Web组,最高效的权限管理) +if [ -d "$APP_ROOT" ]; then + # 重新获取最终的WEB_GROUP(可能已被修改) + FINAL_WEB_GROUP="" - # 确保目录存在 - mkdir -p "$dir" - - # 设置所有权 - chown -R www-data:www-data "$dir" - - # 设置权限 - chmod -R 775 "$dir" - - # 设置setgid权限 - chmod g+s "$dir" - - # 尝试设置ACL(如果支持) - if command -v setfacl >/dev/null 2>&1; then - setfacl -dR -m u:www-data:rwx "$dir" + # 首选:使用创建的webaccess组 + if getent group "webaccess" &>/dev/null; then + FINAL_WEB_GROUP="webaccess" + echo "🎯 使用创建的统一Web组: $FINAL_WEB_GROUP" + # 备选:使用www-data组 + elif getent group "www-data" &>/dev/null; then + FINAL_WEB_GROUP="www-data" + echo "🔄 回退到www-data组: $FINAL_WEB_GROUP" + # 最后:使用当前用户的组 + else + CURRENT_USER=$(whoami) + CURRENT_GROUP=$(id -gn "$CURRENT_USER") + FINAL_WEB_GROUP="$CURRENT_GROUP" + echo "🔧 使用当前用户组: $FINAL_WEB_GROUP" + fi + + # 最终验证 + if [ -z "$FINAL_WEB_GROUP" ]; then + echo "❌ 无法确定有效的Web组,跳过权限设置" + echo "=== 启动应用 ===" + exec "$@" + fi + + WEB_GROUP="$FINAL_WEB_GROUP" + WEB_GROUP_GID=$(getent group "$WEB_GROUP" | cut -d: -f3) + echo "✅ 最终使用Web组: $WEB_GROUP (GID: $WEB_GROUP_GID)" + echo "🔒 统一组权限模式:所有Web用户通过组继承权限" + + # 设置所有权为统一Web组(增强错误处理) + echo "📁 设置应用目录所有权为统一Web组" + CURRENT_USER=$(whoami) + + if chown -R $CURRENT_USER:$WEB_GROUP "$APP_ROOT" 2>/dev/null; then + echo "✅ 所有权设置成功: $CURRENT_USER:$WEB_GROUP" + else + echo "⚠️ 所有权设置失败,尝试只设置组权限" + chgrp -R "$WEB_GROUP" "$APP_ROOT" 2>/dev/null || echo "❌ 组权限设置也失败" + fi + + # 设置目录权限为775(组权限为rwx,所有组内用户都有完整权限) + echo "🔐 设置目录权限775,文件权限664" + + # 使用更安全的权限设置方式,避免权限被拒绝 + dir_count=0 + file_count=0 + + # 设置目录权限(兼容性更好的方式) + if command -v find >/dev/null 2>&1; then + dir_count=$(find "$APP_ROOT" -type d -exec chmod 775 {} \; 2>/dev/null | wc -l) + file_count=$(find "$APP_ROOT" -type f -exec chmod 664 {} \; 2>/dev/null | wc -l) + find "$APP_ROOT" -type d -exec chmod g+s {} \; 2>/dev/null + else + # 备用方案:使用简单的循环 + echo "find命令不可用,跳过批量权限设置" + dir_count=0 + file_count=0 + fi + + echo "📊 权限设置完成: $dir_count个目录, $file_count个文件" + + echo "✅ 统一组权限设置完成,所有Web用户通过组获得权限" + + # 设置ACL(如果支持,只需设置统一组) + if command -v setfacl >/dev/null 2>&1; then + echo "🔒 设置ACL权限(只需设置统一Web组)" + + acl_success=0 + + # 只为统一Web组设置ACL权限(限制处理深度) + if setfacl -R -m g:$WEB_GROUP:rwx "$APP_ROOT" 2>/dev/null; then + echo " ✅ 设置组ACL权限成功" + acl_success=$((acl_success + 1)) + else + echo " ❌ 设置组ACL权限失败" + fi + + # 设置默认ACL权限(新创建的文件自动继承权限) + if setfacl -dR -m g:$WEB_GROUP:rwx "$APP_ROOT" 2>/dev/null; then + echo " ✅ 设置默认ACL权限成功" + acl_success=$((acl_success + 1)) + else + echo " ❌ 设置默认ACL权限失败" + fi + + if [ $acl_success -eq 2 ]; then + echo "🎉 统一组ACL设置完成,所有组内用户自动获得权限" + elif [ $acl_success -eq 1 ]; then + echo "⚠️ ACL部分设置成功,建议检查文件系统ACL支持" + else + echo "❌ ACL设置完全失败,文件系统可能不支持ACL" + fi + else + echo "ℹ️ ACL不支持,依赖传统权限模式" + echo "✅ 775权限已足够,所有组内用户都有rwx权限" fi - - find "$dir" -type d -exec chmod 775 {} \; - find "$dir" -type f -exec chmod 775 {} \; - find "$dir" -type d -exec chmod g+s {} \; - find "$dir" -type f -exec chmod g+s {} \; # 设置umask umask 0002 + + echo "✅ 应用目录权限修复完成" - echo "✅ $dir 权限设置完成, 目录权限: $(stat -c '%a %n' "$dir"), setgid权限: $(stat -c '%a %n' "$dir" | grep 's')" -} - -# 处理所有需要权限的目录 -directories=("runtime" "upload" "runtime/log" "runtime/cache" "runtime/temp") -for dir in "${directories[@]}"; do - fix_directory_permissions "$APP_ROOT/$dir" -done - - -# 验证权限 -echo "=== 权限验证 ===" -echo "当前用户: $(whoami)" -echo "当前UID: $(id -u), GID: $(id -g)" -echo "当前umask: $(umask)" - -# 验证www-data用户是否可以在runtime和upload目录下新建子目录 - -# 方法1:使用sudo -if command -v sudo >/dev/null 2>&1; then - echo "使用sudo测试..." - if sudo -u www-data mkdir -p $APP_ROOT/runtime/log/test_dir 2>/dev/null; then - echo "✅ sudo: runtime目录创建子目录成功 [使用www-data用户]" - rm -rf $APP_ROOT/runtime/log/test_dir + # 验证文件权限是否足够(测试统一组权限效果) + echo "=== 验证统一组权限效果 ===" + + # 查找测试文件的更可靠方法 + test_file="" + + # 方法1: 查找index.html + if [ -f "$APP_ROOT/index.html" ]; then + test_file="$APP_ROOT/index.html" + fi + + # 方法2: 查找任意HTML文件(更安全的方式) + if [ -z "$test_file" ]; then + first_html=$(find "$APP_ROOT" -maxdepth 2 -name "*.html" -type f 2>/dev/null | head -1) + if [ -n "$first_html" ] && [ -f "$first_html" ]; then + test_file="$first_html" + fi + fi + + # 方法3: 查找index.php + if [ -z "$test_file" ] && [ -f "$APP_ROOT/index.php" ]; then + test_file="$APP_ROOT/index.php" + fi + + # 方法4: 创建专用测试文件(最安全的选择) + if [ -z "$test_file" ]; then + test_file="$APP_ROOT/.permission_test.html" + echo "创建专用权限测试文件" + cat > "$test_file" << 'EOF' + + +