V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
NGINX
NGINX Trac
3rd Party Modules
Security Advisories
CHANGES
OpenResty
ngx_lua
Tengine
在线学习资源
NGINX 开发从入门到精通
NGINX Modules
ngx_echo
bronana
V2EX  ›  NGINX

想请教大家 nginx 如何判断 server_name

  •  
  •   bronana · 2023-01-12 03:44:45 +08:00 · 2770 次点击
    这是一个创建于 686 天前的主题,其中的信息可能已经有所发展或是发生改变。

    有这样的配置在监听 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;
    }
    
    11 条回复    2023-01-13 13:00:13 +08:00
    Pastsong
        1
    Pastsong  
       2023-01-12 04:09:32 +08:00
    你加个 default 就好了吧 server_name 匹配不到就去 default_server 了
    bronana
        2
    bronana  
    OP
       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
        3
    h0099  
       2023-01-12 04:25:58 +08:00   ❤️ 2
    首先 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
        4
    ETiV  
       2023-01-12 04:32:08 +08:00 via iPhone
    server{
    server_name _;
    listen 80;
    location / { return 401; }
    }
    bronana
        5
    bronana  
    OP
       2023-01-12 04:54:27 +08:00
    @h0099 #3 谢谢回复,读到第二个链接的时候,就解决问题了
    ```
    +server {
    + listen 80 default_server;
    + server_name _; # _ 下划线是无数个无效域名中的一个
    + return 444;
    +}
    ```
    bronana
        6
    bronana  
    OP
       2023-01-12 04:54:52 +08:00
    @ETiV #4 谢谢回复,问题解决了
    bronana
        7
    bronana  
    OP
       2023-01-12 05:00:25 +08:00
    @Pastsong #1 谢谢回复,好像结果和您说的差不多,可能是我先前操作还是不当.问题解决了,再次感谢.
    h0099
        8
    h0099  
       2023-01-12 17:52:40 +08:00   ❤️ 1
    #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
        9
    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
        10
    RynItme  
       2023-01-13 10:27:42 +08:00
    配置泛解析 *
    bronana
        11
    bronana  
    OP
       2023-01-13 13:00:13 +08:00
    @RynItme #10 正解,我试过 *.domain.cc,这个也可以.
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1107 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 19:27 · PVG 03:27 · LAX 11:27 · JFK 14:27
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.