使用 Nginx Stream 模块来实现 sniproxy
之前写过一篇使用 sniproxy 这个软件来实现免证书代理 https 网站用来做到对某些资源加速访问的作用,不过现在这个项目已经不更新了,不过好在 nginx 通过 stream 模块也能支持同样的功能,这里来介绍下使用方式。
nginx 启用相应模块
我这里的 nginx 使用 docker 方式来部署,其他方式部署的也类似,这里对 nginx 有些要求,需要编译时包含 –with-stream –with-stream_ssl_preread_module –with-stream_ssl_module,可以使用 nginx -V 命令来查看编译时是否包含,我这里使用 nginx:alpine 镜像,已经默认包含了这些模块。
部署 nginx (docker)
docker
docker run -d --name nginx-sniproxy -p 443:443 --restart always -v $(pwd)/nginx.conf:/etc/nginx/nginx.conf nginx:alpinedocker-compose
version: '3.7'
services:
nginx-sniproxy:
image: nginx:alpine
container_name: nginx-sniproxy
ports:
- "443:443"
restart: always
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf还需要在当前目录放一个 nginx.conf,这个配置下文会介绍。
配置文件
代理所有域名
worker_processes 1;
events {
worker_connections 1024;
}
stream {
server {
listen 443;
resolver 1.1.1.1;
ssl_preread on;
proxy_pass $ssl_preread_server_name:443;
}
}这个配置表示允许代理所有域名,也允许任何 IP 访问,这是不安全的,可能被别人
白嫖你的服务。
代理指定域名
worker_processes 1;
events {
worker_connections 1024;
}
stream {
map $ssl_preread_server_name $filtered_sni_name {
~^(.*fast\.com)$ $ssl_preread_server_name;
default "127.255.255.255";
}
server {
resolver 1.1.1.1;
listen 443;
proxy_pass $filtered_sni_name:443; # 由于这里上面没有指定端口,这里要指定为 443
ssl_preread on;
}
}这里增加了一组 map,根据规则过滤 $ssl_preread_server_name(也就是请求的 SNI),上面的配置表示允许 fast.com 这个域名使用,然后指向 $ssl_preread_server_name,如果没有匹配到任何规则,则默认为一个本地回环地址,用于访问了未被允许的域名时,返回空。
如果希望和 https 服务共存,可以让 https 使用一个其他端口,如 1443,然后 defualt 改为 127.0.0.1:1443。
限制只允许指定 ip 使用
还可以限制指定 ip 使用该服务,在 server 代码块中增加:
server {
resolver 1.1.1.1;
listen 443;
proxy_pass $filtered_sni_name:443; # 由于这里上面没有指定端口,这里要指定为 443
ssl_preread on;
deny 192.168.1.2;
allow 192.168.1.1/24;
deny all;
}规则从上到下执行,如果有 deny 匹配,则后面所有的 allow 都将无效,上面这个配置的意思是只允许 192.168.1.1/24 这个网段访问,但不包含 192.168.1.2 这个 ip。
扩展-负载均衡
worker_processes 1;
events {
worker_connections 1024;
}
stream {
map $ssl_preread_server_name $filtered_sni_name {
fast.com backend_example;
}
upstream backend_example {
server fast1.com:443;
server fast2.com:443;
}
server {
resolver 1.1.1.1;
listen 443;
proxy_pass $filtered_sni_name;
ssl_preread on;
}
}map 的 value 中不止可以写根据 $ssl_preread_server_name 获取到的 SNI,还可以指定一个 upstream,里面可以写多个地址,进行负载均衡。
还可以指定负载均衡策略:
- 最少连接负载均衡
upstream myapp1 {
least_conn;
server srv1.example.com;
server srv2.example.com;
server srv3.example.com;
}- 会话持久化(hash)
upstream myapp1 {
ip_hash;
server srv1.example.com;
server srv2.example.com;
server srv3.example.com;
}- 指定权重
upstream myapp1 {
server srv1.example.com weight=3;
server srv2.example.com;
server srv3.example.com;
}