Nginx 支持多个域名共用一个 443 端口,并为每个域名配置不同的 SSL 证书。这项功能依赖 SNI(Server Name Indication,服务器名称指示) 技术来实现。
简单来说,当客户端(如浏览器)发起 HTTPS 连接时,会在 TLS 握手阶段通过 SNI 扩展告诉 Nginx 它要访问的域名。Nginx 收到后,就能根据这个域名,从众多 `server` 块中匹配到正确的配置,并使用对应的证书。
核心配置思路是为每个域名创建一个独立的 `server` 块。以下是一个基础配置
1. 为每个域名配置独立的 server 块
```nginx
第一个域名:example.com
server {
listen 443 ssl;
server_name example.com www.example.com;
# 指定该域名对应的证书和私钥
ssl_certificate /etc/nginx/ssl/example.com/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/example.com/privkey.pem;
# 网站根目录或其他配置
root /var/www/example.com;
# ... 其他 location 配置
}
第二个域名:another-site.com
server {
listen 443 ssl;
server_name another-site.com www.another-site.com;
# 使用另一套独立的证书
ssl_certificate /etc/nginx/ssl/another-site.com/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/another-site.com/privkey.pem;
root /var/www/another-site;
# ... 其他 location 配置
}
```
2. 优化:提取公共 SSL 配置
如果多个域名的 SSL 参数(如协议版本、加密套件等)相同,可以将其提取到一个公共文件中,用 `include` 指令引入,使配置更简洁。
首先,创建一个公共配置文件,例如 `/etc/nginx/ssl-common.conf`:
```nginx
# /etc/nginx/ssl-common.conf
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
# ... 其他 SSL 相关配置
```
然后,在每个 `server` 块中引入它:
```nginx
server {
listen 443 ssl;
server_name example.com www.example.com;
ssl_certificate /etc/nginx/ssl/example.com/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/example.com/privkey.pem;
# 引入公共 SSL 配置
include /etc/nginx/ssl-common.conf;
root /var/www/example.com;
}
```
3. (可选)配置默认 server 块处理未匹配请求
建议配置一个默认的 `server` 块,用于处理那些无法通过 `server_name` 匹配的请求,例如直接通过 IP 访问。
```nginx
server {
listen 443 ssl default_server;
server_name _; # 匹配任何未指定的域名
# 可以配置一个默认证书,或者直接拒绝连接
ssl_certificate /etc/nginx/ssl/default/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/default/privkey.pem;
return 444; # 直接关闭连接,不返回任何响应
}
```
4. 验证与测试
配置完成后,务必按以下步骤验证,确保无误:
1. 检查配置文件语法:
```bash
nginx -t
```
如果显示 `syntax is ok` 和 `test is successful`,说明配置语法正确。
2. 重载 Nginx 配置:
```bash
nginx -s reload
```
3. 测试证书是否匹配:
使用 `openssl` 命令模拟带有 SNI 的请求,可以验证服务器是否返回了正确的证书。
```bash
openssl s_client -connect example.com:443 -servername example.com
```
检查输出中的证书信息,确认是否为 `example.com` 的证书。
重要注意事项
证书要求:每个 `server` 块中 `server_name` 指定的域名,必须被该块中 `ssl_certificate` 对应的证书所覆盖(即证书的通用名称 `CN` 或使用者备用名称 `SAN` 中需包含该域名)。
路径与权限:`ssl_certificate` 和 `ssl_certificate_key` 应使用绝对路径。确保证书文件(`.pem`/`.crt`)权限为 `644`,私钥文件(`.key`)权限为 `600`。
SNI 兼容性:SNI 已被所有现代浏览器和操作系统广泛支持。对于极少数不支持 SNI 的旧客户端,Nginx 无法正确匹配域名,将回退到默认的 `server` 块。
listen 指令:确保 `listen` 指令中包含 `ssl` 参数,这是启用 SSL 的现代写法。
HTTP 跳转:别忘了为每个域名配置监听 80 端口的 `server` 块,将 HTTP 请求重定向到 HTTPS。