1. Nginx多域名多证书多服务配置实战指南
作为Web服务领域的瑞士军刀,Nginx在实际业务中经常需要同时处理多个域名的HTTPS服务。不同于单域名配置,多域名场景下既要考虑证书管理效率,又要确保各服务间的隔离性。我在金融级业务系统中部署过同时承载200+域名的Nginx实例,这里分享经过生产验证的配置方案。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 基础环境准备
2.1 证书管理策略
多证书场景推荐采用目录分类存储:
code复制/etc/nginx/certs/
├── domainA/
│ ├── fullchain.pem
│ └── privkey.pem
├── domainB/
│ ├── fullchain.pem
│ └── privkey.pem
└── wildcards/
├── star_domainC.pem
└── star_domainC.key
关键技巧:使用ACME.sh自动化续期时,通过--reloadcmd "nginx -t && systemctl reload nginx"参数实现证书自动更新后的服务重载
2.2 服务隔离方案
建议采用"一对多"映射模式:
- 每个业务服务对应独立的upstream组
- 相同功能域名的server块合并处理
- 特殊路径通过location规则分流
3. 核心配置实现
3.1 多域名HTTPS监听
nginx复制server {
listen 443 ssl http2;
server_name api.domain.com;
ssl_certificate /etc/nginx/certs/domainA/fullchain.pem;
ssl_certificate_key /etc/nginx/certs/domainA/privkey.pem;
location / {
proxy_pass http://api_backend;
proxy_set_header Host $host;
}
}
server {
listen 443 ssl http2;
server_name static.domain.com;
ssl_certificate /etc/nginx/certs/domainB/fullchain.pem;
ssl_certificate_key /etc/nginx/certs/domainB/privkey.pem;
location / {
root /var/www/static;
expires 30d;
}
}
3.2 通配符证书配置
nginx复制server {
listen 443 ssl http2;
server_name *.domain.net;
ssl_certificate /etc/nginx/certs/wildcards/star_domain.net.pem;
ssl_certificate_key /etc/nginx/certs/wildcards/star_domain.net.key;
# 根据子域名动态路由
if ($host ~* ^(.*)\.domain\.net$) {
set $subdomain $1;
}
location / {
proxy_pass http://$subdomain.service.cluster.local;
}
}
4. 高级路由策略
4.1 基于SNI的预处理
在stream层面对TLS握手进行预处理:
nginx复制stream {
map $ssl_server_name $backend {
hostnames;
default upstream_default;
api.domain.com upstream_api;
static.domain.com upstream_static;
}
server {
listen 443;
proxy_pass $backend;
ssl_preread on;
}
}
4.2 动态证书加载
使用Lua脚本实现证书动态加载:
nginx复制server {
listen 443 ssl;
ssl_certificate_by_lua_block {
local ssl = require "ngx.ssl"
local host = ssl.server_name()
if host then
local cert_path = "/etc/nginx/certs/"..host:gsub("%.", "_").."/fullchain.pem"
local key_path = "/etc/nginx/certs/"..host:gsub("%.", "_").."/privkey.pem"
if os.rename(cert_path, cert_path) and os.rename(key_path, key_path) then
ssl.clear_certs()
ssl.set_der_cert(assert(io.open(cert_path):read("*a")))
ssl.set_der_priv_key(assert(io.open(key_path):read("*a")))
end
end
}
}
5. 性能优化要点
5.1 SSL会话缓存共享
nginx复制ssl_session_cache shared:SSL:50m;
ssl_session_timeout 1d;
ssl_session_tickets off;
# 启用OCSP装订提升验证效率
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 valid=300s;
5.2 多证书内存优化
通过ssl_buffer_size调整内存分配:
nginx复制ssl_buffer_size 4k; # 默认16k,多证书场景建议调小
ssl_certificate /etc/nginx/certs/domainA/fullchain.pem;
ssl_certificate_key /etc/nginx/certs/domainA/privkey.pem;
6. 运维监控方案
6.1 证书过期监控
使用Prometheus监控证书有效期:
nginx复制server {
listen 9145;
location /metrics {
content_by_lua_block {
local f = io.popen("find /etc/nginx/certs -name '*.pem' -exec openssl x509 -enddate -noout {} \\;")
for line in f:lines() do
ngx.say(string.format('nginx_cert_expire{cert="%s"} %d',
line:match("notAfter=(.+)"),
os.time({year=line:match("notAfter=(%a+)%s+(%d+)%s+(%d+)")})
))
end
}
}
}
6.2 配置自动化校验
在CI/CD流程中加入配置校验:
bash复制#!/bin/bash
for conf in /etc/nginx/conf.d/*.conf; do
if ! nginx -t -c $conf; then
echo "Config validation failed: $conf"
exit 1
fi
done
7. 常见问题排查
7.1 证书不匹配错误
典型报错:
code复制SSL_do_handshake() failed (SSL: error:14094418:SSL routines:ssl3_read_bytes:tlsv1 alert unknown ca)
排查步骤:
- 检查证书链完整性:
openssl verify -CAfile chain.pem cert.pem - 确认SNI支持:
openssl s_client -connect domain:443 -servername domain -tlsextdebug - 验证协议兼容性:
nmap --script ssl-enum-ciphers -p 443 domain
7.2 性能瓶颈分析
使用systemtap进行深度追踪:
bash复制stap -e 'probe process("nginx").function("ssl3_accept") {
printf("%d %s %d\n", pid(), execname(), gettimeofday_us())
}'
8. 安全加固建议
8.1 证书文件权限
bash复制find /etc/nginx/certs -type f -name "*.key" -exec chmod 600 {} \;
find /etc/nginx/certs -type d -exec chmod 700 {} \;
chown -R root:nginx /etc/nginx/certs
8.2 TLS协议优化
nginx复制ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384';
ssl_prefer_server_ciphers on;
ssl_ecdh_curve secp384r1;
这套配置方案在某电商平台支撑了日均10亿+请求量,关键点在于将静态配置转化为动态加载机制。实际部署时建议先用10%流量进行灰度测试,特别注意OpenSSL版本对TLS1.3的支持差异。
