SNI (Server Name Indication) 是TLS协议的扩展,允许客户端在SSL握手阶段就指明要连接的主机名,使得服务器能够为不同的域名提供不同的SSL证书。这在Nginx反向代理环境中非常有用,特别是当你需要代理多个HTTPS服务时。
在Nginx中配置基于SNI的SSL反向代理非常简单:
server {
listen 443 ssl;
server_name domain1.com;
ssl_certificate /path/to/domain1.crt;
ssl_certificate_key /path/to/domain1.key;
location / {
proxy_pass https://backend1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
server {
listen 443 ssl;
server_name domain2.com;
ssl_certificate /path/to/domain2.crt;
ssl_certificate_key /path/to/domain2.key;
location / {
proxy_pass https://backend2;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
当请求的主机名不匹配任何server_name时,Nginx会使用默认证书(配置文件中第一个定义的证书):
server {
listen 443 ssl default_server;
server_name _;
ssl_certificate /path/to/default.crt;
ssl_certificate_key /path/to/default.key;
return 444; # 关闭连接
}
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256...';
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets off;
对于大量域名的情况,可以使用动态证书加载:
server {
listen 443 ssl;
server_name ~^(?<domain>.+)$;
ssl_certificate /etc/nginx/certs/$domain.crt;
ssl_certificate_key /etc/nginx/certs/$domain.key;
# 如果证书不存在则使用默认证书
if (!-f $ssl_certificate) {
set $domain "default";
}
location / {
proxy_pass https://backend_$domain;
# 其他代理设置...
}
}
对于不支持SNI的旧客户端(如IE6/7/8 on Windows XP, Android 2.x等): - 为这些客户端配置一个默认的server块 - 考虑是否真的需要支持这些老旧客户端
确保: - 证书链完整 - 证书与域名匹配 - 证书未过期 - 私钥与证书匹配
对于大量HTTPS站点: - 使用OCSP Stapling减少证书验证时间 - 启用SSL session缓存 - 考虑使用TLS 1.3减少握手时间
检查SNI是否正常工作:
openssl s_client -connect your.server:443 -servername domain.com -tlsextdebug
查看Nginx错误日志:
tail -f /var/log/nginx/error.log
# 全局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:SSL:50m;
ssl_session_tickets off;
# 默认服务器
server {
listen 443 ssl default_server;
server_name _;
ssl_certificate /etc/nginx/ssl/default.crt;
ssl_certificate_key /etc/nginx/ssl/default.key;
return 444;
}
# 域名1
server {
listen 443 ssl;
server_name domain1.com www.domain1.com;
ssl_certificate /etc/nginx/ssl/domain1.com.crt;
ssl_certificate_key /etc/nginx/ssl/domain1.com.key;
# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/nginx/ssl/domain1.com.chain.crt;
location / {
proxy_pass https://backend1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
# 域名2
server {
listen 443 ssl;
server_name domain2.com;
ssl_certificate /etc/nginx/ssl/domain2.com.crt;
ssl_certificate_key /etc/nginx/ssl/domain2.com.key;
location / {
proxy_pass https://backend2;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
通过以上配置,Nginx可以有效地作为反向代理处理多个HTTPS站点,每个站点使用自己的SSL证书,同时保持高性能和安全性。