squid + stunnel 大法

用户将tcp包发给stunnel client;stunnel client将包加密,发送给stunnel server;stunnel server解密后发送给squid;squid将包中的http请求进行转发,然后再将请求结果返回给stunnel server;stunnel server加密发给stunnel client;stunnel client解密后交回给用户。这样,由于通过GFW的数据是被stunnel加密过的,用户就能放心的“上网”了

这里我们来说几种方案

方案1:墙外服务器部署squid + stunnel server;墙内用户主机部署stunnel client,并将浏览器代理设置为本机上的stunnel client。

这个方案的优点就是节约,只需要一台墙外服务器。缺点是墙内每个用户主机都要装stunnel client,如果只是自己一个人用的话还好,用户多的话就麻烦了。

方案2:墙外服务器部署squid + stunnel server;墙内服务器部署stunnel client;墙内用户主机将浏览器代理设置为墙内的stunnel client服务器。

这个方案的优点就是对用户方便,傻瓜操作,只要修改浏览器代理设置即可使用。缺点就是不节约,需要两台服务器,墙外墙内各一台。

TLS/SSL证书

生成签名证书

openssl req -new -x509 -days 3650 -nodes -out stunnel.pem -keyout stunnel.pem

req指令,用来创建和管理证书请求(Certificate Signing Request, CSR)以让第三方权威机构CA来签发我们需要的证书。也可以使用-x509参数来生成自签名证书。

-new参数,表示新建证书(或证书请求)

-x509参数,表示要生成x.509格式的证书而不是证书请求

-days参数,表示生成的证书的有效时间

-nodes参数,不要加密私钥(如果没有定义这个参数,执行openssl req命令时候会要求输入一个密码,来对要生成的私钥文件进行加密,然后后面stunnel或nginx这些服务器程序要使用这个私钥的时候就会被要求输入密码)

-out参数,要生成的证书(certificate)文件名(如果没有定义-x509参数,生成的就是证书请求certificate request)

-keyout参数,要生成的私钥(private key)文件名(上面使用了跟证书一样的文件名,并不会覆盖该文件,而是追加到一起)

安装配置squid(我这里是centos9)

安装 Squid:

sudo dnf install squid

配置 Squid (squid.conf):

使用 vi /etc/squid/squid.conf 或你喜欢的编辑器打开配置文件。 找到以下几行并修改或添加:

http_access allow all
http_access deny manager
http_port 3128
dns_nameservers 8.8.8.8 1.1.1.1

以上是开放所有互联网链接的配置 我这里不做详细描述

启动 Squid 服务:

sudo systemctl enable --now squid 开机自启动并启动

实时查看squid日志

tail -f /var/log/squid/access.log

查看状态

sudo systemctl status squid

systemctl start/stop/restart/status squid 启动/停止/重启/查看状态

配置防火墙 (firewalld):

sudo firewall-cmd --permanent --add-port=3128/tcp # 将3128替换为你配置的端口
sudo firewall-cmd --reload

或者直接关闭防火墙详细防火墙相关命令参考我另一篇帖子 Firewalld

systemctl stop firewalld

如上就已经简单完成配置 squid了 如果想查看详细的配置 这里推荐一个相关帖子 squid

安装配置stunnel

安装stunnel

sudo dnf install stunnel -y

配置 stunnel服务端(海外服务器)

默认的stunnel配置文件在/etc/stunnel/stunnel.conf。关于更多参数信息,可以参考:

https://www.stunnel.org/static/stunnel.html

; 设置工作目录(没有此目录需要创建)
chroot = /var/run/stunnel/
; 设置stunnel的pid文件路径(在chroot下)
pid = /stunnel.pid
; 设置stunnel工作的用户(组)
setuid = root
setgid = root

; 开启日志等级:emerg (0), alert (1), crit (2), err (3), warning (4), notice (5), info (6), or debug (7)
; 默认为5
debug = 7
; 日志文件路径(我的server的版本有个bug,这个文件也被放在chroot路径下了,client的版本则是独立的=。=#)
output = /stunnel.log

; 证书文件,就是在本文2.2中用openssl生成的自签名证书(server端必须设置这两项)
cert = /etc/stunnel/stunnel.pem
; 私钥文件
key = /etc/stunnel/stunnel.pem

; 设置stunnel服务,可以设置多个服务,监听同的端口,并发给不同的server。
; 自定义服务名squid-proxy
[squid-proxy]
; 服务监听的端口,client要连接这个端口与server通信
accept = 3129
; 服务要连接的端口,连接到squid的3128端口,将数据发给squid
connect = 3128

; **************************************************************************
; * 下面这些配置我都注释掉了,但也需要了解下 *
; **************************************************************************

; 设置是否对传输数据进行压缩,默认不开启。
; 这是跟openssl相关的,如果你的openssl没有zlib,开启这个设置会导致启动失败(failed to initialize compression method)
;compression = zlib

; 设置ssl版本,这个也是跟安装的openssl有关的
;sslVersion = TLSv1

; Authentication stuff needs to be configured to prevent MITM attacks
; It is important to understand that this option was solely designed for access control and not for authorization
; It is not enabled by default!
; 下面这些配置用来定义是否信任对方发过来的证书。就好比浏览器访问https的时候,浏览器默认会信任那些由权威CA机构签发的证书,
; 对于那些自签名证书,浏览器就会弹出对话框提醒用户这个证书可能不安全,是否要信任该证书。
; 这是有效防止中间人攻击的手段
; verify 等级2表示需要验证对方发过来的证书(默认0,不需要验证,都信任)
; 因为这个配置是server端的,我们不需要理会client的证书(client也不会没事发证书过来啦)
;verify = 2
; CAfile 表示受信的证书文件,即如果对方发过来的证书在这个CAfile里,那么就是受信任的证书;否则不信任该证书,断开连接。
;CAfile = /etc/stunnel/stunnel-client.pem

启动stunnel

systemctl enable --now stunnel 开机自启动并启动

systemctl enable stunnel 如果你已经启动可以直接运行

  • enable: 设置 stunnel 服务在系统启动时自动启动。

  • --now: 立即启动 stunnel 服务。

    service stunnel start

service stunnel start/stop/restart/status 启动/停止/重启/查看状态

配置stunnel客户端(方案一:只需一台海外服务器即可)

首先需要安装对应版本的客户端

下载地址为 https://www.stunnel.org/downloads.html

我这里以windowns为例 (stunnel-5.74-win64-installer.exe

下载完成之后编辑配置文件如下

; stunnel工作的用户组
; stunnel工作时候的pid

; 日志等级
debug = 7
; 日志文件
output = D:\stunnel\stunnel.log

; 表示以client模式启动stunnel,默认client = no,即server模式
client = yes

; 定义一个服务
[squid-proxy]
; 监听3128端口,那么用户浏览器的代理设置就是 stunnel-client-ip:3128
accept = 3128
; 要连接到的stunnel server的ip与端口
connect = xxxxx:3129

; 需要验证对方发过来的证书
verify = 2
; 用来进行证书验证的文件(里面有stunnel server的证书)
CAfile = D:\stunnel\stunnel-server.pem

; 客户端不需要传递自己的证书,所以注释掉
;cert = /etc/stunnel/stunnel.pem
;key = /etc/stunnel/stunnel.key

如上方案一就已经实现了

需要再浏览器设置对应代理 我用的是谷歌的插件 Proxy SwitchyOmega

配置上代理服务器为你windowns的ip和端口即可 127.0.0.1 3128

提示:也可以填写你的局域网ip 同理同局域网都可以用 比如在你的电脑上启动成功后,你的局域网ip为xxxx.xxx.xx 可在手机上wifi或者数据里设置代理服务器 填写你的局域网ip和端口即可实现!!非常方便,switch和主机加速同理!

配置stunnel客户端(方案二:需两台服务器一个国内一个海外)

因为我会在client的配置中开启了证书验证,就是对于对方发过来的证书文件,client需要去CAfile中进行匹配,匹配到的证书才是受信证书,才允许建立连接。这样的话,我们就需要把server端的证书拷贝过来。我是直接打开server端的stunnel.pem,然后将里面CERITIFICATE拷贝到client端新建的/etc/stunnel/stunnel-server.pem文件中。

;stunnel工作目录
chroot = /var/run/stunnel/
; stunnel工作的用户组
setuid = root
setgid = root
; stunnel工作时候的pid
pid = /stunnel.pid

; 日志等级
debug = 7
; 日志文件
output = /var/log/stunnel/stunnel.log

; 表示以client模式启动stunnel,默认client = no,即server模式
client = yes

; 定义一个服务
[squid-proxy]
; 监听3128端口,那么用户浏览器的代理设置就是 stunnel-client-ip:3128
accept = 3128
; 要连接到的stunnel server的ip与端口
connect = xx.xx.xx.xx:3129

; 需要验证对方发过来的证书
verify = 2
; 用来进行证书验证的文件(里面有stunnel server的证书)
CAfile = /etc/stunnel/stunnel-server.pem

; 客户端不需要传递自己的证书,所以注释掉
;cert = /etc/stunnel/stunnel.pem
;key = /etc/stunnel/stunnel.key

参考帖子 https://www.hawu.me/operation/886