nginx try_files、proxy_pass 和上游
Posted
技术标签:
【中文标题】nginx try_files、proxy_pass 和上游【英文标题】:nginx try_files, proxy_pass and upstream 【发布时间】:2016-07-30 08:41:15 【问题描述】:我正在为 php 应用程序构建一个 dockerised 测试“平台”——特别是(目前)为 WordPress。我正在使用 PHPFarm 在不同的端口上提供不同版本的 PHP。在前面使用 nginx,我已经完成了很多工作。 (https://github.com/richardtape/testit 是主要仓库)
我现在面临的大问题是让 WordPress 的“漂亮的永久链接”发挥作用。在标准的 nginx 设置中,这只是类似
的情况location /
index index.php index.html index.htm;
try_files $uri $uri/ /index.php?$args;
但是为了能够从主机获得漂亮的 url,并且为了拥有一个代码库,我使用了以下几行:
server
listen 80;
index index.php index.html index.htm;
server_name 52.spaces.dev;
location /
proxy_pass http://phpfarm_52;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
root /var/www;
upstream phpfarm_52
server phpfarm:8052;
就目前而言,这很有效。 (对于 PHP 5.3、5.4、5.5、5.6 和 7,还有 5 个类似的规则)主页从主机加载到每个不同的 server_names 上(如果您在每个上输出 PHP 版本,您可以看到你得到一个不同的 PHP 版本)。
但是,当我切换到“内部”网址(或任何非 root,即 http://52.spaces.dev/about/)时,我得到了 404。我尝试过类似于
location /
try_files $uri $uri/ /index.php?$args
location ~ \.php$
proxy_pass http://phpfarm_52;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
我得到了一个重定向循环,这取决于我尝试过的几种不同方式,它要么只是一系列 301 重定向并且页面永远不会加载,要么是诸如
之类的错误nginx_1 | 2016/04/08 20:31:29 [error] 5#5: *4 rewrite or internal redirection cycle while processing "/index.php", client: 192.168.99.1, server: 52.spaces.dev, request: "GET /favicon.ico HTTP/1.1", host: "52.spaces.dev", referrer: "http://52.spaces.dev/"
我被困住了。我对 nginx 配置也很陌生(这可能很明显),所以我很可能会做一些完全错误和/或愚蠢的事情。有什么建议吗?
【问题讨论】:
从实例内部 curl phpfarm:8052/about 会发生什么? (基本上,这就是您最初的 proxy_pass 所做的)。如果您也收到 404,您希望对上游进行什么调用? 它本身应该是 404,但据我了解,try_files $uri $uri/ /index.php?$args
意味着它最终应该回退到 index.php(带有适当的 args),而不是 404 (如主页工作的事实所示)。如果我禁用“漂亮”永久链接(即所有内容都通过 index.php 运行),那么它会按预期工作。
【参考方案1】:
您在问题中遇到的重定向循环问题是,基本上每个请求,即使是静态文件,都会尝试通过您的 index.php?$args 块进行路由。
我在这里看到了 2 种可能的解决方案。首先,如果您愿意使用单个 nginx 实例来实现 nginx 设置,请查看此线程:NGINX try_files with multiple named locations 和此博客文章 http://linuxplayer.org/2013/06/nginx-try-files-on-multiple-named-location-or-server
需要发生的事情是,您需要首先测试资源是否按原样存在于上游(即不返回 404)。如果是这样,那么您按原样提供。如果没有,那么您将调用重写块,该块试图将其作为参数放入 index.php。所以你最终会得到这样的东西(对不起,我真的没有机会测试这个,但希望它能给你一个想法):
location /
try_files $uri $uri/ @phpproxy;
location @phpproxy
proxy_pass http://phpfarm_52;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_intercept_errors on;
recursive_error_pages on;
error_page 404 = @rewrite_proxy;
location @rewrite_proxy
rewrite ^/(.*)$ /index.php?$1 break;
proxy_pass http://phpfarm_52;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
第二种解决方案(我个人更喜欢)是在每个上游都使用自己的 nginx。然后,前面所有其他 nginx 的顶部将具有更简洁的结构,其中包含简单的 proxy_pass(+ 可能是一些静态内容),仅此而已。它还将减少请求往返,因为您不需要解析来自上游的 404。
【讨论】:
首先,Pavel,非常感谢您抽出宝贵时间。其次,我其实明白你在说什么(这改变了哈哈)。我尝试了上面的内容(第 2 行缺少;
),但现在提供的任何页面(包括主页)都会下载 index.php 文件而不是执行它。我怀疑我们快到了。
修复了分号 ;) 如果它下载文件,则意味着内容类型未正确传递,或者我在重写行中搞砸了一些东西(我不确定它应该如何这些天用于wordpress),或两者兼而有之。但是和那些一起玩应该可以解决它。希望对您有所帮助。
再次感谢您迄今为止的帮助。我尝试将default_type
(和proxy_set_header content-type
)添加为application/octet-stream,但没有骰子。我认为这可能是因为安装了 nginx 的容器,PHP 没有,所以根位置块的 try_files
行正在查看 index.php 文件并只是下载它。那会有什么不同吗?我尝试添加一个 .php 位置块,但不断收到重定向循环。 conf文件的当前状态为:gist.github.com/richardtape/9a84e5de6f09d14a1ff8b92449ba96b0
所以上面的代码是正确的(可能需要对重写处理等进行一些调整),但问题在于 PHPFarm/Apache 的末尾和处理重写
嗨,理查德,再看看你的配置,显然你的 phpfarm 节点前面有 Apache。您是否尝试使用 Apache 解决永久链接,这相当于我的第二个解决方案,其中 nginx 将成为一个干净的反向代理? codex.wordpress.org/Using_Permalinks以上是关于nginx try_files、proxy_pass 和上游的主要内容,如果未能解决你的问题,请参考以下文章