Nginx 多位置问题

And*_*iuc 17 nginx

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

我正在努力解决的是其中一个应用程序需要成为不存在网址的后备,因此如果第一个不匹配,第二个不匹配,那么第三个应该处理请求

我得到的结构是:

/etc/nginx/sites-enabled/main_site,在这里,除了 server_name 和日志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 app) 提供

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/*;
}
Run Code Online (Sandbox Code Playgroud)

/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;
}
Run Code Online (Sandbox Code Playgroud)

/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;
  }
}
Run Code Online (Sandbox Code Playgroud)

/etc/nginx/subsites-enabled/app:

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;
  }
}
Run Code Online (Sandbox Code Playgroud)

cyb*_*x86 52

您的配置有一些问题,两个相关的问题是:

  1. 位置块内的路径仍然包括匹配的路径。
  2. 使用 'last' 重写继续查看匹配的所有可用位置(它们跳出当前位置块)。

例如,使用 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 指令的问题会变得更加复杂。与“新闻”块不同,您可以想象从路径中删除“新闻”(因为它将被重新添加),您不能对以“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;
    }
}
Run Code Online (Sandbox Code Playgroud)
  • location = / - 只会匹配根路径
  • location ^~ /community - 将匹配所有以 /community 开头的路径
  • location ~ \.pl - 将匹配所有包含 .pl 的文件
  • location ^~ /news - 将匹配所有以 /news 开头的路径
  • location ^~ /app - 将匹配所有以 /app 开头的路径
  • location / - 将匹配上面不匹配的所有路径

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

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

一种解决方案是使用单独的位置块与 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

  • 首先完全匹配(使用=
  • ^~第二个匹配
  • 匹配正则表达式块
  • 常规字符串 - 仅当找不到匹配的正则表达式时

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

重要的一点是,当捕获与别名一起使用时,整个 URL 将被替换 - 而不仅仅是前导文件夹。不幸的是,这意味着它$fastcgi_script_name是空的 - 所以,我用$1上面代替。

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

  • 伙计,我希望我能为你点赞 100 次。你真是太棒了。谢谢! (2认同)