Nginx多个位置问题


14

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

我正在苦苦挣扎的是其中一个应用程序必须是不存在的URL的后备,因此,如果第一个不匹配,而第二个不匹配,则第三个应处理请求

我得到的结构是:

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

3个配置文件中的每一个都包含一个位置块。

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

因此,总结一下:

/和/ 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(蛋糕应用程序)提供

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 / 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;
  }
}

a)发布您的配置,以及有关各种重定向(包括那些不存在的URL)应该进行重定向的示例。b)将try_files@映射到默认应用程序的命名位置块(使用前缀)一起使用。您还可以设置将404映射到命名位置的error_page。
cyberx86

@ cyberx86我添加了更多详细信息和配置
Andrei Serdeliuc 2012年

一眼就能看出以下几点:a)正则表达式匹配优先于常规字符串-因此您的应用程序块将匹配而不是新闻块-try location ^~ /news。b)对于您的应用程序块,您应该能够做到location /(这与并不相同location = /,但是应该匹配所有尚未匹配的内容。c)在某些情况下(尤其是正则表达式),顺序很重要-您可能希望将3文件以正确的顺序排列成一个文件。另外,请使用try_files而不是!-e。最后查看wiki.nginx.org/HttpCoreModule#location
cyberx86 '02

我几乎尝试了所有这些变体,包括将它们组合到一个文件中(尽管它们需要分开部署,因为它们是分开部署的),但它们都不起作用。新闻只是由应用处理。
Andrei Serdeliuc 2012年

好吧,我认为已经解决了这一问题-比我最初预期的要复杂一些-但与之抗衡确实很有趣。谢谢你的困惑。
cyberx86 '02 -2-18

Answers:


45

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

  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指令的问题更加复杂。与“新闻”块不同,可以想象只是从路径中删除“新闻”(因为它将被重新添加),因此您无法对以“ webroot”结尾的应用程序路径执行此操作。

解决方案在于alias指令。这不会更改document_root,但会更改用于处理请求的文件路径。不幸的是,rewrite并且try_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上面使用了。

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


2
杜德,我希望我能投票给你100次。你真棒。谢谢!
Andrei Serdeliuc 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.