解决Docker中部署PHP-FPM出现"File not found."的问题


场景:在Docker里跑PHP-FPM,把TCP Socket开在localhost:9999上,用本机的Nginx去访问。

问题:访问存在的index.php文件时,显示File not found.

看一下/var/log/nginx/errors.log,发现有这样的错误信息:

FastCGI sent in stderr: "Primary script unknown" while reading response header from upstream

于是确定是通过FastCGI调用PHP-FPM时,传递的文件名有误。这就涉及到PHP的工作原理了:Nginx提供 HTTP服务,对于客户端对PHP文件的请求,Nginx将构造一个对应的CGI调用,通过配置的TCP套接字或者Unix 套接字,将请求发送给PHP。请求中有一个参数SCRIPT_FILENAME标识了客户端请求的脚本文件的本地 路径。由于我将PHP环境放在了Docker内部,PHP通过Docker Volume访问重定向后的本机路径,这个路径 和外部的Nginx看到的路径不一样,从而导致了Nginx能看到这个PHP脚本文件、而PHP不能。

需要修改Nginx站点的配置文件,一般我们都会从网上抄来这么一行配置:

fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

如果Nginx和PHP在一个Docker环境/文件系统环境里,或者Docker内外,你的网页本地路径一样, 那么这样配置就不会出现问题。现在我们只需要手动设置一下Nginx通过CGI传递的文件路径,将这个路径 改为Docker内部重定向后的路径。

我的PHP volume配置:

volumes:
  - /opt/myapp/html:/var/www/html

可见,外部路径是/opt/myapp/html,而Docker内部路径是/var/www/html,所以我们只需要把Nginx 里的那行配置改成:

fastcgi_param SCRIPT_FILENAME /var/www/html$fastcgi_script_name;

就可以了。当你修改了Docker内部容器的布局后,还需要改一下Nginx的这里的配置。