Traefik 不能直接代理 PHP 是因为其仅支持 HTTP/HTTPS 等七层协议,而 PHP-FPM 使用不兼容的 FastCGI 协议;必须通过 Nginx(或类似服务器)作为中间层解析 HTTP 并转发 FastCGI 请求。

traefik 本身不直接运行 PHP,它只是反向代理;PHP 和 Nginx 需各自独立运行(比如用 php-fpm),再由 Nginx 处理 .php 请求,最后让 traefik 把流量转发给 Nginx。硬凑“trae配置php”会踩进进程模型混淆的坑。
为什么不能让 traefik 直连 php-fpm?
traefik 是 HTTP/HTTPS 反向代理,只理解七层协议(HTTP、gRPC、TLS SNI 等)。php-fpm 使用的是 FastCGI 协议(二进制+私有帧格式),和 HTTP 完全不兼容。你没法在 traefik 的 services 中直接指向 php-fpm:9000 —— 它根本解析不了 FastCGI 包。
必须保留 Nginx(或 Apache、Caddy)作为 FastCGI 终端:接收 HTTP 请求 → 解析 URI → 转发 .php 文件给 php-fpm → 拿回响应 → 返回给客户端。
典型三容器结构怎么编排?
推荐用 Docker Compose 实现隔离与复用。关键点不是“配置”,而是网络打通和路径对齐:
立即学习“PHP免费学习笔记(深入)”;
- Nginx 容器暴露端口(如
80),不映射到宿主机;只和 traefik 同一个自定义网络(如traefik-public) - PHP-FPM 容器不暴露端口,只和 Nginx 在同一网络(可共用
internal网络),Nginx 通过服务名(如php:9000)访问它 - traefik 容器启用
dockerprovider,监听容器 label,并把请求路由到nginx服务(不是 php) - 所有容器共享代码卷(如
./src:/var/www/html),确保 Nginx 能读文件、php-fpm 能执行文件
示例片段(docker-compose.yml 片段):
services:
nginx:
image: nginx:alpine
volumes:
- ./src:/var/www/html
- ./nginx.conf:/etc/nginx/nginx.conf
labels:
- "traefik.enable=true"
- "traefik.http.routers.myapp.rule=Host(`app.test`)"
- "traefik.http.routers.myapp.entrypoints=web"
networks:
- traefik-public
php:
image: php:8.2-fpm-alpine
volumes:
- ./src:/var/www/html networks:
- internal
traefik:
... 其他配置
networks: - traefik-public - internal
nginx.conf 里 fastcgi_pass 怎么写才不报 502?
错误常见于网络不通或 php-fpm 没监听对地址。在容器内,fastcgi_pass 必须指向 php 服务名 + 端口(默认 9000),不能写 127.0.0.1:9000 或 localhost:9000 —— 那是 Nginx 自己的 loopback,不是 php 容器。
正确写法(在 nginx.conf 的 location ~ /.php$ 块中):
fastcgi_pass php:9000; fastcgi_param SCRIPT_FILENAME /var/www/html$fastcgi_script_name; include fastcgi_params;
同时确认 php 容器里 php-fpm.conf 或 www.conf 没改过监听地址(保持默认 0.0.0.0:9000 或 php:9000);若用了 socket(/var/run/php/php8.2-fpm.sock),则需挂载相同路径并改用 fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;。
traefik 路由规则漏掉静态资源怎么办?
traefik 默认把所有匹配 Host 的请求都转给 Nginx,但如果你在 Nginx 里没配好 root 或 try_files,容易出现 CSS/JS 404,或 PHP 脚本被当静态文件下载。核心是:Nginx 必须自己决定哪些走 PHP,哪些直出。
最小可用 server 块应包含:
server {
listen 80;
root /var/www/html;
index index.php;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ /.php$ {
fastcgi_pass php:9000;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
}
}
注意:$realpath_root 比 $document_root 更可靠,能处理符号链接;try_files 保证前端路由(如 Vue Router history 模式)也能 fallback 到 index.php。
最常被忽略的是 volume 挂载路径一致性 —— Nginx 和 php 容器看到的 /var/www/html 必须是同一份文件,否则修改 PHP 代码后刷新页面还是旧的,或者提示 “No input file specified”。
