最近新买了一台服务器放在家里跑各种杂七杂八的服务,需整一个内网穿透的服务通过外网也能远程登录服务器。很久之前就听闻 ngrok 能实现,于是乎自己也整了一遍。这篇文章记录服务端到客户端部署的全过程,备忘。
首先得有一台外网能够访问的 vps 用以部署 ngrok 的服务端、及一个用以解析自搭建 ngrok 服务的域名。
创建证书
ngrok 的隧道采用 TSL 传输数据,如果使用默认证书的话任何人都可以连接你搭建的 ngrok 服务,在这里你可以去买,不过还是推荐自己生成证书。
export NGROK_DOMAIN="ngrok.xxx.com"
openssl genrsa -out base.key 2048
openssl req -new -x509 -nodes -key base.key -days 10000 -subj "/CN=$NGROK_DOMAIN" -out base.pem
openssl genrsa -out server.key 2048
openssl req -new -key server.key -subj "/CN=$NGROK_DOMAIN" -out server.csr
openssl x509 -req -in server.csr -CA base.pem -CAkey base.key -CAcreateserial -days 10000 -out server.crt
执行上述文件会生成 6 个文件,server.key, server.crt, base.pem 这三个才是我们需要用到的,覆盖 ngrok 默认证书
cp server.key assets/server/tls/snakeoil.key
cp server.crt assets/server/tls/snakeoil.crt
cp base.pem assets/client/tls/ngrokroot.crt
编译 ngrok 服务端和客户端
编译需要 Golang 环境,获取 ngrok 源码: git clone https://github.com/inconshreveable/ngrok.git
ngrok 默认监听 IPv6 端口,我大清自有国情,我们需要源码两处
-
src/ngrok/server/tunnel.go
文件中 net.ListenTCP 后面的 tcp 改为 tcp4 -
src/ngrok/conn/conn.go
文件中 net.Listen 后面的 tcp 改为 tcp4
接下来就是编译,我们需要查看将要部署 ngrok 服务的服务端和客户端 ARCH 信息以便进行跨平台编译,使用命令:
// 这里是我机器的信息,你需要根据你机器得到的信息使用对用的编译指令
dpkg --print-architecture
amd64 // 将要部署 ngrok 服务端的 vps 服务器 arch 信息
i386 // 将要部署 ngrok 客户端的内网服务器
Go (Golang) GOOS and GOARCH
cd 到 ngrok 源码的目录准备编译:
// 服务端
GOOS=linux GOARCH=amd64 make release-server
// 客户端
GOOS=linux GOARCH=386 make release-client
编译得到的可执行文件在 bin 目录下,然后我们使用 scp 命令或 async 命令把编译后得到的文件拷贝到 vps 和内网服务器上:
scp bin/linux_amd64/ngrokd {vps_server}
scp bin/linux_386/ngrok {local_server}
配置域名和 ngrok 客户端、服务端
首先你需要在域名解析网站解析域名,后续你就可以通过域名远程连接内网服务器,这也是我们最终的目的哈。
解析主机记录为 ngrock 和 *.ngrok.xxx.com 且全部为 A 记录类型,记录值填你的 vps 外网地址。
服务端配置
前面我们已经把 ngrokd 文件拷贝到 vps 的根目录,在这里我们把转移到这里:sudo mkdir /opt/ngrkd & sudo mv ngrokd /opt/ngrokd/
然后使用 systemd 设置自启动服务,把如下内容保存在 /lib/systemd/system/ngrokd.service
, 域名要改成你自己的。
[Unit]
Description=ngrok server
After=network.target
[Service]
Type=simple
ExecStart=/opt/ngrokd/ngrokd -domain ngrok.xxx.com -httpAddr "" -httpsAddr "" -tunnelAddr ":4443" -log "/var/log/ngrokd.log"
Restart=on-failure
[Install]
WantedBy=multi-user.target
启动服务
sudo systemctl enable ngrokd
sudo systemctl start ngrokd
sudo systemctl status ngrokd
客户端配置
登录到内网服务器, 同样把编译好的 ngrok 拷贝过来的 ngrok 客户端,然后同样客户端服务添加到 systemd 自启动服务中,保存下面内容到文件 /lib/systemd/system/ngrok.service
[Unit]
Description=ngrok client
After=network.target
[Service]
Type=simple
ExecStart=/opt/ngrok/ngrok -config "/opt/ngrok/ngrok.yml" -log "/var/log/ngrok.log" start transmission ssh
Restart=on-failure
[Install]
WantedBy=multi-user.target
ExecStart 加载了配置文件 /opt/ngrok/ngrok.yml,其文件内容如下:
server_addr: ngrok.xxx.com:4443
trust_host_root_certs: false
tunnels:
transmission:
remote_port: 9091
proto:
tcp: 9091
ssh:
remote_port: 23333
proto:
tcp: 22
然后像启动 ngrok 服务端服务一样启动客户端服务
在这里提醒一点,我踩到了一个坑,启动客户端服务时日志 (sudo tail -f /var/log/ngrok.log) 出现报错:
[2018/02/13 01:41:28 CST] [DEBG] (ngrok/log.(*PrefixLogger).Debug:79) [view] [term] Waiting for update
[2018/02/13 01:41:28 CST] [EROR] (ngrok/log.Error:120) control recovering from failure dial tcp: lookup ngrok.xxx.com on 8.8.8.8:53: no such host
后面我在内网服务器 ping ngrok.xxx.com
提示找不到 host, 应该是 dns 的问题,nslookup ngrok.xxx.com
看了一下,果不其然,我直接把域名和 IP 写到内服务器的 /etc/hosts
文件上。
systemd 重启客户端服务之后就正常了。
最后通过 ssh -p 23333 [email protected] 即可远程登录局域网内的服务器。
推荐及参考阅读
内网穿透之ngrok [2017-10-13 UPDATED]