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

Posted

技术标签:

【中文标题】如何使用 NGINX 直接提供所有现有的静态文件,但将其余的代理到后端服务器。【英文标题】:How to serve all existing static files directly with NGINX, but proxy the rest to a backend server. 【发布时间】:2010-10-26 12:31:53 【问题描述】:
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;
        
    

Above 将直接使用 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解析。 【参考方案1】:

使用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 服务的所有文件类型列入白名单。

【讨论】:

我正在使用wordpress,所以我需要将上传文件夹放在nginx服务器上吗? 我对此解决方案的问题:nginx 不使用其他位置(代理)并尝试显示目录​​列表。因此它会抛出 403,因为目录列表未激活。 编辑:好的,如果你删除 $uri/ 那么它就可以了。 这会将 /example 代理到 apache,但允许下载 /example.php。 @TerenceJohnson 将 php 文件放在静态文件夹下是不安全的。请注意,我设置了root /path/to/root/of/*static*/files;。 php 文件应放在不同的文件夹中,不能直接从 Internet 访问。 我知道事情应该是这样的,但是如果有人将 Nginx 放在许多常见的现成 PHP 应用程序的前面,这些应用程序的所有内容都在 Web 根目录下并依赖 .htaccess文件,他们不应该复制和粘贴您的配置。【参考方案2】:

如果您使用 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;

我在以下位置找到了这个 sn-p 的第一部分:http://code.google.com/p/scalr/wiki/NginxStatic

【讨论】:

这很好用,虽然我仍然收到缩小文件的错误(例如 site.min.css 和 main.min.js 等)。我将如何在位置正则表达式中捕获那些? @lo_fye【参考方案3】:

试试这个:

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。休息将作为静态文件处理。实际的定位算法是here。

【讨论】:

以上是关于如何使用 NGINX 直接提供所有现有的静态文件,但将其余的代理到后端服务器。的主要内容,如果未能解决你的问题,请参考以下文章

如何使用现有的静态库构建可可触控框架

如何将 CORS(跨域策略)添加到 NGINX 中的所有域?

我们如何使用 Kong 替换现有的 Nginx?

Elastic Beanstalk Nginx 提供静态文件

如何在NGINX中路由静态文件和不同的应用程序?

更好的方法是啥:使用 Express 或 nginx 提供静态文件?