Nginx 多个位置问题

Nginx 多个位置问题

我目前正尝试将一个存储库中的 3 个应用程序拆分成 3 个,但保留 url 结构,因此基本上同一域下的不同位置必须由不同的应用程序提供。

我所苦苦挣扎的是,其中一个应用程序需要作为不存在的 URL 的后备,因此,如果第一个应用程序不匹配,而第二个应用程序不匹配,那么第三个应用程序应该处理该请求

我得到的结构是:

/etc/nginx/sites-enabled/main_site,在这里,除了 server_name 和 logs 之外include /etc/nginx/subsites-enabled/*,我还有 3 个配置文件,每个应用程序一个。

这 3 个配置文件各自包含一个位置块。

我尝试过在正则表达式中进行负向前瞻(基本上是尝试对其他应用程序处理的 URL 进行硬编码)但失败了。

总结一下:

/ 和 /community 应该由 /etc/nginx/subsites-enabled/example.org/home 提供(一些 perl 脚本)

/news 应由 /etc/nginx/subsites-enabled/example.org/news (wordpress) 提供

其余所有内容应通过 /etc/nginx/subsites-enabled/example.org/app (cake 应用程序)提供

perl 位工作正常。我遇到的问题是应用程序正在接管新闻(可能是因为它匹配 .*),我尝试了各种选项(我已经尝试了 2 天),但没有一个能解决所有问题(有时静态资产不起作用,等等)。

我的配置是:

/etc/nginx/sites-enabled/example.org:

server {
    listen   80;
    server_name example.org;
    error_log /var/log/nginx/example.org.log;

    include /etc/nginx/subsites-enabled/example.org/*;
}

/etc/nginx/subsites-enabled/example.org/home:

location = / {
  rewrite ^.*$ /index.pl last;
}

location ~* /community(.*) {
  rewrite ^.*$ /index.pl last;
}

location ~ \.pl {
  root   /var/www/vhosts/home;
  access_log /var/log/nginx/home/access.log;
  error_log /var/log/nginx/home/error.log;

  include /etc/nginx/fastcgi_params;
  fastcgi_index index.pl;
  fastcgi_param SCRIPT_FILENAME /var/www/vhosts/home$fastcgi_script_name;
  fastcgi_pass  unix:/var/run/fcgiwrap.socket;
}

/etc/ngins/subsites-enabled/news

location /news {
  access_log /var/log/nginx/news/access.log;
  error_log /var/log/nginx/news/error.log debug;

  error_page 404 = /news/index.php;

  root /var/www/vhosts/news;

  index index.php;

  if (!-e $request_filename) {
      rewrite ^.*$ /index.php last;
  }

  location ~ \.php {
    include /etc/nginx/fastcgi_params;
    fastcgi_pass  127.0.0.1:9000;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME /var/www/vhosts/news$fastcgi_script_name;
  }
}

在/etc/nginx/子站点已启用/应用程序:

location ~ .* {
  access_log /var/log/nginx/app/access.log;
  error_log /var/log/nginx/app/error.log;

  rewrite_log on;

  index index.php;
  root /var/www/vhosts/app/app/webroot;

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

  if (!-e $request_filename) {
    rewrite ^.*$ /index.php last;
  }

  location ~ \.php {
    include /etc/nginx/fastcgi_params;
    fastcgi_pass  127.0.0.1:9000;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME /var/www/vhosts/app/app/webroot$fastcgi_script_name;
  }
}

答案1

您的配置存在一些问题,其中两个相关问题如下:

  1. 位置块内的路径仍然包含匹配的路径。
  2. 使用“最后”重写将继续通过查看所有可用位置来查找匹配项(它们会突破当前位置块)。

例如,以 URL example.org/news/test.htm 为例

  • location /news块将匹配它
  • 然后使用的路径是/news/test.htm- 这不会改变,只是因为它在位置块中
  • 将路径添加到 document_root,您将获得:/var/www/vhosts/news/news/test.htm
  • 你的if (!-e $request_filename)声明应该捕获这个不存在的文件
  • 你重写路径/index.php
  • 由于您正在使用last重新开始的流程(突破位置块)
  • /index.php现已被 捕获location /app block

当您转到应用程序位置块时,上述使用 root 指令的问题会变得更加严重。与“news”块不同,在“news”块中,您可以从路径中删除“news”(因为它会重新添加),但您无法对以“webroot”结尾的应用程序路径执行此操作。

解决方案在于alias指令。这不会更改 document_root,但会更改用于处理请求的文件路径。不幸的是,rewritetry_files往往会对 产生一些意外的影响alias

让我们从一个简单的例子开始 - 没有 PHP - 只有 HTML 和你的 Perl 块 - 但有一个与你匹配的文件夹结构(在 Nginx 1.0.12、CentOS 6 上测试):

server {
    server_name example.org;
    error_log /var/log/nginx/example.org.error.log notice;
    access_log /var/log/nginx/example.org.access.log;
    rewrite_log on;

    location = / {
        rewrite ^ /index.pl last;
    }

    location ^~ /community {
        rewrite ^ /index.pl last;
    }

    location ~ \.pl {
        root   /var/www/vhosts/home;

        [fastcgi_stuff...]
    }


    location ^~ /news {
        alias /var/www/vhosts/news;
        index index.htm;

        try_files $uri $uri/ /news/index.htm;
    }

    location ^~ /app {
        alias /var/www/vhosts/app/app/webroot;
        index index.htm;

        try_files $uri $uri/ /app/index.htm;
    }

    location / {
        rewrite ^/(.*) /app/$1 last;
    }
}
  • location = /- 仅匹配根路径
  • location ^~ /community- 将匹配以 /community 开头的每个路径
  • location ~ \.pl- 将匹配所有包含 .pl 的文件
  • location ^~ /news- 将匹配以 /news 开头的每个路径
  • location ^~ /app- 将匹配以 /app 开头的每个路径
  • location /- 将匹配上面未匹配的所有路径

您应该能够删除^~- 但它可能会稍微提高性能,因为一旦找到匹配项它就会停止搜索。

虽然重新添加 PHP 块应该是一件简单的事情,但不幸的是,还是有一点困难 - try_files(并且您的重写)最终没有将所需的路径传递到嵌套的位置块 - 并且alias当仅在位置块中指定扩展名时使用不起作用。

一种解决方案是使用单独的位置块与别名指令一起执行捕获 - 它不是很优雅,但据我所知,它确实有效(再次在 Nginx 1.0.12、CentOS 6 上测试 - 当然,我没有设置 CakePHP、Wordpress 和 Perl - 我只是在每个文件夹中使用了几个 PHP 和 HTML 文件)

server {
    server_name example.org;
    error_log /var/log/nginx/example.org.error.log notice;
    access_log /var/log/nginx/example.org.access.log;
    rewrite_log on;

    location = / {
        rewrite ^ /index.pl last;
    }

    location ^~ /community {
        rewrite ^ /index.pl last;
    }

    location ~ \.pl {
        root   /var/www/vhosts/home;
        access_log /var/log/nginx/home.access.log;
        error_log /var/log/nginx/home.error.log;
        include /etc/nginx/fastcgi_params;
        fastcgi_index index.pl;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_pass  unix:/var/run/fcgiwrap.socket;
    }

    location /news {
        access_log /var/log/nginx/news.access.log;
        error_log /var/log/nginx/news.error.log notice;
        alias /var/www/vhosts/news;
        index index.php;
        try_files $uri $uri/ /news/index.php;
    }

    location ~* ^/news/(.*\.php)$ {
        access_log /var/log/nginx/news.php.access.log;
        error_log /var/log/nginx/news.php.error.log notice;
        alias /var/www/vhosts/news/$1;
        try_files "" /news/index.php;
        include /etc/nginx/fastcgi_params;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_NAME $1;
        fastcgi_param SCRIPT_FILENAME /var/www/vhosts/news/$1;
        fastcgi_pass  127.0.0.1:9000;
    }

    location /app {
        alias /var/www/vhosts/app/app/webroot;
        access_log /var/log/nginx/app.access.log;
        error_log /var/log/nginx/app.error.log notice;
        index index.php;
        try_files $uri $uri/ /app/index.php;
    }

    location ~* ^/app/(.*\.php)$ {
        access_log /var/log/nginx/news.access.log;
        error_log /var/log/nginx/news.error.log notice;
        alias /var/www/vhosts/app/app/webroot/$1;
        try_files "" /app/index.php;
        include /etc/nginx/fastcgi_params;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_NAME $1;
        fastcgi_param SCRIPT_FILENAME /var/www/vhosts/app/app/webroot/$1;
        fastcgi_pass  127.0.0.1:9000;
    }

    location / {
        rewrite ^/(.*) /app/$1 last;
    }
}

上面的配置采用了上面的简单配置,并做了两处更改:

  • 添加两个位置块:
    • location ~* ^/news/(.*\.php)$- 将匹配所有以 .php 结尾的文件,路径以 /news/ 开头
    • location ~* ^/app/(.*\.php)$- 将匹配所有以 .php 结尾的文件,路径以 /app/ 开头
  • 删除^~匹配 - 这是必需的,以便两个添加的位置块可以与路径匹配(否则匹配将停止在/news 或/app 块上)。

需要注意的是,这里位置匹配的顺序非常重要:

  • 精确匹配优先(使用=
  • ^~与第二名匹配
  • 匹配正则表达式块
  • 常规字符串 - 仅当未找到匹配的正则表达式时

匹配的正则表达式将取代直字符串!

需要注意的一点是,当使用别名捕获时,整个 URL 都会被替换 - 而不仅仅是前导文件夹。不幸的是,这意味着$fastcgi_script_name保留为空 - 因此,我改用$1上面的方法。

我确信您需要进行一些更改,但基本前提应该是实用的。您应该能够根据需要将块分成多个文件 - 排序不应影响配置。

相关内容