Nginx不支持直接在server_name中使用IDN(如“你好.中国”),必须使用Punycode编码后的ASCII域名(如“xn--fsq088a.xn--fiqs8s”);HTTPS需证书SAN包含对应Punycode,否则报错。

Nginx 本身不直接支持国际化域名(IDN)的 server_name 原生写法,比如不能直接写 server_name 你好.中国; 或 server_name café.example;。它只接受 ASCII 格式的域名(即 Punycode 编码后的形式)。所以要在 Nginx 中正确匹配 IDN,关键不是“在配置里写中文”,而是把用户输入的国际化域名,先转成标准 Punycode,再填进 server_name。
必须用 Punycode 编码后填写
IDN 在 DNS 和 HTTP 协议底层都要求转换为 ASCII 兼容编码(ACE),也就是 Punycode。浏览器访问 例子.中国 时,实际发出的 Host 请求头是 xn--fsq088a.xn--fiqs8s。Nginx 匹配的是这个 ASCII 形式,不是原始 Unicode 字符串。
- 使用 Linux 自带的
idn工具转码:idn 例子.中国→ 输出xn--fsq088a.xn--fiqs8sidn café.example→ 输出caf-dma.example - 把转换结果作为
server_name的值:server_name xn--fsq088a.xn--fiqs8s; - 注意:不要混用,比如
server_name 例子.中国 xn--fsq088a.xn--fiqs8s;—— 前者无效,后者才生效
HTTPS 下需 SAN 证书覆盖 Punycode 域名
如果启用 HTTPS,SSL/TLS 握手阶段的 SNI 扩展传递的也是 Punycode 域名。证书必须包含该 Punycode 形式,否则会触发浏览器证书错误。
- 申请证书时,-d 参数必须用 Punycode:
certbot -d xn--fsq088a.xn--fiqs8s - 不能只写原始 IDN:
certbot -d 例子.中国会导致证书不被信任 - 若同时支持 ASCII 和 IDN 访问(如 example.com + 例子.中国),两个 Punycode 都要加进 SAN 列表
可选:用正则提取并记录原始 Host(便于日志或跳转)
虽然 server_name 必须是 Punycode,但请求头里的 $host 变量在某些场景下仍可能是解码后的 IDN(取决于客户端和中间代理)。更可靠的做法是用正则捕获 Punycode 并映射回可读名:
server {<br> listen 80;<br> server_name xn--fsq088a.xn--fiqs8s;<br> location / {<br> set $display_name "例子.中国";<br> add_header X-Display-Domain $display_name;<br> }<br>}
常见误区提醒
以下做法均无效或危险:
- 直接在
server_name中写 UTF-8 字符(Nginx 启动失败或静默忽略) - 仅靠 DNS 解析支持 IDN 就以为 Nginx 能自动识别(DNS 和 Nginx 匹配是两层,Nginx 不参与 IDN 解码)
- HTTPS 配置了 IDN 域名但证书没包含对应 Punycode(必报证书错误)
- 依赖
if ($host = "例子.中国")做判断($host 此时通常是 Punycode,字符串不等)


















