如何使用NGINX直接提供所有现有的静态文件,但将其余内容代理到后端服务器。

96
location / {
    proxy_set_header X-Real-IP  $remote_addr;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    if (-f $request_filename) {
        access_log off;
        expires 30d;
        break;
        }

    if (!-f $request_filename) {
        proxy_pass http://127.0.0.1:8080; # backend server listening
        break;
        }
    }
以上将直接使用Nginx为所有现有文件提供服务(例如,Nginx仅显示PHP源代码),否则将请求转发到Apache。我需要从规则中排除*.php文件,以便对*.php的请求也会传递到Apache并进行处理。
我希望Nginx处理所有静态文件,而Apache处理所有动态内容。
编辑:有一个白名单方法,但它不是非常优雅。看到所有这些扩展名,我不想要这个。
location ~* ^.+.(jpg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|doc|xls|exe|pdf|ppt|txt|tar|mid|midi|wav|bmp|rtf|js)$ {
    access_log off;
    expires 30d;
    }
location / {
    proxy_set_header X-Real-IP  $remote_addr;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass http://127.0.0.1:8080;
    }

编辑2:在更新版本的Nginx中,请使用try_files而不是http://wiki.nginx.org/HttpCoreModule#try_files


只是为了澄清事情:如果磁盘上存在静态文件,则上述代码将提供该文件,如果文件不存在,则请求将传递给Apache。这在大多数情况下都有效,因为我的应用程序中的所有URL都使用mod_rewrite(或路由),并且实际上不存在于磁盘上。只有对*.php文件名的直接访问是例外,并且需要由Apache解析。 - fmalina
3个回答

164

使用try_files和命名位置块('@apachesite')。这将去除不必要的正则表达式匹配和if块。更有效率。

location / {
    root /path/to/root/of/static/files;
    try_files $uri $uri/ @apachesite;

    expires max;
    access_log off;
}

location @apachesite {
    proxy_set_header X-Real-IP  $remote_addr;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass http://127.0.0.1:8080;
}

更新:此配置的假设是在/path/to/root/of/static/files下不存在任何php脚本。这在大多数现代php框架中很常见。如果您的旧版php项目将php脚本和静态文件混合放置在同一个文件夹中,则可能需要将所有要由nginx提供服务的文件类型列入白名单。


7
我对这个解决方案有问题:nginx没有使用其他位置(代理),试图显示目录列表。因此,它会抛出403错误,因为目录列表未激活。编辑: 如果你移除 $uri/ 那么就可以工作了。 - ChristophLSA
1
这将代理/example到apache,但允许下载/example.php。 - Terence Johnson
1
@TerenceJohnson 在静态文件夹下放置您的php文件是不安全的。请注意,我设置了 root /path/to/root/of/*static*/files;。php文件应该放在另一个文件夹中,不能直接从互联网访问。 - Chuan Ma
2
我知道这应该是正确的做法,但如果有人在任何一个常见的现成PHP应用程序前面放置Nginx,并且这些应用程序将所有内容都放在Web根目录下并依赖于.htaccess文件,那么他们不应该复制和粘贴你的配置。 - Terence Johnson
我的答案是针对这个问题的:nginx会自己处理任何文件下载请求,并将其余请求传递给apache。因此,如果有人有一个非常旧的PHP应用程序(其中包含混合静态文件和php文件),他们不应该复制我的配置。相反,他们应该更具体地指定哪些文件可以直接由他们的nginx服务器提供服务。 - Chuan Ma
显示剩余2条评论

18

试试这个:

location / {
    root /path/to/root;
    expires 30d;
    access_log off;
}

location ~* ^.*\.php$ {
    if (!-f $request_filename) {
        return 404;
    }
    proxy_set_header X-Real-IP  $remote_addr;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass http://127.0.0.1:8080;
}

希望它能正常工作。正则表达式的优先级高于普通字符串,因此如果只存在相应的.php文件,则所有以.php结尾的请求都应被转发到Apache。其他请求将被处理为静态文件。评估位置的实际算法在这里


6

如果您使用mod_rewrite来隐藏脚本的扩展名,或者您喜欢以/结尾的美观URL,则可能希望从另一个方向来解决此问题。告诉nginx让任何具有非静态扩展名的内容通过到apache。例如:

location ~* ^.+\.(jpg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|pdf|txt|tar|wav|bmp|rtf|js|flv|swf|html|htm)$
{
    root   /path/to/static-content;
}

location ~* ^!.+\.(jpg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|pdf|txt|tar|wav|bmp|rtf|js|flv|swf|html|htm)$ {
    if (!-f $request_filename) {
        return 404;
    }
    proxy_set_header X-Real-IP  $remote_addr;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass http://127.0.0.1:8080;
}

我在这个代码片段的第一部分中发现了以下内容: http://code.google.com/p/scalr/wiki/NginxStatic

这个方法很好用,但是我仍然会在被缩小过的文件(例如site.min.css和main.min.js)中得到错误。我该如何通过位置正则表达式捕获它们?@lo_fye - Garth

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接