插件窝 干货文章 Nginx反向代理中基于SNI的SSL解决方案

Nginx反向代理中基于SNI的SSL解决方案

SSL Server certificate domain 911    来源:    2025-04-20

Nginx反向代理中基于SNI的SSL解决方案

SNI (Server Name Indication) 是TLS协议的扩展,允许客户端在SSL握手阶段就指明要连接的主机名,使得服务器能够为不同的域名提供不同的SSL证书。这在Nginx反向代理环境中非常有用,特别是当你需要代理多个HTTPS服务时。

基本SNI配置

在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;
    }
}

高级配置选项

1. 默认SSL证书

当请求的主机名不匹配任何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;  # 关闭连接
}

2. SSL优化参数

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;

3. 动态证书加载

对于大量域名的情况,可以使用动态证书加载:

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;
        # 其他代理设置...
    }
}

常见问题解决方案

1. 旧客户端不支持SNI

对于不支持SNI的旧客户端(如IE6/7/8 on Windows XP, Android 2.x等): - 为这些客户端配置一个默认的server块 - 考虑是否真的需要支持这些老旧客户端

2. 证书验证问题

确保: - 证书链完整 - 证书与域名匹配 - 证书未过期 - 私钥与证书匹配

3. 性能优化

对于大量HTTPS站点: - 使用OCSP Stapling减少证书验证时间 - 启用SSL session缓存 - 考虑使用TLS 1.3减少握手时间

4. 调试技巧

检查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证书,同时保持高性能和安全性。