Nginx多域名虚拟主机配置与TLS证书绑定实战指南

本文面向运维人员,系统讲解Nginx多域名虚拟主机的配置方法,涵盖server_name匹配规则、不同域名指向不同站点、以及TLS证书绑定的完整流程,包括SSL配置、HTTP跳转、OCSP Stapling等安全优化项,并提供验证与排错技巧。

Nginx多域名虚拟主机配置与TLS证书绑定实战指南
封面图:ZuCDN · ZuCDN 原创

前言:为什么需要多域名虚拟主机与SSL绑定

在实际生产环境中,一台服务器往往需要同时承载多个网站或应用,例如 example.com、api.example.com、admin.example.com。Nginx 的虚拟主机(Server Block)机制允许通过不同的 server_name 来区分请求,并将流量分发到对应的站点目录或上游服务。与此同时,HTTPS 已成为默认要求,每个域名都需要绑定有效的 TLS 证书,以确保通信加密和用户信任。

本文假设读者已安装 Nginx 并具备基础操作能力,将直接围绕配置文件展开,不介绍安装步骤。所有指令均经过实际测试,适用环境为 CentOS 7/8、Ubuntu 20.04/22.04 及主流 Linux 发行版。

一、多域名虚拟主机基础配置

1.1 理解 server_name 匹配规则

Nginx 通过 server_name 指令匹配 HTTP 请求中的 Host 头部。多个域名可以用空格分隔,如:

server_name example.com www.example.com

如果请求的 Host 与任何 server_name 都不匹配,则会落入默认 server 块(通常是监听 80 端口的第一个 server 块)。为了安全,建议显式定义一个默认返回 444 的 server 块:

server {
    listen 80 default_server;
    server_name _;
    return 444;
}

正则匹配使用 ~ 开头,例如 ~^(www.)?mydomain.com$,但一般场景下直接使用精确域名即可。

1.2 创建独立的配置文件

推荐将每个虚拟主机的配置单独存放于 /etc/nginx/conf.d//etc/nginx/sites-enabled/ 目录下。例如:

/etc/nginx/conf.d/example.com.conf
/etc/nginx/conf.d/api.example.com.conf
/etc/nginx/conf.d/admin.example.com.conf

每个文件包含一个 server 块,分别定义 root、index、location 等。这种组织方式便于维护和单独启停。

1.3 示例:静态站点与反向代理混合

假设 example.com 为静态站点,api.example.com 为 Node.js 后端。配置如下:

# example.com.conf
server {
    listen 80;
    server_name example.com www.example.com;
    root /var/www/example;
    index index.html;
}

# api.example.com.conf
server {
    listen 80;
    server_name api.example.com;
    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

二、TLS 证书绑定与 HTTPS 配置

2.1 准备证书文件

使用 Let’s Encrypt 免费证书或商业证书。假设证书文件位于 /etc/ssl/example.com/ 下:

  • fullchain.pem - 包含服务器证书与中间证书链
  • privkey.pem - 私钥(权限需设为 600)
  • 某些情况还需要 chain.pem(中间证书)

私钥安全是底线,务必使用 chmod 600 privkey.pem 并归 owner 为 root 或 nginx。

2.2 配置 HTTPS server 块

修改原有虚拟主机,增加监听 443 端口的 server 块。例如:

server {
    listen 443 ssl http2;
    server_name example.com www.example.com;

    ssl_certificate /etc/ssl/example.com/fullchain.pem;
    ssl_certificate_key /etc/ssl/example.com/privkey.pem;

    root /var/www/example;
    index index.html;
}

重要参数说明:

  • ssl 开启 SSL/TLS,http2 启用 HTTP/2 提升性能
  • ssl_certificate 使用 fullchain.pem,而非仅 server.crt
  • 证书路径不要包含空格或中文字符

2.3 强制 HTTP 重定向到 HTTPS

保留原监听 80 的 server 块,将其改为 301 跳转:

server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://$host$request_uri;
}

注意 $host 会保持原始域名,避免将 api.example.com 跳转到 example.com 的情况。如果所有子域名共用同一套跳转逻辑,也可以使用泛域名证书,但需确保每个域名均能通过验证。

三、多域名 TLS 绑定的高级实践

3.1 SNI(服务器名称指示)

Nginx 默认支持 SNI,即一台服务器可以绑定多个不同域名的 SSL 证书。只需为每个域名分别配置独立的 server 块并指定对应的 ssl_certificate 即可。Nginx 根据客户端握手时发送的域名选择正确的证书。

验证 SNI 是否正常工作:

openssl s_client -connect example.com:443 -servername example.com

注意:所有 HTTPS 配置都必须包含 listen 443 ssl,且 server_name 与证书中的 CN 或 SAN 匹配。

3.2 安全加固参数

以下配置可移除老旧协议,启用现代密码套件:

ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;

若使用 ECDSA 证书,需确保密码套件顺序优先 ECDHE-ECDSA。可借助 Mozilla SSL Configuration Generator 生成符合自身需求的配置。

3.3 OCSP Stapling 与 HSTS

开启 OCSP Stapling 可以提升握手速度并减轻 CA 服务器的压力:

ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;

HSTS(HTTP Strict Transport Security)告知浏览器强制 HTTPS:

add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;

注意:启用 includeSubDomains 前务必确认所有子域名均已支持 HTTPS,否则可能造成子域名无法访问。

四、配置验证与排错

4.1 测试配置语法

nginx -t

输出 syntax is oktest is successful 后,方可 reload:

systemctl reload nginx

4.2 使用 curl 验证 HTTPS

检查证书链是否完整:

curl -I https://example.com

查看证书信息:

openssl s_client -connect example.com:443 -servername example.com -showcerts

注意 -servername 参数必须与请求域名一致,否则 SNI 不会生效。

4.3 常见问题

  • SSL_ERROR_BAD_CERT_DOMAIN:证书中的域名未包含 server_name 中声明的域名,需重新申请证书或使用通配符证书。
  • chown: invalid user: ‘nginx’:用户权限问题,检查 nginx worker 进程用户(通常是 nginx 或 www-data),确保私钥可被读取。
  • 443 port conflict:多个 server 块未正确绑定不同域名,或默认 server 块配置不当。检查 netstat -tulpn | grep 443
  • 证书链不完整:SSL 握手时浏览器提示“未提供中间证书”。解决方法是将中间证书合并到 fullchain.pem 中,或使用 ssl_trusted_certificate 指令。

结语

Nginx 的多域名虚拟主机和 TLS 证书绑定是服务器运维中最常见的任务之一,但细节往往决定成败。从 server_name 的精确匹配、配置文件的结构化组织,到 SSL 协议的现代参数选择,每一步都需要严谨对待。建议在正式上线前使用 SSL Labs 的在线测试工具检查评级,并定期更新证书。

掌握本文所述的方法,你可以在单台服务器上稳定托管数十个域名,同时保证安全性和性能。如果在实践过程中遇到问题,欢迎留言讨论。

延伸阅读