Total Pageviews

Sunday, 11 November 2018

用Nginx+gsproxy搭建HTTPS Proxy,进行翻墙(亲测有效)

HTTPS Proxy 是指普通HTTP Proxy经过TLS加密,Chrome 和 Firefox可直连的代理,也称作HTTP over SSL Proxy。优点是无需独立客户端程序,浏览器内置支持,轻量级,支持PAC配置。缺点是服务端配置复杂,客户端只能在浏览器上使用,或者使用MEOW 或 Stunnel 去掉SSL 加密当作普通HTTP 代理。现在已经有商用的代理使用这种方案。
原理就是后端一个普通的HTTP 代理,Squid 或gsproxy(详见https://briteming.blogspot.com/2018/06/gohttp-gsproxy.html)都可以(不建议搭配tinyproxy使用,因为tinyproxy不正常),然后用nghttpx 或Nginx 进行反向代理和TLS加密。麻烦点在于证书的申请和配置.
这里使用Nginx 和gsproxy 的组合进行配置。系统使用debian/ubuntu或centos最新版,安装系统默认的软件包。

先编译nginx:

wget http://nginx.org/download/nginx-1.27.2.tar.gz
tar zxvf nginx-1.27.2.tar.gz
cd nginx-1.27.2
./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_v2_module --with-http_dav_module --with-http_flv_module --with-http_realip_module --with-http_gzip_static_module --with-http_stub_status_module --with-mail --with-mail_ssl_module --with-http_mp4_module --with-stream --with-stream_ssl_module 
make && make install
其中 --with-stream --with-stream_ssl_module 是必须的.

(参考https://nginx.org/en/docs/configure.html,nginx的编译参数
nginx的源码包的下载地址:https://nginx.org/en/download.html)

root@whme:~# cd /usr/local/nginx
root@whme:/usr/local/nginx# ls
conf  logs            
html  sbin                     
root@whme:/usr/local/nginx# cd sbin
root@whme:/usr/local/nginx/sbin# ls
nginx
root@whme:/usr/local/nginx/sbin# echo 'export PATH=$PATH:/usr/local/nginx/sbin' >> /etc/profile && source /etc/profile
root@whme:/usr/local/nginx/sbin#
nginx编译完成。

然后/usr/local/nginx/conf/nginx.conf文件的http段的上方加入如下的配置片段:
stream {
        upstream http_proxy {
                server 127.0.0.1:9090;
        }
server {
listen 8443 ssl;
ssl_session_cache shared:proxy_nginx_SSL:1m;
ssl_session_timeout 1440m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;

ssl_ciphers "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384";
ssl_certificate /root/.acme.sh/yourdomain.com/fullchain.cer;
ssl_certificate_key /root/.acme.sh/yourdomain.com/yourdomain.com.key;
proxy_pass http_proxy;
}
}

其中,证书使用Let't Encrypt的免费证书,在此感谢Let't Encrypt的卓越服务。用acme.sh安装letsencrypt的免费SSL证书,见此文https://briteming.blogspot.com/2018/10/acmeshletsencryptssl.html

然后启动nginx:

nginx

接下来安装gsproxy:
详见https://briteming.blogspot.com/2018/06/gohttp-gsproxy.html

然后在本地机器的chrome里设置https proxy为yourdomain.com,端口:8443,用chrome就能翻墙了。


HTTPS Proxy基本上可用了,你可以到此为止。

如果你使用的http proxy不支持用户认证,也就是说proxy authorization 不能使用。那么可以使用SSL的双向认证,在Nginx上设置ssl_verify_client on。在 server 段中加入以下配置:
ssl_client_certificate /etc/nginx/certs/client.crt;
ssl_verify_client on
12
客户端证书与网站证书不同,可以使用Easy-RSA 自己申请和管理,不需要第三方认证,client.crt 就是自己生成的Root CA。
客户端使用CA签发的证书与服务器连接,没有证书无法连接,Chrome 支持使用 AutoSelectCertificateForUrls 策略自动选证书。
 ./easyrsa init-pki
 ./easyrsa build-ca
 ./easyrsa gen-req proxy.example.name
 ./easyrsa sign-req client proxy.example.name
1234
以上命令会询问CN,即你的域名。基本上Root CA即执行init-pki 时填写example.com,gen-req 时填写一个子域名,proxy.example.com。example.com 根据需要替换。
这时生成了pki 文件夹,里面要用的文件是pki/ca.crt,把内容写入/etc/nginx/certs/client.crt:
cat pki/ca.crt > /etc/nginx/certs/client.crt
接下来要把proxy.example.com 的证书转换为Chrome 可识别的p12 格式:
openssl pkcs12 -export -clcerts -in pki/issued/proxy.example.com.crt -inkey pki/privae/proxy.example.com.key -out proxy.example.com.p12
执行完会生成proxy.example.com.p12 文件,可以导入Chrome 使用,Linux 下进入 chrome://settings/certificates 执行导入,Windows 下双击打开,导入系统,Chrome 使用系统的证书管理程序。
客户端证书认证必须配合AutoSelectCertificateForUrls, Chrome 不会主动提示代理需要选择证书。
Linux 下创建/etc/opt/chrome/policies/managed/policies.json 文件,写入以下内容:
{
  "AutoSelectCertificateForUrls": ["{\"pattern\":\"https://proxy.example.com\",\"filter\":{\"ISSUER\":{\"CN\":\"example.com\"}}}"]
}
123
Windows 下导入以下注册表:
Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Google\Chrome\AutoSelectCertificateForUrls]
"1"="{\"pattern\":\"https://proxy.example.com\",\"filter\":{\"ISSUER\":{\"CN\":\"example.com\"}}}"
1234
chrome://policy/ 应该会出现对应的值。
如果以上步骤完成,那么使用SwitchyOmega 配置一个 HTTPS 代理, 服务器填写 proxy.example.com, 端口 8443,访问 https://httpbin.org/ip 应该能得到服务器IP。
以上就是所有步骤,增加客户端可以使用相同的证书进行导入,也可以使用Easy-RSA申请新的证书,只需执行gen-req和sign-req即可。不要忘记导入AutoSelectCertificateForUrls 的配置,查看chrome://policy/ 检查配置是否生效。
以上完成了HTTP1.1 over TLS 代理,这在大部分情况下工作良好,只是在高延迟的网络条件下有点慢.

参考文档:
Easy-RSA - Github
Easy-RSA - ArchWiki
带你使用Nginx实现HTTPS双向验证
AutoSelectCertificateForUrls
------------------------------------------

仅使用Nginx实现HTTPS PROXY

需要插件 ngx_http_proxy_connect_module 支持,且需要 auth_basic 作为访问认证,但由于 auth_basic 模块只能处理 Authorization header,所以还要加入 lua-nginx-module 来处理 Proxy-Authorization header 认证。

简单点讲就是需要 nginx 加入 ngx_http_proxy_connect_module 和 lua-nginx-module 两个插件,来处理正向代理和认证。

下面服务端以 Debian10 来示范一下编译、安装过程。

开始之前,先安装一下依赖工具:

apt update -y

apt install -y build-essential libtool libpcre3 libpcre3-dev zlib1g-dev openssl libssl-dev wget git

ngx_http_proxy_connect_module插件

这个插件,就是用来处理 HTTPS 正向代理的,项目地址:

https://github.com/chobits/ngx_http_proxy_connect_module

下载插件,以下俺未标记目录的,默认就是 root 目录:

git clone https://github.com/chobits/ngx_http_proxy_connect_module.git

lua-nginx-module插件

需要先安装LuaJIT,并依赖ngx_devel_kit,如下:

安装LuaJIT

LuaJIT官网:http://luajit.org/

1
2
3
4
5
#下载
wget http://luajit.org/download/LuaJIT-2.0.5.tar.gz -O – | tar -xz
#编译
cd LuaJIT-2.0.5
make install PREFIX=/usr/local/LuaJIT

安装完成后会显示:

==== Successfully installed LuaJIT 2.0.5 to /usr/local/LuaJIT ====

设置环境变量:

vi /etc/profile

添加变量:

1
2
export LUAJIT_LIB=/usr/local/LuaJIT/lib
export LUAJIT_INC=/usr/local/LuaJIT/include/luajit-2.0

最后:source /etc/profile

下载ngx_devel_kit

项目地址:https://github.com/simplresty/ngx_devel_kit

回到 root 目录,下面下载的文件都在 root 目录:

cd ..

只需要下载就好了,不需要安装:

git clone https://github.com/vision5/ngx_devel_kit.git

下载lua-nginx-module

项目地址:https://github.com/openresty/lua-nginx-module

只需要下载就好了,不需要安装:

git clone https://github.com/openresty/lua-nginx-module.git

下载lua-resty-core

项目地址:https://github.com/openresty/lua-resty-core

只需要下载就好了,稍后安装:

git clone https://github.com/openresty/lua-resty-core.git

下载lua-resty-lrucache

项目地址:https://github.com/openresty/lua-resty-lrucache

只需要下载就好了,稍后安装:

git clone https://github.com/openresty/lua-resty-lrucache.git

编译Nginx

这次来下载 openresty 版的 Nginx 来编译:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
wget https://openresty.org/download/nginx-1.19.3.tar.gz -O – | tar -xz

cd nginx-1.19.3/

patch -p1 < /root/ngx_http_proxy_connect_module/patch/proxy_connect_rewrite_1018.patch

./configure –prefix=/etc/nginx \
–sbin-path=/usr/sbin/nginx \
–modules-path=/usr/lib/nginx/modules \
–conf-path=/etc/nginx/nginx.conf \
–error-log-path=/var/log/nginx/error.log \
–http-log-path=/var/log/nginx/access.log \
–pid-path=/var/run/nginx.pid \
–lock-path=/var/run/nginx.lock \
–with-http_v2_module \
–with-http_ssl_module \
–with-http_gzip_static_module \
–with-http_stub_status_module \
–with-http_sub_module \
–with-stream \
–with-stream_ssl_module \
–with-pcre \
–add-module=/root/ngx_http_proxy_connect_module \
–with-ld-opt=-Wl,-rpath,/usr/local/LuaJIT/lib \
–add-module=/root/ngx_devel_kit \
–add-module=/root/lua-nginx-module

make
make install

上面 nginx 就算编译完成了,再来安装一下 lua-resty-core 和 lua-resty-lrucache 依赖:

1
2
3
4
5
6
7
8
cd ..
cd lua-resty-core
make install PREFIX=/opt/nginx

cd ..
cd lua-resty-lrucache
make install PREFIX=/opt/nginx

最后把 path 引用加入 nginx 配置文件就好了,下面配置文件已添加:

lua_package_path "/opt/nginx/lib/lua/?.lua;;";

Nginx配置文件

在写 nginx 配置文件之前,俺们先配置一下Basic Auth用户和密码。

配置Basic Auth

1
2
3
4
5
6
7
8
9
10
11
12
13
mkdir /etc/nginx/conf.d

cd /etc/nginx/conf.d

#用 openssl 生成密码为12345,或者别的密码

openssl passwd 12345

#会输出一串密钥
fIHcRVEKijgoM

#然后把密钥写入 htpasswd 文件,其中 admin 为用户名
echo “admin:fIHcRVEKijgoM” > htpasswd

这个用户名和密码,后面连接代理的时候会用到。

407标头和传输检查

vi /etc/nginx/conf.d/proxy_auth.lua

添加如下内容:

1
2
3
4
5
6
7
8
— check Proxy-Authorization for https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/407
if not ngx.var.http_proxy_authorization then
ngx.header[“Proxy-Authenticate”] = “Basic realm=\”Access to internal site\””
ngx.exit(407)
end

— transfer Proxy-Authorization header to Authorization for auth basic module
ngx.req.set_header(“Authorization”, ngx.var.http_proxy_authorization)

nginx.conf配置文件

vi /etc/nginx/nginx.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
pid /var/run/nginx.pid;
worker_processes auto;
worker_rlimit_nofile 51200;
events {
worker_connections 1024;
multi_accept on;
use epoll;
}

http {
server_tokens off;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 120s;
keepalive_requests 10000;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
lua_package_path “/opt/nginx/lib/lua/?.lua;;”;
access_log off;
error_log /dev/null;

server {
listen 3128 ssl;
server_name xxxx.com;

ssl_certificate_key /etc/letsencrypt/live/xxxx.com/privkey.pem;
ssl_certificate /etc/letsencrypt/live/xxxx.com/fullchain.pem;
ssl_session_cache shared:SSL:1m;

auth_basic “Hello, World!”;
auth_basic_user_file /etc/nginx/conf.d/htpasswd;

resolver 8.8.8.8;

rewrite_by_lua_file /etc/nginx/conf.d/proxy_auth.lua;


proxy_connect;
proxy_connect_allow all;
proxy_connect_connect_timeout 10s;
proxy_connect_data_timeout 10s;

location / {
proxy_pass http://$host;
proxy_set_header Host $host;
proxy_hide_header Authorization;
proxy_hide_header Proxy-Authorization;
}
}
}

申请域名证书

首先还是要到 DNS 上添加一个 A 记录,这个就不赘述了。然后申请证书如下:

安装certbot:

apt install certbot -y

certbot申请证书:

certbot certonly --standalone --email youmail@mail.com -d xxxx.com

运行完成后,会生成类似下面路径的证书,这个路径已经添加到nginx配置文件里面了,你只需要修改下域名:

1
2
/etc/letsencrypt/live/xxxx.com/fullchain.pem #证书公钥,xxxx.com是你的域名
/etc/letsencrypt/live/xxxx.com/privkey.pem #证书私钥

启动Nginx

首先还是要写个 systemd 守护进程:

vi /lib/systemd/system/nginx.service

添加内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[Unit]
Description=The NGINX HTTP and reverse proxy server
After=syslog.target network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target

[Service]
Type=forking
PIDFile=/var/run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t
ExecStart=/usr/sbin/nginx
ExecReload=/usr/sbin/nginx -s reload
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true

[Install]
WantedBy=multi-user.target

重载服务:systemctl daemon-reload

然后就可以启动Nginx了:

systemctl start nginx

Nginx的常用命令

systemctl enable nginx #设置开机自动启动

systemctl status nginx #查看运行状态,显示running表示成功运行

systemctl reload nginx #重新载入

systemctl restart nginx #重新启动

客户端使用

电脑端浏览器安装 SwitchyOmega 插件,新建一个代理情景模式,代理协议选择HTTPS,代理服务器填写你的域名,端口填写nginx监听的端口,如上 nginx 配置端口就填写3128,最后点击右边小锁,填写你的用户名(admin)和密码(12345)就可以使用了。

移动端,俺们以小火箭和 Quantumult X 为例,小火箭,选择 HTTPS 代理,服务器填写你的域名,端口3128。

Quantumult X 配置文件/编辑/server_local字头下填写:

http=xxxx.com:3128, username=用户名, password=密码, over-tls=true, tls-host=xxxx.com, fast-open=false, udp-relay=false, tag=NGINX

最后推荐几个移动端支持https代理的软件,iOS:Quantumult X ,小火箭, Android:Clash ,Surfboard.

-----------------------

相关帖子:https://briteming.blogspot.com/2018/07/https.html