Alibaba Cloud Linux 3 +Docker 部署 ThinkPHP6 (宝塔环境)-问题篇

Docker部署ThinkPHP6常见问题

上篇文章介绍了具体的操作步骤,这里总结记录一下部署过程中遇到的问题:

这里注明一下,所有操作容器的命令要在项目目录(tp6)下运行,目录结构如下图:

宿主机(安装宝塔面板)

 ├─ /www/wwwroot/tp6 (项目目录)

      ├─app

      ├─config

      ├─public

      ├─vender

       ... ...

      ├─think

      ├─Dockerfile

      ├─docker-composer.yml

一、Nginx 报 “502 Bad Gateway”

1、排查问题及临时解决方案

步骤1:检查 PHP-FPM 是否正常运行并监听 9003 端口

首先需要找到运行 PHP-FPM 的容器,并确认其内部端口:

执行命令:

#列出所有运行中的容器

[root@iZ2ze8he63z0zt6g8kiae2Z tp6]# docker ps

#输出结果

CONTAINER ID   IMAGE                       COMMAND                  CREATED       STATUS       PORTS                                                 NAMES
7205b7c455d3   tp6-tp6-php-fpm             "docker-php-entrypoi…"   7 hours ago   Up 7 hours   9000/tcp, 0.0.0.0:9003->9003/tcp, :::9003->9003/tcp   tp6-tp6-php-fpm-1

关键信息:

  • 容器名称(如tp6-tp6-php-fpm-1

  • 端口映射(如9003:9000表示宿主机 9003 映射到容器内 9000 端口)

步骤 2:检查容器内 PHP-FPM 是否监听正确端口

进入容器内部,确认 PHP-FPM 实际监听的端口(通常是 9000,而非宿主机的 9003):

# 进入容器(替换容器ID或名称)
[root@iZ2ze8he63z0zt6g8kiae2Z tp6]# docker exec -it tp6-tp6-php-fpm-1 bash

# 在容器内执行,检查PHP-FPM监听端口
root@7205b7c455d3:/var/www/html# netstat -tlnp | grep php-fpm

运行结果:

tcp6       0      0 :::9000                 :::*                    LISTEN      1/php-fpm: master p 

根据运行结果,就可以确定Docker内部实际监听的端口是9000

在我们的Docker中,有一段代码如下图红框中部分就是用来修改 PHP-FPM 的监听端口,从默认的 9000 端口改为 9003 端口。

  • s/listen = 9000/listen = 9003/ 是替换规则,意思是将所有 "listen = 9000" 字符串替换为 "listen = 9003" ,这里是完全匹配的原则。

再看看容器内的www.conf中的内容,

# 进入容器(替换容器ID或名称)
[root@iZ2ze8he63z0zt6g8kiae2Z tp6]# docker exec -it tp6-tp6-php-fpm-1 bash


//编辑www.conf文件
root@7205b7c455d3:/usr/local/etc/php-fpm.d# vim /usr/local/etc/php-fpm.d/www.conf

如下图:

这里可以看到文件 中是 listen = 127.0.0.1:9000,按照匹配规则,肯定是修改不掉这部分的,所以,我们先临时修改一下(即:进入www.conf文件,修改内容 为 listen = 9003 保存退出)

ctrl + PQ键退出容器

# 重启容器(会自动加载修改后的配置)
[root@iZ2ze8he63z0zt6g8kiae2Z tp6]# docker restart tp6-tp6-php-fpm-1

等待5秒,再次进入容器,检查PHP-FPM监听的端口

# 进入容器(替换容器ID或名称)
[root@iZ2ze8he63z0zt6g8kiae2Z tp6]# docker exec -it tp6-tp6-php-fpm-1 bash

# 在容器内执行,检查PHP-FPM监听端口
root@7205b7c455d3:/var/www/html# netstat -tlnp | grep php-fpm

运行结果:

还是9000,可能存在多个配置文件:

#容器内直接搜索配置文件中的 listen 配置,查看都有哪些配置文件监听了9000端口
grep -r "listen = " /usr/local/etc/php-fpm.d/

运行结果:

这里看到以.conf结尾的文件有两个一个www.conf,一个是zz-docker.conf,zz-docker.conf文件中监听了9000端口,我们把这个也修改一下试试。

#修改配置文件listen = 9000 为 listen = 9003
vim /usr/local/etc/php-fpm.d/zz-docker.conf

退出容器,重启容器

ctrl + PQ键退出容器

#重启容器

docker restart tp6-tp6-php-fpm-1

等待5秒,再次进入容器,检查PHP-FPM监听的端口

​
# 进入容器(替换容器ID或名称)
[root@iZ2ze8he63z0zt6g8kiae2Z tp6]# docker exec -it tp6-tp6-php-fpm-1 bash

# 在容器内执行,检查PHP-FPM监听端口
root@7205b7c455d3:/var/www/html# netstat -tlnp | grep php-fpm

​

运行结果如下图:

监听接口正确了,我们再尝试打开网址,这时候显示404错误。

2、解决方案

前面我们讲述了502错误排查过程,以及临时的解决方案,之所以叫临时解决方案,是因为只要我们删除容器,再次创建我们修改的内容就会被覆盖,并重置为最初的状态。下面我们来尝试从创建容器时便设好监听端口。

方案一:只修改 zz-docker.conf(推荐)
# 基础镜像:PHP 8.1-FPM
FROM php:8.1-fpm

# 使用阿里云镜像源加速
RUN sed -i 's/deb.debian.org/mirrors.aliyun.com/g' /etc/apt/sources.list && \
    sed -i 's/security.debian.org/mirrors.aliyun.com/g' /etc/apt/sources.list

# 安装 ThinkPHP6 必需扩展
RUN apt-get update && apt-get install -y \
    net-tools \
    libfreetype6-dev \
    libjpeg62-turbo-dev \
    libpng-dev \
    libzip-dev \
    && rm -rf /var/lib/apt/lists/* \
    && docker-php-ext-configure gd --with-freetype --with-jpeg \
    && docker-php-ext-install -j$(nproc) gd pdo_mysql mysqli zip opcache

# 关键修正:只修改 zz-docker.conf(基于你的测试结果)
RUN sed -i 's/listen = 9000/listen = 9003/' /usr/local/etc/php-fpm.d/zz-docker.conf

# 可选:确保 www.conf 不会干扰(注释掉或删除其中的 listen 配置)
RUN sed -i 's/^listen = /;listen = /' /usr/local/etc/php-fpm.d/www.conf

# 配置 PHP 时区
RUN echo "date.timezone = Asia/Shanghai" >> /usr/local/etc/php/conf.d/docker-php-ext-timezone.ini

# 设置工作目录
WORKDIR /var/www/html

# 暴露端口
EXPOSE 9003
方案二:直接创建新的配置文件(最可靠)
FROM php:8.1-fpm

# ... 前面的安装步骤保持不变 ...

# 删除或注释所有现有的 listen 配置,创建统一的配置
RUN sed -i 's/^listen = /;listen = /' /usr/local/etc/php-fpm.d/www.conf && \
    sed -i 's/^listen = /;listen = /' /usr/local/etc/php-fpm.d/zz-docker.conf

# 创建新的监听配置
RUN echo '[www]' > /usr/local/etc/php-fpm.d/listen.conf && \
    echo 'listen = 9003' >> /usr/local/etc/php-fpm.d/listen.conf && \
    echo 'listen.allowed_clients = any' >> /usr/local/etc/php-fpm.d/listen.conf

# ... 后面的配置保持不变 ...
方案三:使用环境变量(Docker 官方推荐方式)
FROM php:8.1-fpm

# ... 前面的安装步骤保持不变 ...

# 确保 zz-docker.conf 使用环境变量(如果它支持)
# 或者直接替换 zz-docker.conf
RUN echo '[www]' > /usr/local/etc/php-fpm.d/zz-docker.conf && \
    echo 'listen = 9003' >> /usr/local/etc/php-fpm.d/zz-docker.conf && \
    echo 'listen.allowed_clients = any' >> /usr/local/etc/php-fpm.d/zz-docker.conf

# ... 后面的配置保持不变 ...

在前面排查问题时,我们进入容器修改了zz-docker.conf配置文件中的端口方才解决,原因:

官方 PHP-FPM 镜像的 zz-docker.conf 是 Docker 环境专用配置,核心内容是:

(不同镜像版本会略有不同)

[global]
daemonize = no 

[www]
listen = 9000
  • 它的优先级高于默认 www.confzz-docker.conf 加载顺序在最后,会覆盖我们自定义 www.conf 中的冲突配置,确保监听地址统一
  • 若删除该文件,PHP-FPM 会完全依赖你自定义的 www.conf,若你的 www.conf 中缺少 listen 相关配置(或格式错误),PHP-FPM 会启动失败或监听地址无效,导致 Nginx 502。我删除了,导致容器无法启动,容器状态如下:

正确的状态:

所以不建议删除。

二、404 错误

1、排查流程

第 1 步:查看日志
docker logs tp6-tp6-php-fpm-1

错误信息 Operation not permitted 表明是文件权限问题,PHP-FPM 进程没有权限读取 /var/www/html/public/index.php 文件

第2步:检查文件权限

index.php是TP的入口文件,如果没有权限肯定是访问不了网页的。下面来检查一下容器内站点文件的权限,代码如下:

docker exec -it tp6-tp6-php-fpm-1 bash

# 检查文件权限和所有者
ls -la /var/www/html/
ls -la /var/www/html/public/index.php

运行结果如图:

从上面的结果来看,index.php文件权限是 755 (-rwxr-xr-x),但文件所有者是 UID 1000(宿主机www用户),而 PHP-FPM 默认以 www-data 用户运行,导致权限不足。

🔍 问题分析

  • 当前权限-rwxr-xr-x (755) - 权限是足够的

  • 文件所有者: UID 1000 (宿主机用户),可以在如主机执行代码

    #查询宿主机UID 1000的用户
    grep -w "1000" /etc/passwd

    结果:

  • PHP-FPM 用户: 通常是 www-data (UID 33) 或 nobody

  • 问题: UID 1000 ≠ PHP-FPM 用户,导致 Operation not permitt

第3步:检查容器内当前用户
#进入容器
docker exec -it tp6-tp6-php-fpm-1 bash

#检查容器内当前用户
ps aux | grep php-fpm

运行结果:

🔍 问题分析

  • PHP-FPM Master: 以 root 用户运行

  • PHP-FPM Worker: 以 www-data 用户运行(UID 33)

  • 文件所有者: UID 1000(宿主机用户)

  • 问题www-data 用户(UID 33)无法访问 UID 1000 的文件

第4步:修改文件所有者

问题是 www-data 用户(UID 33)无法访问 UID 1000 的文件,那我们将文件所有者改为 www-data。

#进入容器
docker exec -it tp6-tp6-php-fpm-1 bash
#修改容器内文件所有者为www-data
chown -R www-data:www-data /var/www/html/

# 验证修改
ls -la /var/www/html/public/index.php

结果:

可以打开网址看看是否能正常访问。如果不能继续下一步

第5步:宝塔跨域防护open_basedir 限制

查看容器内文件权限

docker exec -it tp6-tp6-php-fpm-1 ls -la /var/www/html/public/

运行结果:

根据上图,只有.user.ini的权限所有者是root用户,其实没有关系,这里不影响,要是尝试修改也比较麻烦,这个文件是一个特殊文件,所以我们不在修改权限,只修改一下内容。改内容之前,先来解读一下这个文件:

.user.ini 是宝塔面板用于每个站点独立 PHP 配置的文件,类似于 php.ini 的站点级配置。

; 防跨站攻击(open_basedir)
open_basedir = /www/wwwroot/站点目录/:/tmp/:/proc/

; 防跨域访问
; 宝塔会自动添加跨域防护规则

关键点:宝塔防跨站攻击里的默认配置使用的宿主机路径,而容器内需要使用容器路径

这里我在这宿主机路径的基础之上增加了容器路径

open_basedir=/www/wwwroot/tp6/public/:/var/www/html:/tmp/:/proc/

尝试重启容器,之后再访问网站:

#重启容器
docker-compose restart

结果:

2、解决方案

修改 Dockerfile增加文件所有者:

# 基础镜像:PHP 8.1-FPM(与宿主机宝塔 PHP 版本一致,避免语法兼容问题)
FROM php:8.1-fpm

# 使用阿里云镜像源加速
RUN sed -i 's/deb.debian.org/mirrors.aliyun.com/g' /etc/apt/sources.list && \
    sed -i 's/security.debian.org/mirrors.aliyun.com/g' /etc/apt/sources.list

# 安装 ThinkPHP6 必需扩展(gd、pdo_mysql 等)
RUN apt-get update && apt-get install -y \
    net-tools \
    libfreetype6-dev \
    libjpeg62-turbo-dev \
    libpng-dev \
    libzip-dev \
    && rm -rf /var/lib/apt/lists/* \
    && docker-php-ext-configure gd --with-freetype --with-jpeg \
    && docker-php-ext-install -j$(nproc) gd pdo_mysql mysqli zip opcache


# 修改 zz-docker.conf
RUN sed -i 's/listen = 9000/listen = 9003/' /usr/local/etc/php-fpm.d/zz-docker.conf

# 确保 www.conf 不会干扰
RUN sed -i 's/^listen = /;listen = /' /usr/local/etc/php-fpm.d/www.conf


# 配置 PHP 时区(与宿主机一致,避免时间戳问题)
RUN echo "date.timezone = Asia/Shanghai" >> /usr/local/etc/php/conf.d/docker-php-ext-timezone.ini

# 设置工作目录(与宿主机项目目录对应,后续通过挂载同步代码)
WORKDIR /var/www/html

#关键修正: 递归修改所有者
RUN chown -R www-data:www-data /var/www/html/


# 暴露自定义 PHP-FPM 端口(9003)
EXPOSE 9003

修改部分:


#关键修正: 递归修改所有者
RUN chown -R www-data:www-data /var/www/html/

然后删除并重新创建容器

#删除容器
docker-compose down

#清理网络
docker network prune -f

#清理构建缓存
docker system prune -f

#创建容器
docker-compose build --no-cache

#启动容器
docker-compose up -d

#查看容器
 docker-compose ps

宝塔跨域防护open_basedir 限制因为这个导致的错误部分,前边我们修改了宿主机文件,这里重新创建容器也是不会来改变的。

三、补充

1、网站目录设置:一定要设置到public目录下。

2、PHP版本选择“纯静态”

因为我这里依赖于PHP容器,选择纯静态,意思是宿主机不再处理PHP 请求。

暂时补充到这里,如有其他问题,欢迎留言

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值