php nginx try_files、proxy_pass 和上游
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/36510523/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
nginx try_files, proxy_pass and upstream
提问by RichardTape
I'm building a dockerised testing 'platform' for PHP apps - specifically (for the moment) for WordPress. I'm using PHPFarm to serve different versions of PHP on different ports. Using nginx in front, I've got much of it working. ( https://github.com/richardtape/testitis the main repo )
我正在为 PHP 应用程序构建一个 dockerised 测试“平台” - 特别是(目前)为 WordPress。我正在使用 PHPFarm 在不同端口上提供不同版本的 PHP。在前面使用 nginx,我已经完成了大部分工作。(https://github.com/richardtape/testit是主要的 repo )
The big issue I'm facing now is getting WordPress's "pretty permalinks" to work. In a standard nginx setup, it's just a case of something like
我现在面临的一个大问题是让 WordPress 的“漂亮的永久链接”发挥作用。在标准的 nginx 设置中,这只是类似的情况
location / {
index index.php index.html index.htm;
try_files $uri $uri/ /index.php?$args;
}
But in order to be able to have nice urls from the host machine, and in order to have one code base, I'm using something along the following lines:
但是为了能够从主机获得漂亮的 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;
}
This, as it stands, works. (There are 5 more rules similar for this for PHP 5.3, 5.4, 5.5, 5.6 and 7) The home page loads on each of the different server_names from the host machine (and if you output the PHP version on each of them, you can see that you're getting a different PHP version).
就目前而言,这是有效的。(对于 PHP 5.3、5.4、5.5、5.6 和 7,还有 5 条与此类似的规则)主页在主机的每个不同 server_names 上加载(如果您在每个服务器上输出 PHP 版本,您可以看到您获得了不同的 PHP 版本)。
However, the second I switch to an 'internal' url (or any non-root i.e. http://52.spaces.dev/about/), I get a 404. I've tried something similar to
但是,第二次我切换到“内部”网址(或任何非根网址,即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;
}
I get a redirect loop, depending on a few different ways I've tried it's either just been a series of 301 redirects and the page never loads or an error such as
我得到了一个重定向循环,这取决于我尝试过的几种不同方式,它要么只是一系列 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/"
I'm stuck. I'm also pretty new to nginx configuration (which may be obvious) so I might well be doing something completely wrong and/or dumb. Any suggestions?
我被困住了。我对 nginx 配置也很陌生(这可能很明显),所以我很可能在做一些完全错误和/或愚蠢的事情。有什么建议?
回答by taleodor
The issue you're experiencing with the redirect loop in your question is that basically every request, even for static files tries to route via your index.php?$args block.
您在问题中遇到的重定向循环问题是,基本上每个请求,即使是静态文件,都试图通过您的 index.php?$args 块进行路由。
I see 2 possible solutions here. First, if you are willing to implement the nginx setup with a single nginx instance, look at this thread: NGINX try_files with multiple named locationsand this blog post http://linuxplayer.org/2013/06/nginx-try-files-on-multiple-named-location-or-server
我在这里看到 2 种可能的解决方案。首先,如果您愿意使用单个 nginx 实例实现 nginx 设置,请查看此线程:具有多个命名位置的 NGINX try_files和这篇博客文章http://linuxplayer.org/2013/06/nginx-try-files-在多个命名位置或服务器上
What needs to happen, is you need to first test if the resource is present on the upstream as is (i.e., doesn't return 404). If it does, then you serve it as is. If it does not, then you would be calling the rewrite block which tries to put it as a parameter to index.php. So you would end up with something like this (sorry, I don't really have a chance to test this, but hopefully it gives an idea):
需要发生的是,您需要首先测试资源是否按原样存在于上游(即不返回 404)。如果是这样,那么您将按原样提供服务。如果没有,那么您将调用 rewrite 块,该块试图将其作为参数放入 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? break;
proxy_pass http://phpfarm_52;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
}
The second solution (that I would personally prefer) is to front every upstream with its own nginx. Then the top nginx which is fronting all others will have a much cleaner structure with simple proxy_pass's (+ maybe some static content) and that's it. It will also cut down on the request round-trip, since you wouldn't need to resolve 404's coming from the upstreams.
第二个解决方案(我个人更喜欢)是在每个上游都有自己的 nginx。然后,位于所有其他前端的顶级 nginx 将具有更简洁的结构,带有简单的 proxy_pass(+ 可能是一些静态内容),仅此而已。它还将减少请求往返,因为您不需要解决来自上游的 404。