ThinkPHP伪静态在Docker中必须由Nginx(非PHP-FPM容器)正确配置location规则:root指向public目录,location /用try_files $uri $uri/ /index.php?$query_string,location ~ \.php$中fastcgi_param SCRIPT_FILENAME需设为$document_root$fastcgi_script_name,且fastcgi_pass必须用服务名如php:9000。

ThinkPHP 伪静态在 Docker 中不是“配一下就能用”,而是必须由 Nginx(或 Apache)在容器内正确转发请求到 index.php,且 PHP 容器本身不处理 URL 重写。直接改 ThinkPHP 的 url_rewrite 配置或 .htaccess 在纯 FPM 容器里完全无效。
Nginx 容器里 location / 的 rewrite 规则怎么写
这是最常出问题的地方:很多用户复制了 Apache 的 .htaccess 规则,或者照搬旧版 ThinkPHP 的 Nginx 配置,结果 404 或路由全进首页。
- ThinkPHP 6/8 默认使用
pathinfo模式,入口是public/index.php,所以root必须指向/var/www/html/public,不能是项目根目录 -
location /块里不能只写try_files $uri $uri/ =404—— 这会跳过所有伪静态路由 - 正确写法是:
try_files $uri $uri/ /index.php?$query_string;$query_string保证 GET 参数透传,否则?s=api/user会丢失 - 如果用了 ThinkPHP 的
rewrite模式(即去掉index.php),必须配合location ~ \.php$块里的fastcgi_param SCRIPT_FILENAME指向$document_root$fastcgi_script_name,否则$_SERVER['SCRIPT_NAME']错乱导致路由解析失败
示例片段(nginx.conf):
server {
listen 80;
root /var/www/html/public;
index index.php;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass php:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
php-fpm 容器里为什么不能用 .htaccess
因为 .htaccess 是 Apache 特有的运行时配置机制,php-fpm 本身只是 FastCGI 进程管理器,不解析任何 Web 服务器规则。你在 PHP 容器里放一个 .htaccess 文件,它永远也不会被读取。
MiniMax 图片理解 + 网络搜索 MCP 工具。适配 Docker 环境(极空间等),支持图片 OCR 识别、图像内容理解、网络搜索。API Key 安全存储在本地 credentials 文件,不暴露在代码中。
立即学习“PHP免费学习笔记(深入)”;
- 常见错误:把 Apache 版 ThinkPHP 的
.htaccess直接 COPY 进 php-fpm 镜像,以为能生效 - 真正起作用的是 Nginx(或 Apache)容器的配置,PHP 容器只负责执行
index.php并返回结果 - 如果你非要用 Apache,得换基础镜像为
php:8.1-apache,并启用a2enmod rewrite,但这样会增加镜像体积和攻击面,不推荐 - 多语言场景下(如中英文切换),URL 路由依赖 ThinkPHP 的
lang参数或子域名,这些都靠 Nginx 转发后的$_GET或$_SERVER变量传递,跟 PHP 容器无关
Docker Compose 中 fastcgi_pass 怎么写才不连错
fastcgi_pass 的值不是 IP 地址,也不是宿主机端口,而是 Docker 内网中 PHP 容器的服务名 + 端口,且必须与 docker-compose.yml 中定义的 service 名称严格一致。
- 如果
php服务在docker-compose.yml里定义为service: php,那 Nginx 配置里必须写fastcgi_pass php:9000,不能写127.0.0.1:9000或localhost:9000(容器内没有 localhost 到 PHP 的映射) - PHP 容器默认监听
0.0.0.0:9000,但暴露端口(ports)不是必须的——Nginx 和 PHP 在同一个 Docker 网络里通信,走内部 DNS,不需要映射到宿主机 - 容易踩坑:PHP 容器加了
ports: ["9000:9000"],同时又在 Nginx 配置里写fastcgi_pass host.docker.internal:9000,这在 Linux 上根本不可靠,macOS/Windows 才有该 DNS 名 - 验证是否连通:进入 Nginx 容器执行
ping php或telnet php 9000,通了才算网络就绪
多语言路径(如 /zh-CN/xxx)伪静态失效怎么办
ThinkPHP 多语言通常靠 URL path segment(如 /zh-CN/index/index)或域名(zh.example.com)识别,伪静态失效往往是因为 Nginx 没把完整路径交给 index.php,导致 $_SERVER['REQUEST_URI'] 被截断。
- 确保 Nginx 的
fastcgi_param REQUEST_URI $request_uri没被覆盖(默认fastcgi_params里已有,但有些自定义配置会删掉) - 不要在
location块里用rewrite去“标准化”多语言前缀,ThinkPHP 自己会 parseREQUEST_URI - 检查 PHP 容器里
public/index.php是否被意外修改——标准 ThinkPHP 入口文件会自动设置$_SERVER['PATH_INFO'],改错了会导致语言检测失败 - 调试技巧:在
index.php开头临时加file_put_contents('/tmp/request.log', print_r($_SERVER, true), FILE_APPEND),然后docker exec -it nginx cat /tmp/request.log查看原始请求头
最易被忽略的一点:ThinkPHP 的多语言路由依赖 config/app.php 中的 'default_lang' => 'zh-cn' 和 'allow_cross_domain' => true(跨域调试时),但这些配置和 Docker 无关,一旦容器启动后改了配置文件,必须重启 PHP 容器才能生效——挂载卷方式更新配置不会触发 FPM reload。


















