背景
这两天想跟异地的妹子一起玩《泰拉瑞亚》。直接用steam的联机非常卡,而自己的电脑又没有公网IP,于是最简单朴素的想法就是搞一个内网穿透,将自己本地的IP映射到一个公网IP上。
natapp
一开始是打算用natapp,但是这个东西的免费版会经常强制换域名换端口,非常难受。而收费版虽然不算贵,但总觉得挺浪费,可能也不怎么用却一直要续费。
后来想到natapp其实本质上是对ngrok的一个封装,于是就想自己干脆自己搭一个ngrok服务器就好了。
ngrok
当我打开ngrok官网的时候才发现事情却没那么简单。
原以为ngrok是一个开源项目,可是没想到为了恰饭,这个项目只有1.x版本是开源的,到了2.x以及3.x的阶段就直接闭源了。当然,对于一个普通用户来说,我并不关心他开源还是闭源,但是蛋疼的是他闭源之后,很多功能(比如自定义域名端口等)就从免费变成收费了。而且除了Github上还保留着的1.x的项目代码以及文档之外,他的官网上已经不提供对1.x版本的所有支持(包括文档、客户端下载链接等)。
不提供老版本的客户端下载链接就导致了我们只能自己编译并构建客户端。这显然很麻烦,根据多年开源项目的使用经验,编译别人的项目通常都会有一大堆的坑要踩。况且除了服务端需要编译、客户端也需要编译。我当然不希望这么麻烦,就想着要不试一试官网推荐的2.x,3.x版本?于是看了下官网的功能和收费:
真香,比natapp贵这么多,而且还是用的国外服务器,速度估计还比natapp要慢。是有多想不开才会用这个。
搭建
稳妥的做法当然是下载开源版本的源码自己编译,但是显然太慢了,我们希望能最快的构建服务。
服务端安装
我们知道,对于Unix系统来说,最方便的安装软件的方法就是直接在他自带的软件中心找。
我的云服务器是 Ubuntu 16.04LTS(xenial)
系统,于是我就去 ubuntu 的软件包搜索页面里搜了一把ngrok,结果如下:
虽然我们遗憾的看到,在 18.04(bionic) 和 18.10(cosmic) 中都被移除了,但是还好,ngrok-client
和 ngrok-server
软件包在 16.04 的版本里还是有的。
于是我们只需要一条命令即可安装ngrok的开源版:
代码语言:javascript复制$ sudo apt install ngrok-client ngrok-server
安装好后可以确认一下版本:
代码语言:javascript复制$ ngrok version
1.6
是1.x版本,可以安心使用了。
服务端SSL配置
ngrok服务端在使用自定义域名时需要配置TLS证书,最简单的方法当然是使用 letencrypt的certbot
工具啦。
$ sudo apt install certbot
具体操作方法可以另找教程,需要的结果就是在letsencrypt
的相关目录下找到自定义域名的证书文件(*.pem):
$ ls /etc/letsencrypt/live/ngrok.mythsman.com
cert.pem chain.pem fullchain.pem privkey.pem README
服务端启动服务
先查看 ngrokd
服务的说明:
$ ngrokd -h
Usage of ngrokd:
-domain="ngrok.com": Domain where the tunnels are hosted
-httpAddr=":80": Public address for HTTP connections, empty string to disable
-httpsAddr=":443": Public address listening for HTTPS connections, emptry string to disable
-log="stdout": Write log messages to this file. 'stdout' and 'none' have special meanings
-tlsCrt="": Path to a TLS certificate file
-tlsKey="": Path to a TLS key file
-tunnelAddr=":4443": Public address listening for ngrok client
依样画葫芦,比如可以设置成这样:
代码语言:javascript复制$ ngrokd -domain="ngrok.mythsman.com" -httpAddr="" -tunnelAddr=":443" -httpsAddr="" -tlsCrt="/etc/letsencrypt/live/ngrok.mythsman.com/cert.pem" -tlsKey="/etc/letsencrypt/live/ngrok.mythsman.com/privkey.pem"
由于这样默认是会将阻塞当前会话,因此需要用nohup
配合将程序放到后台运行,并将输出重定向:
$ nohup ngrokd -domain="ngrok.mythsman.com" -httpAddr="" -tunnelAddr=":4443" -httpsAddr="" -tlsCrt="/etc/letsencrypt/live/ngrok.mythsman.com/cert.pem" -tlsKey="/etc/letsencrypt/live/ngrok.mythsman.com/privkey.pem" &>output.log &
这样一来,服务器就开启好了4443端口等待ngrok客户端的连接了。
客户端安装
如果是客户端是Ubuntu,那么其实已将安装好了。。。可是我这边的客户端是Windows,就比较难受了,没有一个官方的软件包下载中心。
还好,找了半天终于找到了一个好人将之前下载好的1.x版本的Windows客户端分享了下来(而且还不要积分):CSDN下载链接。
这个是免安装的,下载下来打开命令行就可以直接用了。
客户端启动
客户端启动分两步即可:
1.编写ngrok.cfg配置文件如下:
代码语言:javascript复制server_addr: "ngrok.mythsman.com:4443"
trust_host_root_certs: true
这里的server_addr填写的就是ngrok服务端的域名以及当时指定的 -tunnelAddr
参数。
2. 启动
代码语言:javascript复制> ngrok.exe -subdomain="terraria" -config="ngrok.cfg" -proto="tcp" 7777
这里的-subdomain可以随便填一个、表示你需要在服务端域名的基础上生成的新的子域名。当然,由于我的服务用的并不是web协议,而只是一个普通tcp协议,因此这个配置实际没有用。
这里的-proto表示你内网需要映射的网络协议。如果不填,默认是会把你的端口当成是http或https。由于我这边需要映射泰拉瑞亚的游戏端口的并不是web协议而是一个底层的tcp协议,因此这里需要指定成tcp协议。
最后的端口是你需要映射的本地端口(对于泰拉瑞亚来说默认就是7777啦)
输入完之后就会跳出一个新的页面:
代码语言:javascript复制ngrok (Ctrl C to quit)
Tunnel Status online
Version 1.7/1.6
Forwarding tcp://ngrok.mythsman.com:35146 -> 127.0.0.1:20533
Web Interface 127.0.0.1:4040
# Conn 0
Avg Conn Time 0.00ms
那么,这里的 ngrok.mythsman.com:35146 就是在公网映射后的本地7777端口的服务了。
说明
最后有一个不容回避的问题,那就是ngrok只支持tcp协议的穿透,对于使用udp协议的服务是无法处理的。比如像《饥荒》这样的使用udp进行传输的游戏是不好用ngrok搞的。如果想要做的话,只能用工具将udp转为tcp或者用frp那种支持udp穿透的工具。