18 Star 95 Fork 35

newflydd / ngrok

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README
BSD-3-Clause

原文地址来自我的博客,欢迎访问:https://www.hexcode.cn/article/show/raspberry-ngrok

场景需求:家里的几台树莓派通过家用WIFI路由器上网,虽然装了Teamviewer可以远程穿透内网控制图形界面,但远程时屏幕分辨率太小,体验不佳,于是想让树莓派上的SSH也能拥有穿透内网的功能。

前言,关于Ngrok

查阅了很多资料,发现大多数内网穿透功能的实现都与一款Go语言编写的Ngrok项目相关,Ngrok是一整套的服务器,客户端解决方案。因为其是由Go语言编写的,所以天生具备很强的跨平台能力(但目前基本上所有资料都指向在Linux上部署该服务器端)。博主使用的是阿里云的Windows VPS,并且这段时间正好也在使用Go编程,因此这篇文章将具体介绍如何在Windows上部署Ngrok项目,并且在家用树莓派上部署客户端,实现树莓派的SSH内网穿透。

关于Ngrok,值得注意的有以下几点:

  • Ngrok并不仅仅用来22端口的SSH内网穿透,通过简单配置,它可以将遵循TCP/UDP协议的多个端口进行内网穿透。
  • Ngrok是由一台服务器端和一个或者多个客户端组成的体系。
  • Ngrok需要一台部署在公网固定IP上的服务器,最好有可正常指向的域名,Ngrok的服务器端就部署在上面,如本次实验的阿里云主机。
  • Ngrok的客户端装在需要映射的各个没有公网IP的机器上,比如本次实验的树莓派。
  • Ngrok服务器会在接受到Ngrok客户端请求时分配固定或者随机的端口号,将客户端请求的端口与之映射,从而达到内网穿透的目的。
  • 用户在远程使用SSH客户端进行连接时,不需要任何Ngrok程序,对终端用户来说,Ngrok是透明的。
  • Ngrok自身有一台欧洲的公网服务器,供没有VPS的用户注册使用,该服务器并不是以分配端口的方式映射,而是以分配子域名的方式,随机子域名是免费使用的,固定子域名映射是收费的。
  • 普通玩家可以直接使用Ngrok的官网服务器,缺点就是有一点点慢,而且每次客户端重启后子域名会随之变化,无法固定使用。
  • 国内也有一些商家提供了Ngrok服务,比如Sunny-Ngrok,同样是收费的,速度可能快一点。

Ngrok源代码是开源的,部署在Git上,但是博主使用下来略觉繁琐,涉及到很多自认为没必要使用的技术,后期我重新在Git上发布了我重构后的Ngrok项目,配有码云同步镜像,以供其他朋友直接使用诸如go build或者go install简单命令进行跨平台编译和安装。

为了致敬原作者,我们对这些高端的Golang编程技术做一个简单的了解,对Go语言没有兴致的朋友可以直接跳过下面这段:

  • go-bindata 技术,该技术是一套将任意资源文件转成二进制数据反向生成到Go代码供hash调用的技术,Ngrok的源码利用这一技术将公网证书和密钥,以及站点的HTML生成到go代码中去了,使其变成了一堆byte数组,在程序中hash调用。这么做固然有它的好处,但缺点也显而易见,因为这套技术要提前用一个项目的程序生成另一个项目的Go代码,所以编译起来难免繁琐,于是Ngrok提供了makefile文件以供用户make编译,这就有点尴尬了,本来好好的跨平台Go语言项目,被make和makefile活生生憋成了只能Linux使用的了。博主初期使用时硬着头皮安装了Cygwin,以及其中的make命令,个中的苦逼无以言表,索性后来了解原理后,将官方的Ngrok重构了一遍,避免了使用几乎是专属于Linux的make指令。
  • build -tags 技术,通过Ngrok项目,我第一次知道Go的这个特性,可以在代码顶端加上// +build !release等标记,注明编译时的模式,比如前面这种表达方式,就是在非release编译模式下才会编译这个文件,然后使用go build -tags 'release'或者go build -tags 'debug'来控制是否编译这个代码文件。这个特性确实灵活,可以在项目中编写不同的编译模式下的代码,缺点呢,就是没有详细文档的情况下,第三方用户并不知道有哪些编译模式,加大了源码本地编译的复杂度,所以这也是原版Ngrok项目使用makefile文件的原因之一。
  • equinox.io 技术,这项技术可以让Go代码在编译和运行期间保持更新,代码作者更新代码后,能够在第三方用户实时更新,具体没有了解,我看原版Ngrok在进行release编译时增加了很多equinox.io令牌密钥,以连接远程仓库,保证代码更新。

总之,上面的这些特性,虽然优点多多,但使用起来难免加大了难度,并且牺牲了Go优良的跨平台特性,这是我不能忍的,于是我重新构造了Ngrok项目,旨在让更多玩家,在众多平台上简单轻松的编译Ngrok项目。

言归正传,准备工作

下面我们言归正传,从零开始部署Ngrok,说说准备工作:

硬件部分

  • 一台公网IP服务器,本实验采用Windows系统,拥有域名hexcode.cn。
  • 一台装有RASPBIAN操作系统的树莓派,用来部署Ngrok客户端,使其可以SSH内网穿透
  • 一台Windows PC,开发环境

软件部分

  • Win32 OpenSSL v1.1.0f Light证书生成程序
  • MobaXterm几乎是最好的SSH客户端
  • go1.9.2.windows-amd64.msiGo语言编译器,我现在用得最多的语言,一股子的亲切感,交叉编译Linux,ARM,X86等平台的目标程序就跟玩一样
  • Ngrok源码这是我自己重构的Ngrok项目,原版的要想用起来还得安装Cygwin等一堆工具,现在非常纯净,拿到手直接用最简单的命令编译,各平台通吃。这份代码不需要手工download,下面会介绍直接用命令获取。
  • Git-windows-amd64这个就不赘述了,程序猿都知道。

从零开始操作

证书生成

Ngrok需要使用SSL证书确保穿透过程中的通信是加密安全的,因此需要SSL证书,值得庆幸的是并不强制去购买CA认证机构颁发的证书,普通用户直接使用OpenSSL工具就可以自行生成证书。方法如下:

  • 下载上述准备工作软件部分的SSL证书生成程序,安装后,将安装路径下的bin目录添加到环境变量,方便cmd直接运行openssl.exe
  • 任意路径打开cmd,执行下面命令:(注意,将两处MY_DOMAIN全部替换成自己的域名,比如我的hexcode.cn)
openssl genrsa -out rootCA.key 2048
openssl req -x509 -new -nodes -key rootCA.key -subj "/CN=MY_DOMAIN" -days 5000 -out rootCA.pem
openssl genrsa -out device.key 2048
openssl req -new -key device.key -subj "/CN=MY_DOMAIN" -out device.csr
openssl x509 -req -in device.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out device.crt -days 5000
cp rootCA.pem ngrokroot.crt
cp device.crt snakeoil.crt
cp device.key snakeoil.key
  • 全部执行完毕后,会在当前路径下生成6个文件,我们服务器端会用到其中的 snakeoil.crt , snakeoil.key ,客户端会用到 ngrokroot.crt 文件,先不管它们,留到下面使用。

编译Windows平台下的服务器端程序

得益于Go的众多优秀的特性,让一份跨平台的代码能够快速地适配不同平台编译和安装。相比其他语言不同的版本,不同的编译方式,编译工具,甚至有些是超级重量级的,比如JAVA,各个平台下的JDK少说也要300M,Go的编译器全平台覆盖,并且只有90M左右,非常轻巧,并且只需要在某一平台下下载一次,就可以轻松靠着两个环境变量编译出全平台覆盖的可执行程序,交叉编译从未如此简单过。

一聊起Go的优点,我就差点收不住。我们来实际体验一下吧,在上方准备工作软件部分下载Go的Windows平台编译器,按照提示安装,设置Windows环境变量PATH路径添加Go安装目录下的bin文件夹,方便cmd中直接使用go命令,为了还能直接使用go get命令,我们需要安装Git,下载地址在上方,下载回来直接根据提示全部以默认选项安装即可。 另外需要配置GOPATH,GOROOT两个环境变量,这两个并不是必须的,但为了减少麻烦还是建议设置,其中GOROOT变量指向Go的安装路径,比如C:\GoRootGOPATH是我们的工作区路径,随意填写,写完了就在此路径下编写程序就行了,当然如果你仅仅用来完成这个项目,以后不会学习Go也不会编写Go语言的代码,这个路径对你来说仅仅是接下来自动下载源代码的保存路径而已。这里我们简单设置成C:\GoPath。 如图所示:

OK,接下来正式下载,编译,和安装Ngrok的服务器端。 你一定会以为这一系列操作很复杂,其实对于Go来说仅仅是一条命令行的指令:

go get github.com/newflydd/ngrok/main/ngrokd

就这么简单,就这么神奇,简单到你不管在什么路径下执行这行命令都没有问题。这行命令的背后可不简单,go首先会去下载我上传到git上的Ngrok代码,然后试着编译,编译过程中它会发现Ngrok项目还七零八落地依赖了其他各个项目,于是Go用递归的方式再去执行go get命令,直到将所有依赖通通下载回来,最终它成功编译后,将生成的目标程序存放在%GOPATH%\bin目录下,默认情况下它是根据当前机器的环境来生成可执行文件,如果做一些简单的调整,它即可以交叉编译不同平台下的可执行文件。

执行过程可能会有些漫长,跟网络环境相关,建议使用全局科学上网工具。 成功编译后,在%GOPATH%\bin目录下会出现ngrokd.exe可执行程序,这就是你要上传到Windows服务器的程序,大小在8M左右,同时你需要上传第一步生成SSL证书中的 snakeoil.crt , snakeoil.key 两份文件到同目录。ngrokd.exe双击直接运行是没有意义的,它需要配有参数,因此我们编写bat脚本来方便运行(将下面的MY_DOMAIN替换成自己的域名,比如我的hexcode.cn):

ngrokd.exe -domain="MY_DOMAIN" -log ./ngrokd.log &

将上面脚本保存为run.bat,双击运行是一个命令行界面,同目录下会出现ngrokd.log,打开看一眼,如果出现以下字样,就说明服务器端程序已经正常运行了:

Listening for public http connections on [::]:80
Listening for public https connections on [::]:443
Listening for control and proxy connections on [::]:4443

运行时的画面如下:

编译Linux ARM平台下的树莓派客户端

试想一下,如果没有交叉编译,我们该如何在树莓派上安装Ngrok客户端:我们必须同样在树莓派上安装Go的Linux ARM版的编译器;RASPBIAN系统已经安装了git,所以我们不需要独立安装git;我们还得用go get指令下载和编译Ngrok的源码;openssl指令不用装了,因为证书已经生成了。

虽然也不是特别复杂,但还是挺费时间的,而且还会占用树莓派的资源,平白无故地要去安装接近90M的Go编译环境。得益于Go的强大,交叉编译发挥了巨大作用,我们在Windows X86 AMD64上就能编译出能在Linux ARM上跑的可执行文件。

打开一个新的cmd命令行,任意路径,执行下面命令:

set GOOS=linux
set GOARCH=arm
go get github.com/newflydd/ngrok/main/ngrok

OK,就这么简单,就这么神奇,Windows AMD64上的Go利用简单的两个环境变量,直接构造出了Linux ARM上的可执行文件,多么伟大的语言。。。 GOOS GOARCH的组合可以参照:

GOOS GOARCH
darwin 386
darwin amd64
freebsd 386
freebsd amd64
linux 386
linux amd64
linux arm
windows 386
windows amd64

在树莓派中运行Ngrok客户端程序

Go将生成的Linux平台下的程序保存在%GOPATH%\bin\linux_arm目录下,名为ngrok,我们需要将其copy到树莓派中。 我们使用超级强大的终端工具MobaXterm来连接树莓派并上传ngrok,MobaXterm的下载地址在本文上方,下载后按照提示就能安装,因为目前树莓派的SSH还不具备内网穿透功能,因此下面操作必须在局域网中完成。

使用MobaXterm建立与树莓派的SSH连接,这里并不是重点,相关操作如果不清楚可以自行百谷。 MobaXterm具有强大的文件上传功能,直接将使用下面图例中的按钮将Windows本地的ngrok客户端程序上传到指定目录,同时将我们第一步SSL证书环节生成的 ngrokroot.crt 文件上传进去。

我这里操作的目录为:/home/pi/workspace/go-apps/ngrok/,此时上传上去的ngrok文件不具备执行能力,需要使用下面命令为其添加执行权限:

chmod a+x ngrok

同样,ngrok程序不可以直接运行,也需要参数,并且还需要一个配置文件,我们执行下面操作新建配置文件,并编写sh脚本,以便直接运行。

nano ngrok.cfg

新建ngrok.cfg配置文件,并用nano文本编辑器打开,输入以下文本(将MY_DOMAIN替换成自己的域名,比如我的hexcode.cn):

server_addr: "MY_DOMAIN:4443"
trust_host_root_certs: false

tunnels:
    ssh:
        remote_port: 50000
        proto:
            tcp: 22

我这里仅仅需要让SSH的22端口具备穿透能力,因此我只配置了ssh任务,指定了远程端口固定为50000,映射本地的SSH22端口。Ctrl+O并回车保存,Ctrl+X退出文本编辑器。

nano run.sh

新建run.sh脚本文件,并用文本编辑器打开,输入以下文本:

nohup ./ngrok -log ./ngrok.ssh.log -config ./ngrok.cfg start ssh &

Ctrl+O并回车保存,Ctrl+X退出文本编辑器。

chmod a+x run.sh

为run.sh添加可执行权限。OK,大功告成,运行./run.sh即可建立树莓派与公网服务器的通信隧道,将其22端口映射到了公网服务器的50000端口,我们接下来就可以在世界任何角落,使用任何SSH工具,连接自己公网服务器的50000端口,访问家中的树莓派了,下图用MobaXterm做一个测试:

BSD 3-Clause License Copyright (c) 2017, Ding Ding All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

简介

原版Ngrok的重构版,使之更容易在各个平台下编译,尤其是Windows下的编译变得简单了。详细介绍可以参考:https://www.hexcode.cn/article/show/raspberry-ngrok 展开 收起
Go
BSD-3-Clause
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
Go
1
https://gitee.com/newflydd/ngrok.git
git@gitee.com:newflydd/ngrok.git
newflydd
ngrok
ngrok
master

搜索帮助