🫥

SNI

在 TCP 握手时, 本机和服务器 IP 之间建立联系, 如果是 HTTPS, 则需要增加验证证书的步骤.

很多情况下会有多个域名绑定了同一个服务器 IP, 如果是普通的 HTTP, 在 nginx 可以这样配置:

server {
  listen 80;
  server_name example.com www.example.com;
  root /var/www/example.com;
  # OTHER CONFIG
}

或者:

http {
    # server 1
    server {
        listen       80;
        server_name  domain1.com;
        location / {
            proxy_pass http://localhost:8000;
        }
    }
    # server 2
    server {
        listen       80;
        server_name  domain2.com;
        location / {
            proxy_pass http://localhost:8001;
        }
    }
    # server 3
    server {
        listen       80;
        server_name  domain3.com;
        location / {
            proxy_pass http://localhost:8002;
        }
    }
    # default server
    server {
        listen       80 default_server;
        server_name  _;
        return       404;
    }
}

但是如果是 HTTPS, 需要在握手时候验证证书, 所以在握手时候需要将域名告诉对方, 找到匹配的证书, 这就是 SNI 的工作. 否则会导致证书找不到而请求失败.

默认情况下, nginx 并不会开启 proxy_ssl_server_name, 也就是说不启用 SNI. 如果使用 nginx 反代一个虚拟主机的服务, 比如 Cloudflare Workers, 此时如果不开启 SNI, 会导致与 CF 握手时候, CF 并不清楚请求哪一个域名下的服务, 所以找不到匹配的证书, 因此会报 502 错误. 当然也可以使用 proxy_ssl_name 字段复写于最终服务器收到的域名.

既然讲到这, 就顺便提一下 proxy_ssl_verifyproxy_ssl_trusted_certificate 字段, 默认情况下, nginx 是不会验证反代的 https 证书的, 也就是 proxy_ssl_verifyoff, 如果打开此字段, 就会验证此证书的合法性. 如果指定了 proxy_ssl_trusted_certificate 字段, 就会与反代服务器返回的证书与这里填写的证书做对比, 来确定该 SSL 证书是否匹配. 如果 SSL 证书与根证书相符,则连接将被允许并将请求转发给被代理服务器;否则,连接将被拒绝(返回 502 错误).

参考


在我们一生中,命运赐予我们每个人三个导师,三个朋友,三名敌人,三个挚爱。但这十二人总是不以真面目示人,总要等到我们爱上他们、离开他们、或与他们对抗时,才能知道他们是其中哪种角色。