Nginx proxy_pass 只能部分工作
Nginx proxy_pass only works partially
我有以下设置
- 主服务器 - 称之为
https://master.com
- 从属服务器 - 称之为
https://slave.com
两个 运行 Nginx 在 Ubuntu 16.04
在主服务器上,我在 /etc/nginx/sites-available/default
文件中创建了以下配置块
location /test
{
rewrite ^/test(.*) / break;
proxy_pass https://slave.com;
proxy_read_timeout 240;
proxy_redirect off;
proxy_buffering off;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
}
A service nginx reload
稍后 master.com
我可以执行以下操作
- 浏览至
https://master.com/test
并查看 slave.com\index.php
的输出。
- 浏览至
https://master.com/test/test.txt
并查看文件中的文本 slave.com\test.txt
- 浏览至
https://master/com/test/test.jpg
并查看文件 slave.com\test.jpg
中的图像。
但是,我无法执行以下任何操作
- 浏览到
https://master.com/test/test.php
,它没有向我显示 https://slave.com/test.php
的输出,而是向我显示 404 错误消息
- 浏览到
https://master.com/test/adminer/adminer.php
,它没有向我显示从站上 Adminer 实例的登录屏幕,https://slave.com/adminer/adminer.php
向我显示了 master.com
上 Adminer 实例的登录屏幕,即https://master.com/adminer/adminer.php
这显然是因为我在 master.com
上的 Nginx 配置中遗漏了一些东西。但是,我看不出那可能是什么。
为了完整起见,这是我在两台服务器上的配置:
Ubuntu - 16.04.3
Nginx - 1.10.3
PHP - 7.0.22
我应该解释为什么 ^~
是必需的,因为这在我最初的问题中并不清楚。我有另一个块设置来处理 master.com
.
上的 PHP 脚本
location ~ \.php$
{
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
由于 Nginx 处理这些指令的方式,此块在处理 .php
文件时优先,并且 master.com
最终在本地查找 .php
实际上位于 slave.com
。避免这种情况的唯一方法是使用 ^~
你的做法是错误的。在处理 /test
的块内重写它并将其发送出块。 proxy_pass
实际上从未发生过,因为新的 URL 中没有 /test
。解决方法很简单,不要用rewrite
location /test/
{
proxy_pass https://slave.com/;
proxy_read_timeout 240;
proxy_redirect off;
proxy_buffering off;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
}
在位置路径的末尾附加 /
以及 proxy_pass
服务器将确保将 /test/
之后的内容发送到您的 proxy_pass
地址
编辑-1
这是我在发布此答案之前设置的示例测试用例。
events {
worker_connections 1024;
}
http {
server {
listen 80;
location /test1 {
proxy_pass http://127.0.0.1:81;
}
location /test2 {
proxy_pass http://127.0.0.1:81/;
}
location /test3/ {
proxy_pass http://127.0.0.1:81;
}
location /test4/ {
proxy_pass http://127.0.0.1:81/;
}
}
server {
listen 81;
location / {
echo "$request_uri";
}
}
}
现在结果解释了所有 4 个位置块之间的差异
$ curl http://192.168.33.100/test1/abc/test
/test1/abc/test
$ curl http://192.168.33.100/test2/abc/test
//abc/test
$ curl http://192.168.33.100/test3/abc/test
/test3/abc/test
$ curl http://192.168.33.100/test4/abc/test
/abc/test
正如您在 /test4
url 中看到的那样,代理服务器只能看到 /abc/test
我有以下设置
- 主服务器 - 称之为
https://master.com
- 从属服务器 - 称之为
https://slave.com
两个 运行 Nginx 在 Ubuntu 16.04
在主服务器上,我在 /etc/nginx/sites-available/default
文件中创建了以下配置块
location /test
{
rewrite ^/test(.*) / break;
proxy_pass https://slave.com;
proxy_read_timeout 240;
proxy_redirect off;
proxy_buffering off;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
}
A service nginx reload
稍后 master.com
我可以执行以下操作
- 浏览至
https://master.com/test
并查看slave.com\index.php
的输出。 - 浏览至
https://master.com/test/test.txt
并查看文件中的文本slave.com\test.txt
- 浏览至
https://master/com/test/test.jpg
并查看文件slave.com\test.jpg
中的图像。
但是,我无法执行以下任何操作
- 浏览到
https://master.com/test/test.php
,它没有向我显示https://slave.com/test.php
的输出,而是向我显示 404 错误消息 - 浏览到
https://master.com/test/adminer/adminer.php
,它没有向我显示从站上 Adminer 实例的登录屏幕,https://slave.com/adminer/adminer.php
向我显示了master.com
上 Adminer 实例的登录屏幕,即https://master.com/adminer/adminer.php
这显然是因为我在 master.com
上的 Nginx 配置中遗漏了一些东西。但是,我看不出那可能是什么。
为了完整起见,这是我在两台服务器上的配置:
Ubuntu - 16.04.3 Nginx - 1.10.3 PHP - 7.0.22
我应该解释为什么 ^~
是必需的,因为这在我最初的问题中并不清楚。我有另一个块设置来处理 master.com
.
location ~ \.php$
{
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
由于 Nginx 处理这些指令的方式,此块在处理 .php
文件时优先,并且 master.com
最终在本地查找 .php
实际上位于 slave.com
。避免这种情况的唯一方法是使用 ^~
你的做法是错误的。在处理 /test
的块内重写它并将其发送出块。 proxy_pass
实际上从未发生过,因为新的 URL 中没有 /test
。解决方法很简单,不要用rewrite
location /test/
{
proxy_pass https://slave.com/;
proxy_read_timeout 240;
proxy_redirect off;
proxy_buffering off;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
}
在位置路径的末尾附加 /
以及 proxy_pass
服务器将确保将 /test/
之后的内容发送到您的 proxy_pass
地址
编辑-1
这是我在发布此答案之前设置的示例测试用例。
events {
worker_connections 1024;
}
http {
server {
listen 80;
location /test1 {
proxy_pass http://127.0.0.1:81;
}
location /test2 {
proxy_pass http://127.0.0.1:81/;
}
location /test3/ {
proxy_pass http://127.0.0.1:81;
}
location /test4/ {
proxy_pass http://127.0.0.1:81/;
}
}
server {
listen 81;
location / {
echo "$request_uri";
}
}
}
现在结果解释了所有 4 个位置块之间的差异
$ curl http://192.168.33.100/test1/abc/test
/test1/abc/test
$ curl http://192.168.33.100/test2/abc/test
//abc/test
$ curl http://192.168.33.100/test3/abc/test
/test3/abc/test
$ curl http://192.168.33.100/test4/abc/test
/abc/test
正如您在 /test4
url 中看到的那样,代理服务器只能看到 /abc/test