惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

J
Java Code Geeks
GbyAI
GbyAI
Google DeepMind News
Google DeepMind News
Jina AI
Jina AI
B
Blog
aimingoo的专栏
aimingoo的专栏
酷 壳 – CoolShell
酷 壳 – CoolShell
T
The Blog of Author Tim Ferriss
Last Week in AI
Last Week in AI
月光博客
月光博客
H
Help Net Security
V
Visual Studio Blog
量子位
A
About on SuperTechFans
博客园 - Franky
人人都是产品经理
人人都是产品经理
N
Netflix TechBlog - Medium
云风的 BLOG
云风的 BLOG
雷峰网
雷峰网
Martin Fowler
Martin Fowler
Microsoft Security Blog
Microsoft Security Blog
博客园 - 叶小钗
P
Proofpoint News Feed
MongoDB | Blog
MongoDB | Blog

达拉斯・卢

一些没有意义的事情 博客程序的一次大重构 OpenWRT 使用 udp2raw 对抗 WireGuard 阻断 OpenWRT 使用 udp2raw 对抗 WireGuard 阻断 博客程序架构的思考与展望 如何证明你是原创作者 如何证明你是原创作者 Nginx 泛域名配置的隐患与对策 WISeID S/MIME 证书 WISeID S/MIME 证书 V2EX 刑满释放记 V2EX 刑满释放记 使用 Radicale 在 Ubuntu 24.04 中搭建 vCards CardDav 服务 使用 Radicale 在 Ubuntu 24.04 中搭建 vCards CardDav 服务 邮件服务的域名成功从 SURBL 黑名单移除 邮件服务的域名成功从 SURBL 黑名单移除 网站多语言的设计细节 网站多语言的设计细节 网站评论系统的目前进展和展望 网站评论系统的目前进展和展望 在公网使用 iptables 转发端口时保留客户端 IP 在公网使用 iptables 转发端口时保留客户端 IP 邮件投递平台 Postal 的使用经验 邮件投递平台 Postal 的使用经验 自建 Postal 完美替代 SendGrid 自建 Postal 完美替代 SendGrid 互联网在崩塌吗,然后呢 互联网在崩塌吗,然后呢 在 SvelteKit 应用中使用 JSON-LD 在 SvelteKit 应用中使用 JSON-LD
Nginx 泛域名配置的隐患与对策
达拉斯・卢 · 2025-05-23 · via 达拉斯・卢

一个网站的程序支持多站点模式,于是为了方便,在 Nginx 中绑定了域名 *.example.com,但奇怪的是,访问记录中总是有一些奇怪的二级域名,让人隐约觉得不妥。本文记述使用 Nginx 的来规避类似的风险。

Wildcard 域名绑定

原本的 Nginx 大约如下:

server {
    listen 80;
    server_name *.example.com;

    // blabla
}

这样配置简单方便。不过如果你的网站并不是多站点模式,或者网站程序未能恰当地处理,会导致任意二级域名却都能正常访问网站内容,是有点奇怪的。也许有人故意构造并发布了一个链接,不幸又被爬虫抓取,想想一下,从这个流量来源过来的访客们,纷纷皱着眉头看着你的奇怪的二级域名。这是一个未预期的行为,会影响 SEO,且有一定的合规风险,应当采取一些措施。

如果二级站点数量有限,可以手动列出全部二级域名:

server {
    listen 80;
-    server_name *.example.com;
+    server_name
+        www.example.com
+        cdn.example.com
+        api.example.com;
}

倘若你有更复杂的需要,仍需要保留 *.example.com 以简化配置,那么就可以加一个白名单的校验。

在 Nginx 中 $server_name 代表的是 server_name 配置中的第一个值,因此将网站的主域名放在第一位就非常方便后续处理。

如果你曾经使用过 blog.example.com,如今回归到 www.example.com, 那么更合适的办法应该是重定向。而其他未预期的域名都可以使用 return 444; 来直接断开连接。

server {
    listen 80;
-    server_name *.example.com;
+    server_name www.example.com example.com *.example.com;
+
+    if ($host ~* ^((blog|feed|log)\.example\.com|example.com)$) {
+        return 307 $scheme://$server_name$request_uri;
+    }
+
+    if ($host !~* ^(cdn|api)\.example\.com$) {
+        return 444;
+    }
}

默认主机

除了泛域名绑定之外,默认主机也会有类似的问题。如果在中国大陆,有未备案的域名指向到你的服务器,也有监管的风险。直接让默认主机断开所有连接:

server {
    listen 80 default_server;
    server_name _;

    return 444;
}

在某些情况下,你可能需要在阻断未指定域名的同时,支持使用 IP 地址直接访问:

-return 444;
+if ($host !~* "^((?:\d{1,3}\.){3}\d{1,3}|(?:[a-fA-F0-9:]+))$") {
+    return 444;
+}

SNI 域名泄露

在尝试 HTTPS 访问时,即便 Nginx 断开了连接,但客户端仍能够从返回的证书中获取 SNI 域名列表。很多人使用 CDN 全站加速来隐藏真实 IP,被扫描 IP 时,可能就会泄漏服务器与域名的关联。

可以在 server 块中配置,拒绝 ssl 握手:

+ssl_reject_handshake on;

如果你还是希望能够支持使用 IP 地址直接访问……那么,要使用一个 IP 专用的 SSL 证书。IP 证书购买渠道有限,自签一个也是可以的。

生成一个 IPv4 地址的证书:

openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
  -keyout ip.key -out ip.crt \
  -subj "/CN=1.2.3.4" \
  -addext "subjectAltName=IP:1.2.3.4"

如果你还希望支持 IPv6……建立自签证书的配置 openssl-san.conf

[req]
distinguished_name = req_distinguished_name
x509_extensions = v3_req
prompt = no

[req_distinguished_name]
CN = (ip or domain or keep bank)

[v3_req]
subjectAltName = @alt_names

[alt_names]
IP.1 = 1.2.3.4
IP.2 = 2001:db8::1

openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
  -keyout ip-mixed.key -out ip-mixed.crt \
  -config openssl-san.conf

然后配置 Nginx:

server {
    listen 80 default_server;
    listen [::]:80 default_server;
    listen 443 ssl default_server;
    listen [::]:443 ssl default_server;

    server_name _;

    ssl_certificate /path/to/ip.crt;
    ssl_certificate_key /path/to/ip.key;

    if ($host !~* "^((?:\d{1,3}\.){3}\d{1,3}|(?:[a-fA-F0-9:]+))$") {
        return 444;
    }
}

避免 CDN 域名被收录

    root /path/to/webroot/www.example.com;

    location = /robots.txt {
        default_type text/plain;

        if ($host = 'cdn.example.com') {
            #return 200 "User-agent: *\nAllow: /*.png$\nDisallow: /\n";
            alias /path/to/webroot/www.example.com/robots-cdn.txt;
        }
    }