nginx 位置块未按预期解析

nginx 位置块未按预期解析

我在 nginx 配置方面遇到了一个奇怪的问题。我有以下服务器块:

server {
  listen 80;
  listen [::]:80;

  server_name stats.example.com;
  root /usr/share/nginx/html;

  location = /foobar {
    return 403;
  }

  # ACME challenge configuration for Letsencrypt
  location ^~ /.well-known/acme-challenge/ {
    try_files $uri =404;
  }

  return 301 https://stats.example.com$request_uri;
}

这是一个简单的块,应该将任何非 https 流量重定向到其 https 对应部分。我尝试为 Certbot for Letsencrypt 在颁发证书之前用于验证域的“ACME 挑战”创建一个例外。我在各种服务器上都有类似的设置,它通常可以正常工作,但在这个特定的服务器上,它似乎无法正确解析位置块。为了验证服务器块,我还添加了自定义/foobar位置,只是为了确保当我点击它时它会抛出 403。

但两个位置块似乎都不起作用。每当我从其中一个请求某些内容时,它都会将 301 返回到服务器块最后一行中设置的 https URL:

% curl -I 'http://stats.example.com/foobar'
HTTP/1.1 301 Moved Permanently
Server: nginx
Date: Mon, 01 May 2017 11:25:10 GMT
Content-Type: text/html
Content-Length: 178
Connection: keep-alive
Location: https://stats.example.com/foobar

它对 ACME 挑战 URL 执行相同的操作,这就是我无法使用 Certbot 为该域颁发证书的原因。我在这里遗漏了什么?为什么位置块不返回 403 或实际文件(或 404)?为什么这里对所有 URL 强制执行 301?

答案1

在调试并尝试了更多解决方案后,我找到了问题所在。显然,nginx 在处理任何位置块之前会解析 301 规则,因此 301 始终是应用于所有 URL 的第一个也是最后一个规则。我创建了一个单独的“catch-all”位置块,如果没有其他位置匹配,它将为 301 提供服务,因此我的最终配置现在如下所示:

server {
  listen 80;
  listen [::]:80;

  server_name stats.example.com;
  root /usr/share/nginx/html;

  # ACME challenge configuration for Letsencrypt
  location ^~ /.well-known/acme-challenge/ {
    try_files $uri =404;
  }

  location / {    
    return 301 https://stats.example.com$request_uri;
  }
}

我现在能够使用 Certbot 成功颁发证书。

相关内容