VLESS 与多域名 Nginx 站点共存的 SNI 分流配置方案
最近开始白嫖公司的香港云服务器了,与之前自购的美国 VPS 对比测试下来无论是在网络延时、稳定性还是性能都有了比较大的改善。秉承资源利用最大化的原则,这台服务器的流量不能仅用于访问 Google,所以干脆把之前托管在 Github Pages 上的博客(其实是 Student Pack 到期之后,免费用户的私有项目用不了 GitHub Pages),以及自己搞的一些奇奇怪怪的网站也都迁移了过来(原来跑在腾讯云 1Mbps 的境内服务器上,SSL 握手时间都能让人抓狂)。
明确需求
- 访问 Google 要保证安全且快,这里选择 VLESS 方案
- 需要同时兼容多域名站点,这里有几个方案可选:单证书多域名 + VLESS 回落,前置 Nginx 分流,前置 HAProxy 分流
VLESS 回落方案
由于 VLESS 本身不支持根据 SNI 来分流,需要支持多域名就需要签在同一张证书上。Let's Encrypt 已经对泛域名证书有了比较完美的支持,配合 acme.sh 很容易实现单证书多域名(我所有的域名都在 Cloudflare 下解析)
然后这仍然有些一些问题,VLESS fallback 方案对 Typecho 的支持并不好(翻了一下其他博文,对 WordPress 之类的 php 程序支持也不行),所以无奈放弃这种方案(其实我也不太想将 VLESS 作为前置的 TCP 分流器)。于是开始尝试 Nginx 前置分流方案
Nginx 前置分流
借助 Nginx 的 ssl_preread 模块来实现 SNI,配置起来也很简单。
nginx.conf
里面增加 stream 块:
stream {
map $ssl_preread_server_name $backend_name {
v2.example.com vless;
default web;
}
upstream web {
server 127.0.0.1:8443;
}
upstream vless {
server 127.0.0.1:10443;
}
server {
listen 443 reuseport;
proxy_pass $backend_name;
ssl_preread on;
}
}
conf.d/web.conf
里增加对上述 web 端口的监听即可:
server {
listen 8443 ssl;
server_name web1.example.com;
root /home/www/web1;
ssl_certificate /home/ssl/cert.pem;
ssl_certificate_key /home/ssl/key.pem;
}
server {
listen 8443 ssl;
server_name web2.example.com;
root /home/www/web2;
ssl_certificate /home/ssl/cert.pem;
ssl_certificate_key /home/ssl/key.pem;
}
其实这种方案本来也没什么问题,我开始也觉得可以就这样了。之后无意间发现博客后台记录的一些 client_ip 是 127.0.0.1,于是乎又不得不折腾 HAProxy 方案来分流
HAProxy 前置分流
HAProxy 相较于 ngx_stream_ssl_preread_module 的优点就是可以为每一个不同的 backend 设置不一样的数据传递方式,正是因为 nginx 做不到这一点所以上一个方案才会被 pass 掉
正巧 Proxy Protocol 就是用来做这个事情的,正巧 HAProxy 和 Nginx 对这个的支持都不错。相比而言 HAProxy 的配置文件 haproxy.cfg
显得就比较简单一点:
global
log /dev/log local0
log /dev/log local1 notice
chroot /var/lib/haproxy
user haproxy
group haproxy
daemon
defaults
log global
mode tcp
option tcplog
option dontlognull
timeout connect 24h
timeout client 24h
timeout server 24h
frontend ssl
mode tcp
bind *:443
tcp-request inspect-delay 3s
tcp-request content accept if { req.ssl_hello_type 1 }
use_backend vless if { req_ssl_sni -i v2.example.com }
default_backend nginx
backend nginx
mode tcp
server nginx 127.0.0.1:8443 send-proxy
backend vless
mode tcp
server vless 127.0.0.1:10443
同样的对应 Nginx 站点配置 conf.d/web.conf
也需要加上对 Proxy Protocol 的支持:
server {
listen 8443 ssl proxy_protocol;
server_name web1.example.com;
root /home/www/web1;
set_real_ip_from 127.0.0.1;
real_ip_header proxy_protocol;
ssl_certificate /home/ssl/cert.pem;
ssl_certificate_key /home/ssl/key.pem;
}
server {
listen 8443 ssl proxy_protocol;
server_name web2.example.com;
root /home/www/web2;
set_real_ip_from 127.0.0.1;
real_ip_header proxy_protocol;
ssl_certificate /home/ssl/cert.pem;
ssl_certificate_key /home/ssl/key.pem;
}
一些提示
- 部分软件的安装方式和文档基本都可以在 https://github.com/v2fly 找到
- 需要做 http 跳 https 的话直接 Nginx 监听 80 跳
https://$server_name$request_uri
即可 - 因为 Nginx 的跳转是默认使用的是绝对地址,上述配置存在
https://web1.example.com/path
跳https://web1.example.com:8443/path/
的情况,需要使用absolute_redirect off
设置为相对地址的跳转
大佬tql,学习一下
orz