直接使用官方php-fpm镜像(如php:8.2-fpm-alpine)启动即可,无需从scratch自建Dockerfile;它已预装pdo_mysql、opcache等常用扩展,体积小、启动快、更新及时,且避免cli镜像误用于Web服务、网络隔离、挂载路径与配置不一致等常见错误。

直接用官方 php-fpm 镜像启动,别从 scratch 写 Dockerfile
多数本地开发场景下,自己写 Dockerfile 编译 PHP 是过度设计。官方 php:8.2-fpm-alpine 或 php:7.4-fpm 已预装常用扩展(如 pdo_mysql、opcache),体积小、启动快、更新及时。
容易踩的坑:
- 用
php:8.2-cli启动 Web 服务——它没开9000端口,也不运行php-fpm进程,Nginx 会连不上 - 选
php:8.2(无后缀)——这是 CLI 镜像,不是 FPM,和 Web 服务不兼容 - 在 Alpine 镜像里硬装
sqlsrv或oci8——这些扩展官方不支持,编译失败率高,开发阶段建议换 Debian 基础镜像(如php:8.2-fpm)
docker-compose.yml 必须显式声明 network 和 volume 挂载点
只靠 docker run -p 9000:9000 php:8.2-fpm 无法跑通 Web 请求,因为 Nginx 容器和 PHP-FPM 容器默认不在同一网络,DNS 解析失败。
正确做法是用 docker-compose.yml 统一编排,并确保:
立即学习“PHP免费学习笔记(深入)”;
- 所有服务定义在同一
networks下(如app-network),让nginx能通过服务名php访问php-fpm -
php服务的volumes必须挂载代码目录到/var/www/html,且权限匹配(宿主机 UID/GID 与容器内一致,否则opcache写缓存失败) - 不要把
php.ini直接 COPY 进镜像——改配置时得重建镜像;应挂载为./php.ini:/usr/local/etc/php/php.ini:ro
nginx 配置里 fastcgi_pass 必须指向 docker-compose 中的服务名 + 9000 端口
Nginx 容器里不能写 fastcgi_pass 127.0.0.1:9000,因为那是它自己的回环地址,不是 PHP 容器。必须用 Docker 内置 DNS 名称。
示例片段(nginx/default.conf):
location ~ \.php$ {
fastcgi_pass php:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /var/www/html$fastcgi_script_name;
include fastcgi_params;
}
常见错误现象:
-
502 Bad Gateway:fastcgi_pass地址错、PHP 容器没起来、或端口没暴露(php服务缺EXPOSE 9000) -
File not found:Nginx 挂载路径和fastcgi_param SCRIPT_FILENAME不一致,比如代码挂到了/app,但配置里还写/var/www/html - 静态资源 404:Nginx 的
root指向和 volume 挂载路径不对应
多版本 PHP 共存时,端口和域名映射要靠 host 文件 + 浏览器代理,不是靠容器端口
想同时跑 php:7.4-fpm 和 php:8.2-fpm,不能只改 docker-compose.yml 里的 ports(如 9001:9000 和 9002:9000),因为 Nginx 仍需通过服务名通信,端口映射对外无意义。
真正需要的是:
- 两个独立的
docker-compose.yml(分别叫php74和php82),各自定义network和service名 - 在
/etc/hosts加两行:127.0.0.1 php74.test和127.0.0.1 php82.test - 用浏览器插件(如
Simple Proxy)把php74.test→localhost:8081,php82.test→localhost:8082,再配 Nginx 的server_name
这个环节最容易被跳过,结果就是“两个环境都起来了,但浏览器打不开”,其实问题不在 Docker,而在请求根本没走到对应 Nginx 实例。



















