一、背景 & ngrok功能介绍
自己家中设备(PC、NAS网盘、树莓派等)可能运行了一些接口服务,如遇放假或出远门时又想远程访问到这些服务,需要一些解决方案。
家用网络的公网IP一般是浮动的,之前一直使用的方案是花生壳动态域名服务+路由器公网IP绑定+路由器内网端口映射,方案如下图所示。
DDNS方案缺点还是挺多的,比如要自己找免费的DDNS服务,路由器繁琐的配置等。(但也有优点,比如家里电脑可以关机,远程发一个magic包就可以远程启动自己的电脑,主板开启网卡启动)。随着后来搬家次数增多,以及家里的运营商及自购路由器组网结构越来越复杂,端口映射配置也极为繁琐,慢慢就懒得折腾了,最近又有类似需求,这次换另一种方式来解决这个问题。
新方案采用ngrok Tunnel代理的方案,ngrok是一个开源的穿透工具,提供ngrok-server供服务端部署 和ngrok-client供被代理终端连接,ngrok-server可以部署在用户自己的公网服务器上,没有的话也可以用ngrok官方提供的或第三方提供的免费接入,整体方案如下。
Tunnel本质上就是一条tcp连接,再通过内部约定的具体应用层报文协商代理链路,本文不重点关注ngrok的Tunnel层具体实现。
下图是一个隧道建立和代理过程,我们在自己的pc上部署了若干API接口,现在想在公网上访问到这些本地服务:
- ①:本地pc安装ngrok-client,并配置接入地址到我们的公网ngrokd服务(ngrok.xietiandi.tech:4443);启动后,client会主动发起到server的tcp Tunnel连接;
- ②:client通过此Tunnel连接向server发起请求,指定server侧要为此Tunnel暴露出来的端口,如”Remote-Port:8081 -> current Tunnel”;同时,client内部也要维护此Tunnel接收流量到本机target的映射关系。
- ③:Server端调用socket syscall,listen对应端口,维护该端口和Tunnel的映射关系,并将所有该端口流量转发至该Tunnel。
- ④:公网流量发起请求到ngrokd服务的代理端口,端口流量会被ngrokd代理至ngrok-client,再由ngrok-client代理至本机服务。
二、docker部署运行实践
ngrokd - server侧部署
为了简化部署过程,我们在腾讯云虚机上通过docker对ngrokd(服务端)进行部署,参考自:https://github.com/jueying/docker-ngrok-server。
原文镜像做的已经很好了,但是对一些细节新手容易搞不明白,我将自己做错的步骤额外通过注释进行了说明,具体见后续介绍。
DockerFile如下:
1 | # 指定基础镜像 |
docker entrypoint.sh 如下:
1 | #!/bin/sh -e |
ngrok-client 配置
拷贝配套的client到需要被代理的本地设备上
1
2# 将server配套的client从镜像中cp出来,并scp正确系统版本到自己的pc电脑上
docker cp ngrok-server:/usr/local/ngrok/bin .tcp模式启动client
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19# 新建配置文件 ngrok.cfg
server_addr: "ngrok.xietiandi.tech:4443"
trust_host_root_certs: false
tunnels:
gpt:
remote_port: 8081
proto:
tcp: 6006
# run client
.\ngrok.exe -config="ngrok.cfg" start gpt
# status log
Tunnel Status online
Version 1.7/1.7
Forwarding tcp://ngrok.xietiandi.tech:8081 -> 127.0.0.1:6006
Web Interface 127.0.0.1:4040
# Conn 0
Avg Conn Time 0.00mshttp模式启动client
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15# 新建配置文件 ngrok.cfg
server_addr: "ngrok.xietiandi.tech:4443"
trust_host_root_certs: false
# run client, 6006为本地被代理的端口,server端端口为entrypoint中指定的httpAddr,如果你是docker运行的,需要额外注意host到docker的端口映射
.\ngrok.exe -config="ngrok.cfg" 6006
# status log, http://7e8bc833.ngrok.xietiandi.tech 是ngrokd随机出来的多级域名,需要保证你的dns解析了*.domainName -> public ip
Tunnel Status online
Version 1.7/1.7
Forwarding https://7e8bc833.ngrok.xietiandi.tech -> 127.0.0.1:6006
Forwarding http://7e8bc833.ngrok.xietiandi.tech -> 127.0.0.1:6006
Web Interface 127.0.0.1:4040
# Conn 0
Avg Conn Time 0.00ms
三、效果实测
我本地用有显卡的台式机运行着一个ChatGLM2量化版的接口服务,并运行在6006端口,用postman测试,baseUrl设为 http://127.0.0.1 和 http://ngrok.xietiandi.tech:8081 时均可正常返回结果。