想请教大家 nginx 如何判断 server_name

2023-01-12 03:44:45 +08:00
 bronana

有这样的配置在监听 80 端口

server {
    listen       80;
    server_name  www.domain.cc
        cloud.domain.cc
        mail.domain.cc
        blog.domain.cc
        linux.domain.cc
        tools.domain.cc
        notebook.domain.cc
        domain.cc;

    return 301 https://$host$request_uri;
}

我想要判断访问的 host 是否在 server_name 里面

server {
    listen       80;
    server_name  www.domain.cc
        cloud.domain.cc
        mail.domain.cc
        blog.domain.cc
        linux.domain.cc
        tools.domain.cc
        notebook.domain.cc
        domain.cc;
    #region 这里应该怎么写?
    if ($host not in server_name) {
      # 在此返回 404 结束
      return 404;
      exit;
    }
    #endregion

    return 301 https://$host$request_uri;
}
2518 次点击
所在节点    NGINX
11 条回复
Pastsong
2023-01-12 04:09:32 +08:00
你加个 default 就好了吧 server_name 匹配不到就去 default_server 了
bronana
2023-01-12 04:19:41 +08:00
@Pastsong #1 刚试了不可以,它直接走 `return 301 https://$host$request_uri;`了,

假设我有只有一个服务在 `https://cloud.domain.cc`,没有 `https://blog.domain.cc`,

`cloud.domain.cc` 和 `blog.domain.cc` 域名解析是指向的同一个服务器(ip 一样)

有人访问`blog.domain.cc`这个不存在的网站,打开的却是`cloud.domain.cc`网站.
h0099
2023-01-12 04:25:58 +08:00
首先 if is evil https://www.nginx.com/resources/wiki/start/topics/depth/ifisevil/
我想阁下现在遇到的问题是请求任何`非`列出来的这些子域时(例如`curl -I `Host: example.com` -v http://您的服务端 IP`)仍然会匹配这个 block 导致进入`return 301 https://$host$request_uri`
如果您所有的 nginx.conf 文件中只有这一个 server block 那么文档 http://nginx.org/en/docs/http/request_processing.html 对此早有预言
> If its value does not match any server name, or the request does not contain this header field at all, then nginx will route the request to the default server for this port. In the configuration above, the default server is the first one — which is nginx’s standard default behaviour

要想在 80 和 443 上搭建正确的 default http(s) server 您可以参考 https://serverfault.com/questions/847978/best-practice-to-handle-default-server-and-public-ip-in-nginx
一个常见错误是只设置了 port80 的 default server ,导致使用 http 或 https 协议请求 443 (或其他)端口时仍然会绕过 default server (因为 default 是针对单个 listen 端口的)
http://nginx.org/en/docs/http/ngx_http_core_module.html#listen 进一步指出:
> The default_server parameter, if present, will cause the server to become the default server for the specified address:port pair. If none of the directives have the default_server parameter then the first server with the address:port pair will be the default server for this pair.

```nginx
server {
listen 80 fastopen=256 default_server;
listen 443 fastopen=256 ssl default_server;
server_name _ "";
access_log path/to/log/default.access.log;
error_log path/to/log/default.error.log;

ssl_certificate /etc/nginx/snippets/self-signed-ssl.crt; # 使用 openssl 生成的自签名证书 https://stackoverflow.com/questions/10175812/how-to-generate-a-self-signed-ssl-certificate-using-openssl
ssl_certificate_key /etc/nginx/snippets/self-signed-ssl.key;

return 444; # https://nginx.org/en/docs/http/ngx_http_rewrite_module.html#return The non-standard code 444 closes a connection without sending a response header. https://www.reddit.com/r/Network/comments/e8aveo/nginx_explain_http_444_like_im_five/
}
ETiV
2023-01-12 04:32:08 +08:00
server{
server_name _;
listen 80;
location / { return 401; }
}
bronana
2023-01-12 04:54:27 +08:00
@h0099 #3 谢谢回复,读到第二个链接的时候,就解决问题了
```
+server {
+ listen 80 default_server;
+ server_name _; # _ 下划线是无数个无效域名中的一个
+ return 444;
+}
```
bronana
2023-01-12 04:54:52 +08:00
@ETiV #4 谢谢回复,问题解决了
bronana
2023-01-12 05:00:25 +08:00
@Pastsong #1 谢谢回复,好像结果和您说的差不多,可能是我先前操作还是不当.问题解决了,再次感谢.
h0099
2023-01-12 17:52:40 +08:00
#4 @ETiV listen directive 必须加 default 修饰,不然按照 nginx 的脑瘫逻辑,他只会将他读到的所有 conf 文件中第一个出现的 listen 作为 default

#3
如果您所有的 nginx.conf 文件中只有这一个 server block 那么文档
http://nginx.org/en/docs/http/request_processing.html 对此早有预言
> If its value does not match any server name, or the request does not contain this header field at all, then nginx will route the request to the default server for this port. In the configuration above, the default server is the first one — which is nginx’s standard default behaviour
h0099
2023-01-12 17:55:13 +08:00
#5 @bronana 您忘了配置 https 版本以及监听 443 端口的 default listen ,我猜您现在执行
`curl -v -I 'Host: example.com' https://您的服务器 ip`
又会进入最初的`return 301 https://$host$request_uri`

#4 对此早有预言
> 一个常见错误是只设置了 port80 的 default server ,导致使用 http 或 https 协议请求 443 (或其他)端口时仍然会绕过 default server (因为 default 是针对单个 listen 端口的)
RynItme
2023-01-13 10:27:42 +08:00
配置泛解析 *
bronana
2023-01-13 13:00:13 +08:00
@RynItme #10 正解,我试过 *.domain.cc,这个也可以.

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/908296

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX