如何搭建一个基于WebSocket的反向隧道

背景

如何利用VPS构建一个反向隧道?

  • 有了一台VPS,但是因为在大陆访问速度慢的原因,所以需要使用CloudFlare加速
  • 我需要在外网访问家里的一些服务,所以需要一个反向tunnel,即能够从外网访问内网服务
  • 问题是,frp等工具都不太好用,一是直接使用容易被流量识别;二是不支持通过CloudFlare加速
  • 还有就是,原本的域名上也有一个博客,所以需要特定path才走tunnel

在上面的限制下,试了好几个工具,最终发现wstunnel能够满足上面的要求。

最终方案画成图就是:

按照图中的方案,我们一步一步搭建。

服务端/VPS

从图中可以看出,在VPS上,我们需要一个nginx,用来:

  1. 正常访问流量走web服务,特定前缀的websocket流量转发给wstunnel-server
  2. wstunnel-server从nginx接收数据,由于是本地访问,所以只需要使用ws协议接收
  3. wstunnel-server需要有一定的认证能力

在原有的nginx配置中,中添加如下location,让所有/wstunnel的流量转发到wstunnel-server:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
location /wstunnel {
if ($http_upgrade = "") {
return 404;
}
proxy_redirect off;
keepalive_timeout 12000s;
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Host $host;
proxy_set_header Connection "upgrade";
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_intercept_errors on;
proxy_pass_request_headers on;
}

然后我们启动wstunnel-server:

1
2
wstunnel server ws://127.0.0.1:8080 \
--restrict-http-upgrade-path-prefix wstunnel-password

其中的--restrict-http-upgrade-path-prefix wstunnel-password表示连接时需要在/wstunnel-password路径下发起连接。

这样配置后,如果其他人不知道这个路径就无法连接,起到一个认证的作用。

客户端

在客户端

  1. 使用wss协议向服务端发送数据
  2. wss发起连接的时候,需要在特定前缀下

那么,使用如下命令,代表在socks5://[::1]:1212启动了一个sock5代理服务,在http://[::1]:8012启动了一个HTTP代理服务:

1
2
3
wstunnel client wss://xxx.net --http-upgrade-path-prefix wstunnel-password \
--local-to-remote socks5://[::1]:1212 \
--local-to-remote http://[::1]:8012

然后我们就可以使用浏览器加SwitchyOmega扩展,来测试下上面的代理服务。

当然,在上面的配置中,我们只能通过这个tunnel访问其他服务,是一个正向的隧道。

不要忘记,我们最终的需求是如何让公网能够访问我们在内网的服务。

比如,我们想要通过VPS的8002端口,来访问本地8001端口上的一个服务,那么命令如下:

1
2
3
wstunnel client wss://xxx.net --http-upgrade-path-prefix wstunnel-password \
--remote-to-local tcp://[::]:8002:localhost:8001 \
--remote-to-local udp://[::]:8002:localhost:8001

这时候,我们怎么验证下这个反向隧道是正常的呢?

启动一个测试服务,验证下

我们在本地的8002端口,启动一个测试Web服务:

1
python3 -m http.server 8002

然后,通过curl访问vpsIP:8001,就能看到测试服务已经可以访问了:

1
2
3
4
5
6
7
8
9
$ curl http://ipip:8002/ -i
HTTP/1.0 200 OK
Server: SimpleHTTP/0.6 Python/3.13.0
Date: Tue, 03 Dec 2024 08:40:52 GMT
Content-type: text/html; charset=utf-8
Content-Length: 1062

<!DOCTYPE HTML>
...

如何搭建一个基于WebSocket的反向隧道

https://robberphex.com/how-to-build-tunnel-over-websocket/

作者

Robert Lu

发布于

2024-12-03

许可协议

评论