1. 为什么需要Nginx多域名多证书配置?
在今天的互联网环境中,一个服务器托管多个网站已经成为标准做法。想象一下,如果你运营着电商平台、博客和技术文档三个不同的服务,为每个服务单独购买服务器不仅成本高昂,管理起来也极其麻烦。这就是Nginx的多域名多证书配置大显身手的地方。
我管理过数十个生产环境中的Nginx服务器,最常见的需求就是在一个IP地址上托管多个域名,每个域名需要自己的SSL证书,并且指向不同的后端服务。这种配置看似简单,但实际操作中有许多细节需要注意,否则很容易踩坑。
提示:虽然现代浏览器支持SNI(Server Name Indication)技术使得单IP多证书成为可能,但某些老旧客户端(如Windows XP上的IE)可能无法正常工作,如果你的用户群体包含这类特殊情况需要特别注意。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 准备工作与环境配置
2.1 基础环境要求
在开始之前,确保你的系统满足以下条件:
- 已安装Nginx(建议1.15.0以上版本)
- 拥有服务器root或sudo权限
- 已申请好域名并做好DNS解析
- 准备好各个域名的SSL证书(包括.crt和.key文件)
我强烈建议使用Certbot来自动化证书申请和管理,特别是对于Let's Encrypt证书。下面是在Ubuntu上安装Certbot的命令:
bash复制sudo apt update
sudo apt install certbot python3-certbot-nginx
2.2 证书文件组织
合理的文件组织结构能极大简化后续管理。我通常采用这样的目录结构:
code复制/etc/nginx/
├── sites-available/
├── sites-enabled/
└── ssl/
├── domain1/
│ ├── fullchain.pem
│ └── privkey.pem
├── domain2/
│ ├── fullchain.pem
│ └── privkey.pem
└── domain3/
├── fullchain.pem
└── privkey.pem
这种结构的好处是:
- 每个域名的证书独立存放,互不干扰
- 文件名统一,便于批量操作
- 与Nginx的标准目录结构保持一致
3. 多域名多证书配置详解
3.1 基础配置模板
下面是一个典型的多域名多证书Nginx配置示例。假设我们有两个域名:example.com和api.example.com,分别指向不同的后端服务。
nginx复制server {
listen 443 ssl;
server_name example.com;
ssl_certificate /etc/nginx/ssl/example.com/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/example.com/privkey.pem;
# SSL优化配置
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384...';
location / {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
server {
listen 443 ssl;
server_name api.example.com;
ssl_certificate /etc/nginx/ssl/api.example.com/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/api.example.com/privkey.pem;
# 可以针对API优化SSL配置
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m;
location / {
proxy_pass http://localhost:8000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
server {
listen 80;
server_name example.com api.example.com;
return 301 https://$host$request_uri;
}
3.2 关键配置解析
-
server_name指令:这是区分不同域名的关键,Nginx会根据HTTP请求中的Host头来匹配对应的server块。
-
SSL证书路径:每个server块需要指定自己独立的证书路径。我遇到过很多问题都是因为证书路径配置错误导致的。
-
HTTP到HTTPS重定向:最后一个server块捕获所有HTTP请求并重定向到HTTPS,这是安全最佳实践。
-
代理设置:不同域名通常需要代理到不同的后端服务,注意proxy_set_header的设置,特别是Host头的传递。
4. 高级配置与优化技巧
4.1 通配符证书与SAN证书的使用
如果你管理大量子域名,为每个子域名单独申请证书会很麻烦。这时可以考虑:
- 通配符证书:如*.example.com,可以匹配所有子域名
- SAN证书:一个证书包含多个域名(Subject Alternative Name)
配置示例:
nginx复制server {
listen 443 ssl;
server_name *.example.com;
ssl_certificate /etc/nginx/ssl/wildcard.example.com/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/wildcard.example.com/privkey.pem;
...
}
注意:通配符证书只能匹配一级子域名,比如*.example.com可以匹配a.example.com但不能匹配a.b.example.com。
4.2 配置复用与模块化
当管理大量相似配置时,可以使用Nginx的include指令来避免重复。例如,创建/etc/nginx/ssl_params文件:
nginx复制ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384...';
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m;
然后在各个server块中引用:
nginx复制server {
...
include /etc/nginx/ssl_params;
...
}
4.3 性能优化建议
-
OCSP Stapling:减少证书验证时间
nginx复制ssl_stapling on; ssl_stapling_verify on; resolver 8.8.8.8 8.8.4.4 valid=300s; resolver_timeout 5s; -
Session Tickets:减少SSL握手开销
nginx复制ssl_session_tickets on; ssl_session_ticket_key /etc/nginx/ssl/ticket.key; -
HTTP/2支持:现代浏览器性能更好
nginx复制listen 443 ssl http2;
5. 常见问题排查与解决
5.1 证书不匹配错误
症状:浏览器显示"证书与域名不匹配"警告。
排查步骤:
- 检查server_name是否与证书的CN或SAN匹配
- 确认证书链完整(特别是中间证书)
- 使用openssl验证:
bash复制
openssl s_client -connect example.com:443 -servername example.com | openssl x509 -noout -text
5.2 配置不生效问题
症状:修改配置后,Nginx似乎没有使用新配置。
解决方法:
- 检查配置语法:
bash复制sudo nginx -t - 确保已正确reload而非restart:
bash复制sudo systemctl reload nginx - 清除浏览器缓存或使用curl测试:
bash复制
curl -v https://example.com
5.3 性能瓶颈分析
当并发连接数高时可能出现性能问题,建议:
- 调整worker进程数:
nginx复制worker_processes auto; - 优化连接处理:
nginx复制events { worker_connections 1024; multi_accept on; } - 监控工具:
bash复制sudo nginx -T # 查看完整配置 sudo ss -lntp | grep nginx # 查看连接状态
6. 实际案例:电商平台配置
假设我们有一个电商平台,需要配置以下服务:
- 主站:www.shop.com
- 管理后台:admin.shop.com
- API服务:api.shop.com
- 静态资源:cdn.shop.com
完整配置示例:
nginx复制# 全局SSL参数
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384...';
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m;
# 主站
server {
listen 443 ssl http2;
server_name www.shop.com;
ssl_certificate /etc/nginx/ssl/shop.com/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/shop.com/privkey.pem;
location / {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
# 管理后台(更严格的安全设置)
server {
listen 443 ssl http2;
server_name admin.shop.com;
ssl_certificate /etc/nginx/ssl/admin.shop.com/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/admin.shop.com/privkey.pem;
# 额外的安全头
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header Content-Security-Policy "default-src 'self'";
location / {
proxy_pass http://localhost:3001;
proxy_set_header Host $host;
# IP限制示例
allow 192.168.1.0/24;
allow 203.0.113.45;
deny all;
}
}
# API服务(优化长连接)
server {
listen 443 ssl http2;
server_name api.shop.com;
ssl_certificate /etc/nginx/ssl/api.shop.com/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/api.shop.com/privkey.pem;
location / {
proxy_pass http://localhost:8000;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_read_timeout 300s;
}
}
# CDN静态资源(缓存优化)
server {
listen 443 ssl http2;
server_name cdn.shop.com;
ssl_certificate /etc/nginx/ssl/cdn.shop.com/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/cdn.shop.com/privkey.pem;
location / {
root /var/www/cdn;
expires 365d;
add_header Cache-Control "public, immutable";
access_log off;
}
}
# HTTP重定向
server {
listen 80;
server_name shop.com www.shop.com admin.shop.com api.shop.com cdn.shop.com;
return 301 https://$host$request_uri;
}
在这个配置中,我根据不同的服务类型采用了不同的优化策略:
- 主站:标准配置
- 管理后台:增加了IP限制和安全头
- API服务:优化了连接管理
- CDN:配置了长期缓存
这种细粒度的配置可以确保每个服务都能获得最佳的性能和安全性。
