如何让 PHP-FPM 与带有 FastCGI 的 nginx-proxy 一起工作?
How do I get PHP-FPM to work with nginx-proxy with FastCGI?
我正在尝试通过 fastcgi
获取 nginx-proxy to work with the php-fpm
variant of the official php image。不幸的是,我似乎无法这样做。我确定问题只是一些我不知道的简单问题。
我已尽我所能关注 the instructions 的 nginx-proxy,并将其归结为一种非常简单的方法来重现问题。这是我的 docker-compose.yml
文件:
version: "3"
services:
proxy:
image: jwilder/nginx-proxy
ports:
- "80:80"
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
environment:
- DEFAULT_HOST=test.local
fpm:
image: php:fpm
environment:
- VIRTUAL_HOST=test.local
- VIRTUAL_PROTO=fastcgi
然后我通过 运行:
放入一个简单的 index.php
文件
docker container exec -it web_fpm_1 /bin/bash -c 'echo "<?php phpinfo(); ?>" > /var/www/html/index.php'
(它把 web_
放在前面,因为这个项目在一个名为 web/
的目录中。)
我也修改了我的hosts
文件,将test.local
指向127.0.0.1
,这样我就可以测试了。
但是,每次尝试浏览 test.local
都会导致空白页面。
web_proxy_1
容器的日志没有显示任何异常,据我所知:
❯ docker container logs web_proxy_1
WARNING: /etc/nginx/dhparam/dhparam.pem was not found. A pre-generated dhparam.pem will be used for now while a new one
is being generated in the background. Once the new dhparam.pem is in place, nginx will be reloaded.
forego | starting dockergen.1 on port 5000
forego | starting nginx.1 on port 5100
dockergen.1 | 2020/07/20 19:24:54 Generated '/etc/nginx/conf.d/default.conf' from 2 containers
dockergen.1 | 2020/07/20 19:24:54 Watching docker events
dockergen.1 | 2020/07/20 19:24:54 Contents of /etc/nginx/conf.d/default.conf did not change. Skipping notification 'nginx -s reload'
nginx.1 | test.local 172.18.0.1 - - [20/Jul/2020:19:25:12 +0000] "GET / HTTP/1.1" 200 5 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36"
nginx.1 | test.local 172.18.0.1 - - [20/Jul/2020:19:25:13 +0000] "GET /favicon.ico HTTP/1.1" 200 5 "http://test.local/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36"
web_fpm_1
容器的日志显示除了 200 响应外没有发送任何内容:
❯ docker container logs web_fpm_1
[20-Jul-2020 19:24:54] NOTICE: fpm is running, pid 1
[20-Jul-2020 19:24:54] NOTICE: ready to handle connections
172.18.0.3 - 20/Jul/2020:19:25:12 +0000 "- " 200
172.18.0.3 - 20/Jul/2020:19:25:13 +0000 "- " 200
我做错了什么?
顺便提一下,我在 nginx-proxy repo, the nginx-proxy Google Group, and the php repo 上问过这个问题。我要么没有得到回应,要么他们推卸责任。
nginx-proxy
的默认生成配置未完全正常工作。
我认为 VIRTUAL_ROOT
environment variable 出了问题,因为问题的根源是 PHP 通过 SCRIPT_FILENAME
得到了错误的路径(这就是为什么你看不到 PHP 输出)并且没有 try_files
和 =404
符号(这就是为什么你得到 200 的所有东西)。
我准备了一个使用 GitHub 中的 docker-compose
的工作设置,以证明它可以与 nginx 配置中现有的 SCRIPT_FILENAME
一起使用。
我已将 test.local
更改为 test.localhost
。
我认为要使其正常工作,您必须为 nginx-proxy
使用 nginx 模板,因此生成的 default.conf
确实可以与 php fpm 一起使用并且具有缺少包含的 fastcgi 参数。
另一种不同的方法是在项目中打包 PHP 和手动配置的网络服务器 (nginx),并在独立项目中使用自动反向 nginx 代理。
这会花费您一个额外的过程 运行,但会为您提供更多控制和更轻松的部署。
或者,您可能想查看 traefik
,它与 nginx-proxy
.
的作用基本相同
Daniel 的回答绝对是正确的。我使用 php-fpm 图像和 nginx 作为 php 站点的主要堆栈。话虽如此,我不使用 nginx-proxy docker 图像。相反,我在主机上使用纯 nginx,并将端口配置为指向后端 php-fpm docker images.
我也没有使用 docker-compose。因为它只是 docker 容器 运行ning 单个站点,所以我不需要它。这是一个示例 docker 运行 命令:
docker rm -f www.example.com || true
docker run -itd -p 9001:9000 -P \
--name www.example.com \
--volume /var/www/html/www.example.com:/var/www/html/www.example.com \
--link mariadb:database.example.com \
--restart="always" \
--hostname="example.com" \
--log-opt max-size=2m \
--log-opt max-file=5 \
mck7/php-fpm:7.4.x-wordpress
这里是一个 nginx 配置示例:
server {
server_name example.com www.example.com;
location ~ /.well-known {
allow all;
}
location ~ /\.ht {
deny all;
}
root /var/www/html/www.example.com/src;
index index.php;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ [^/]\.php(/|$) {
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
if (!-f $document_root$fastcgi_script_name) {
return 404;
}
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
fastcgi_pass 127.0.0.1:9001;
fastcgi_index index.php;
}
}
关于此设置的一些事情很关键。 docker 容器的端口重新映射。在此示例中,我将端口 9001 映射到 9000。另一个“陷阱”是容器的根目录必须是主机上的实际位置。我不知道为什么会这样,但无论出于何种原因,docker 认为它正在使用的路径实际上也必须是主机上的路径。
我正在尝试通过 fastcgi
获取 nginx-proxy to work with the php-fpm
variant of the official php image。不幸的是,我似乎无法这样做。我确定问题只是一些我不知道的简单问题。
我已尽我所能关注 the instructions 的 nginx-proxy,并将其归结为一种非常简单的方法来重现问题。这是我的 docker-compose.yml
文件:
version: "3"
services:
proxy:
image: jwilder/nginx-proxy
ports:
- "80:80"
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
environment:
- DEFAULT_HOST=test.local
fpm:
image: php:fpm
environment:
- VIRTUAL_HOST=test.local
- VIRTUAL_PROTO=fastcgi
然后我通过 运行:
放入一个简单的index.php
文件
docker container exec -it web_fpm_1 /bin/bash -c 'echo "<?php phpinfo(); ?>" > /var/www/html/index.php'
(它把 web_
放在前面,因为这个项目在一个名为 web/
的目录中。)
我也修改了我的hosts
文件,将test.local
指向127.0.0.1
,这样我就可以测试了。
但是,每次尝试浏览 test.local
都会导致空白页面。
web_proxy_1
容器的日志没有显示任何异常,据我所知:
❯ docker container logs web_proxy_1
WARNING: /etc/nginx/dhparam/dhparam.pem was not found. A pre-generated dhparam.pem will be used for now while a new one
is being generated in the background. Once the new dhparam.pem is in place, nginx will be reloaded.
forego | starting dockergen.1 on port 5000
forego | starting nginx.1 on port 5100
dockergen.1 | 2020/07/20 19:24:54 Generated '/etc/nginx/conf.d/default.conf' from 2 containers
dockergen.1 | 2020/07/20 19:24:54 Watching docker events
dockergen.1 | 2020/07/20 19:24:54 Contents of /etc/nginx/conf.d/default.conf did not change. Skipping notification 'nginx -s reload'
nginx.1 | test.local 172.18.0.1 - - [20/Jul/2020:19:25:12 +0000] "GET / HTTP/1.1" 200 5 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36"
nginx.1 | test.local 172.18.0.1 - - [20/Jul/2020:19:25:13 +0000] "GET /favicon.ico HTTP/1.1" 200 5 "http://test.local/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36"
web_fpm_1
容器的日志显示除了 200 响应外没有发送任何内容:
❯ docker container logs web_fpm_1
[20-Jul-2020 19:24:54] NOTICE: fpm is running, pid 1
[20-Jul-2020 19:24:54] NOTICE: ready to handle connections
172.18.0.3 - 20/Jul/2020:19:25:12 +0000 "- " 200
172.18.0.3 - 20/Jul/2020:19:25:13 +0000 "- " 200
我做错了什么?
顺便提一下,我在 nginx-proxy repo, the nginx-proxy Google Group, and the php repo 上问过这个问题。我要么没有得到回应,要么他们推卸责任。
nginx-proxy
的默认生成配置未完全正常工作。
我认为 VIRTUAL_ROOT
environment variable 出了问题,因为问题的根源是 PHP 通过 SCRIPT_FILENAME
得到了错误的路径(这就是为什么你看不到 PHP 输出)并且没有 try_files
和 =404
符号(这就是为什么你得到 200 的所有东西)。
我准备了一个使用 GitHub 中的 docker-compose
的工作设置,以证明它可以与 nginx 配置中现有的 SCRIPT_FILENAME
一起使用。
我已将 test.local
更改为 test.localhost
。
我认为要使其正常工作,您必须为 nginx-proxy
使用 nginx 模板,因此生成的 default.conf
确实可以与 php fpm 一起使用并且具有缺少包含的 fastcgi 参数。
另一种不同的方法是在项目中打包 PHP 和手动配置的网络服务器 (nginx),并在独立项目中使用自动反向 nginx 代理。 这会花费您一个额外的过程 运行,但会为您提供更多控制和更轻松的部署。
或者,您可能想查看 traefik
,它与 nginx-proxy
.
Daniel 的回答绝对是正确的。我使用 php-fpm 图像和 nginx 作为 php 站点的主要堆栈。话虽如此,我不使用 nginx-proxy docker 图像。相反,我在主机上使用纯 nginx,并将端口配置为指向后端 php-fpm docker images.
我也没有使用 docker-compose。因为它只是 docker 容器 运行ning 单个站点,所以我不需要它。这是一个示例 docker 运行 命令:
docker rm -f www.example.com || true
docker run -itd -p 9001:9000 -P \
--name www.example.com \
--volume /var/www/html/www.example.com:/var/www/html/www.example.com \
--link mariadb:database.example.com \
--restart="always" \
--hostname="example.com" \
--log-opt max-size=2m \
--log-opt max-file=5 \
mck7/php-fpm:7.4.x-wordpress
这里是一个 nginx 配置示例:
server {
server_name example.com www.example.com;
location ~ /.well-known {
allow all;
}
location ~ /\.ht {
deny all;
}
root /var/www/html/www.example.com/src;
index index.php;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ [^/]\.php(/|$) {
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
if (!-f $document_root$fastcgi_script_name) {
return 404;
}
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
fastcgi_pass 127.0.0.1:9001;
fastcgi_index index.php;
}
}
关于此设置的一些事情很关键。 docker 容器的端口重新映射。在此示例中,我将端口 9001 映射到 9000。另一个“陷阱”是容器的根目录必须是主机上的实际位置。我不知道为什么会这样,但无论出于何种原因,docker 认为它正在使用的路径实际上也必须是主机上的路径。