Nginx 不选择具有最长前缀的位置

Nginx 不选择具有最长前缀的位置

在这个简化的 nginx 设置中,我有两个 nginx 位置块,一个用于 SSL 证书更新,一个用于快速代理(用于 uwsgi/Django )。

当通过 acme.sh 进行 SSL 证书更新时,它会将文件放入其中/var/www/example.com/public/.well-known/acme-challenge/,然后测试它们是否可用。但是,快速代理 (Django) 正在处理请求,/.well-known/acme-challenge/.......而不是location = /\.well-known/acme-challenge/位置块。

我该如何告诉 nginx 使用正确的块?如果我删除快速代理位置块,则该location = /\.well-known/acme-challenge/块可以正常工作。

配置如下:

server { 
    listen 443 ssl http2; 
    listen [::]:443 ssl http2; # For IP6 
    server_name www.example.com; 
    charset utf-8; 
    root /var/www/example.com/public; 

    # acme.sh SSL certificate issues
    location /\.well-known/acme-challenge/ {
    }

    # Finally, send all non-media requests to the Django server.
    location / {
        uwsgi_pass django;
        include /home/michael/project/conf/uwsgi/params;  
    } 

nginx 文档说:

当 nginx 选择一个位置块来处理请求时,它首先检查指定前缀的位置指令,记住前缀最长的位置,然后检查正则表达式。如果与正则表达式匹配,nginx 将选择此位置,否则,它将选择先前记住的位置。

对我来说/\.well-known/acme-challenge/这是最长的前缀,所以它应该“获胜”。

答案1

你看过location指示

~*位置既可以通过前缀字符串定义,也可以通过正则表达式定义。正则表达式使用前面的“ ”修饰符(用于不区分大小写的匹配)或“ ~”修饰符(用于区分大小写的匹配)指定。

为了找到与给定请求匹配的位置,nginx 首先检查使用前缀字符串(前缀位置)定义的位置。其中,选择并记住具有最长匹配前缀的位置。然后按照正则表达式在配置文件中出现的顺序检查正则表达式。正则表达式的搜索在第一次匹配时终止,并使用相应的配置。如果没有找到与正则表达式匹配的,则使用先前记住的前缀位置的配置。

您的location /\.well-known/acme-challenge/字符串是前缀字符串,但您尝试将其转义.为正则表达式。这不起作用。

对于 URL https://www.example.com/.well-known/acme-challenge/foo...

server { 
    listen 443 ssl http2; 
    server_name www.example.com; 

    # 1. Prefix string, NO MATCH.
    location /\.well-known/acme-challenge/ {
    }

    # 2. Longest matching prefix string.
    location /.well-known/acme-challenge/ {
    }

    # 3. First case sensitive regex match.
    location ~ /\.well-known/acme-challenge/ {
    }

    # 4. Another case sensitive regex match.
    location ~ ^/\.well-known/acme-challenge/ {
    }

    # 5. Matching prefix string, but not the longest.
    location / {
    }
}

如果您拥有所有这些,则将使用正则表达式匹配 #3,因为它是第一个匹配的正则表达式。它还会与/any/path/having/.well-known/acme-challenge/in/it#4 匹配,而 #4 仅在 URI 路径的开头匹配,类似于前缀字符串匹配。

TL;DR:#2 和 #4 是等效的,通过这两者您都可以实现您的目标。

为了完整性,评估顺序如下:

  1. #1 前缀,不匹配
  2. #2 前缀,匹配(长度=28)
  3. #5 前缀,匹配(长度=1)
  4. #3 正则表达式,匹配 => 选择

#4 不会被评估。如果没有 #3 和 #4,#2 就会获胜。

相关内容