一台服务器上同时要跑网站和 TLS 代理时,会遇到一个很现实的问题:443 端口只有一个,TCP 层面同一个端口只能被一个进程绑定。下面小结两种常见的共存思路。
让代理程序自己监听 443 并持有 TLS 证书。它在完成 TLS 握手后检查对端发来的第一段数据:如果是合法的代理协议且认证通过,就走代理;否则把这条连接原样转发给本机真正的 Web 服务。
"ssl": {
"cert": "/etc/xxx/cert.pem",
"key": "/etc/xxx/private.key",
"sni": "example.com",
"fallback_addr": "127.0.0.1",
"fallback_port": 80
}
这样浏览器或主动探测者访问 https://example.com/ 时,看到的是一个证书有效、内容正常的真实网站;真正的客户端带正确口令连接时则走代理通道。
关键点:443 的监听者始终只有代理程序一个,Nginx 并不直接监听公网 443,它只是背后的「伪装网站」。
另一种做法是让 Nginx 占 443,但不解密流量,而是在 ClientHello 里读取明文 SNI(域名),按域名做四层转发:
stream {
map $ssl_preread_server_name $upstream {
proxy.example.com trojan_backend;
default web_backend;
}
server {
listen 443;
ssl_preread on;
proxy_pass $upstream;
}
}
优点是多个 HTTPS 站点和代理可共用一个 443、各持各的证书;代价是配置更复杂,且分流只依据 SNI。
改完后建议从外部验证三件事:curl https://域名/ 能返回正常网页、证书链有效、代理端口仍可正常使用。用 ss -tlnp 确认 443 的监听者到底是谁,可以避免「以为两个程序都在用 443」的误解。
— 本文为个人运维笔记,如有疏漏欢迎指正。