因为准备创建俱乐部,需要用到网站等内容。而创建俱乐部本身就是为了学习树莓派、编程等内容的,所以计划使用树莓派做Web服务器,不过因为设备在内网,而且没有固定IP,需要用到内网穿透。经过在网络上搜索,找到了Ngrok这个工具,1.X是开源的,2.X不是。于是开始用1.X创建Ngrok服务器。因为我不是技术派,所有的资料都是网上找到的,属于自己试错过来的,依葫芦画瓢而已。很多内容只是知其然而不知期所以然,因此如果这篇文章有幸被其他想要自己创建的朋友看到,有任何问题可以和我交流,我的邮箱是[email protected],欢迎发邮件交流。
一开始我只知道想要做内网穿透可以使用Ngrok,因为我是通过搜索内网穿透找到的它(感觉有点绕,将就一下,就啰嗦这几句)。
通过了解发现,Ngrok主要是用来做内网暴露的,是粗暴的机器翻译这么解释的,来自官网中文网站的介绍是:
将本地Web服务器公开到互联网
ngrok允许您将本地计算机上运行的Web服务器公开到互联网。只是告诉ngrok你的web服务器正在监听什么端口。
如果你不知道你的web服务器正在监听什么端口,它可能是端口80,HTTP的默认值。
我在其他介绍自建Ngrok服务器的文章中还看到:
ngrok是一个反向代理,它能够让你本地的网络服务或TCP服务通过公共的端口和外部建立一个安全的通道,使得外网可以访问本地的计算机服务.ngrok1.x开源,ngrok2.x不开源
ngrok的主要用途有以下几种:
- 内网穿透,可代替VPN
- 将无外网IP的桌面映射到公网
- 临时搭建网络并分配二级域名
- 微信二次开发的本地调试
还有的文章是和各类收费的软件作比较的,比如国内做了很久的花生壳,以及类似的软件(很多我记不住名字)。这部分就啰嗦到这里了。
Ngrok服务器必须搭建在公网独立IP的服务器上,这有点悖论,我都买了个公网独立IP服务器了,我还做内网穿透做什么?
我的考虑是,便宜啊。我的公网服务器只用来搭建Ngrok,对系统的要求很低,入门级别就可以了,一年只有几百大洋。而且,服务还可以搭建在亚马逊的AWS上面,如果是新用户,可以免费用一年,下一步我就准备在AWS上再建一个用一年,节约点成本也是好的。
搞清楚前面的内容后,我们就可以开始动手了。
这个指导文件的第一版我只是带过一下,关于安装操作系统的内容,请上网搜索相关内容了解执行。后续版本我会把相关内容都添加进去。
Debian上官网去下载最新版的安装就可以了,我用的是阿里云服务器,直接在阿里云里通过镜像的方式可以快速安装Debian系统。Raspbian其实就是Debian针对树莓派编译的独立版本Linux,到树莓派的官网就可以下载,按照里面的指导文件操作,很容易就可以搞定。
由于使用的镜像包安装的阿里云系统,简化的比较厉害,不少软件都没有,所以需要安装基础软件,以下的命令都是Debian中可用的,其他系统我没用过,所以没有去了解执行命令。所有的命令我都是在root账号下执行的。
首先是更新系统软件和系统命令:
apt-get update
apt-get upgrade
然后安装git:
apt-get install git
再安装go lang环境:
apt-get install golang-go
git和go lang环境的安装我都是用的Linux命令执行的,Linux系统的软件资源List会自动对应网址进行下载,这样省去了我选择版本的疑惑,基本上安装的都是最新版本的软件。这些步骤结束后,我们的环境已经准备好了,接下来开始安装Ngrok服务。
在使用git软件从github上下载Ngrok源码前,需要先进入装备安装的目录,我看到的几个版本都是建议放在/usr/local/目录下。至于为什么,在写这篇文章的时候我搜索了一下,这与Liunx目录的结构有关,Linux目录结构又来自于Unix系统,而这个初始结构的来历,居然是和过去单个磁盘空间太小有关,下面是引用的内容,大家也一起学习一下吧:
Unix目录结构是历史造成的。
话说1969年,Ken Thompson和Dennis Ritchie在小型机PDP-7上发明了Unix。1971年,他们将主机升级到了PDP-11。
当时,他们使用一种叫做RK05的储存盘,一盘的容量大约是1.5MB。
没过多久,操作系统(根目录)变得越来越大,一块盘已经装不下了。于是,他们加上了第二盘RK05,并且规定第一块盘专门放系统程序,第二块盘专门放用户自己的程序,因此挂载的目录点取名为/usr。也就是说,根目录"/“挂载在第一块盘,”/usr"目录挂载在第二块盘。除此之外,两块盘的目录结构完全相同,第一块盘的目录(/bin, /sbin, /lib, /tmp…)都在/usr目录下重新出现一次。
后来,第二块盘也满了,他们只好又加了第三盘RK05,挂载的目录点取名为/home,并且规定/usr用于存放用户的程序,/home用于存放用户的数据。
从此,这种目录结构就延续了下来。随着硬盘容量越来越大,各个目录的含义进一步得到明确。
/:存放系统程序,也就是At&t开发的Unix程序。
/usr:存放Unix系统商(比如IBM和HP)开发的程序。
/usr/local:存放用户自己安装的程序。
/opt:在某些系统,用于存放第三方厂商开发的程序,所以取名为option,意为"选装"。
**原文件链接 **
于是我也照做了:
cd /usr/local
git clone https://github.com/inconshreveable/ngrok.git
cd ngrok
以上三条命令就把源码文件复制到了ngrok目录下面,第三条命令是进入ngrok目录。到这里,Ngrok的文件已经复制好了,默认复制的是1.7版本的文件。作者针对1.x只到了这个版本,2.x版本就是在他的网站上去下载了,就不是开源的了。
接下来就要准备编译Ngrok服务端和客户端执行程序了,在编译之前要先生成域名证书,需要用到你自己的域名,这里我用domain.com代替一下,按图索骥的朋友记得要替换成你自己的域名。需要先设置一个全局环境变量,为什么要做这个我还没理解,所以照做:
export GOPATH=/usr/local/ngrok/
export NGROK_DOMAIN="domain.com"
这里有个小贴士
域名在正式启动服务前要解析到你的这个Ngrok服务器IP上,建议把二级域名ngrok.domain.com和所有三级域名*.ngrok.domain.com都解析到服务器上。怎么操作请谷歌或者百度。
编译的时候必须带有域名证书,你通过git复制来的文件自带了域名证书,但是里面的域名是开发者放的,和你自己的域名无关,如果不替换,生成的程序会出错。
开始生成域名证书:
openssl genrsa -out rootCA.key 2048
openssl req -x509 -new -nodes -key rootCA.key -subj "/CN=$NGROK_DOMAIN" -days 5000 -out rootCA.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 rootCA.pem -CAkey rootCA.key -CAcreateserial -out server.crt -days 5000
我是直接原样复制了,其中用到了我们刚才设置的全局环境变量,将来搞清楚为何要这样了我再补充,现在就是照做。
然后将文件复制到对应文件中,并更名。这么做的原因我也不清楚,从表面上看应该是程序调用的时候需要使用对应的文件名,由于时间关系,我没有去仔细研究了,以后补上:
cp rootCA.pem assets/client/tls/ngrokroot.crt
cp server.crt assets/server/tls/snakeoil.crt
cp server.key assets/server/tls/snakeoil.key
上面的命令将替换原来的域名证书,这些操作都要确保你是在ngrok目录下,否则会出错,因为其他位置没有这些文件夹和文件。
编译前的最后一步,要修改编译配置中的一个引用git上的文件夹位置。这个步骤只限国内的服务器需要操作,不修改可能被墙,无法正常工作。至于为什么,我也没明白,照做:
nano /usr/local/ngrok/src/ngrok/log/logger.go
将文件中第五行替换为log "github.com/keepeye/log4go"
,只是修改了中间的那个文件夹。
我看到的几篇文章都是用vi或者vim编程器,有一篇文章使用的是nano编程器,我推荐nano,操作更方便。
首先生成服务器端执行程序:
make release-server
这个命令执行的时间有点久,会在某几个位置卡住,让你有死机的错觉,我感觉都是github网站的锅,因为很多文件都是在那上面获取的……
小贴士:如果失败了,多执行几次,这是可以重复执行的。
执行成功后会在ngrok目录下生成bin目录,里面会包含ngrokd这个文件,这就是服务器端的启动服务执行文件了。
接下来编译客户端执行文件:
GOOS=linux GOARCH=amd64 make release-client
GOOS=windows GOARCH=amd64 make release-client
GOOS=linux GOARCH=arm make release-client
第一条命令生成的是在Liunx平台64位系统下的执行文件,第二条命令是windows平台64位系统的,第三条是arm平台的,我的树莓派就是这种平台。不同平台就使用不同的GOOS和GOARCH参数,前面的编译选项GOOS就是指编译出来的操作系统(windows,linux,darwin); GOARCH是指对应的构架(386,amd64,arm)
Linux平台32位系统:
GOOS=linux GOARCH=386 make release-client
Linux平台64位系统:
GOOS=linux GOARCH=amd64 make release-client
Windows平台32位系统:
GOOS=windows GOARCH=386 make release-client
Windows平台64位系统:
GOOS=windows GOARCH=amd64 make release-client
MAC平台32位系统:
GOOS=darwin GOARCH=386 make release-client
MAC平台64位系统:
GOOS=darwin GOARCH=amd64 make release-client
ARM平台:
GOOS=linux GOARCH=arm make release-client
小贴示:确保执行命令时在你的ngrok目录中。
如果没有错误,linux平台这个时候在ngrok/bin
目录中会有ngrok文件生成。windows平台会生成ngrok/bin/windows_amd64
文件夹,里面会生成ngrok.exe文件。arm平台会生成ngrok/bin/linux_arm
文件夹,里面会生成ngrok文件。
小贴示:记得直接复制我这里的命令,如果你是输入进去的话,GOOS和参数间不能有空格,GOARCH和参数间也不能有空格,否则会出错,显示没找到GOOS命令,因为是make这个命令在执行……
我在这里出了错,百思不得其解,害我重置了服务器的系统镜像,重新执行了一遍所有的步骤,最后无意间发现了里面的空格。
后续步骤就是将客户端执行文件复制出来,放到单独的文件夹中,Linux建议同样放在/usr/local/ngrok
文件夹中。
关于文件复制,我又经历了多重磨难,最后树莓派里的文件是直接把卡插windows电脑上复制的,windows里的文件是通过pscp.exe文件在命令行下复制的。由于不懂Linux,我当时为了找ngrok.exe文件可是花了个把小时,生成客户端程序操作了近十次。pscp.exe文件来自windows下超级好用的SSH工具软件PuTTY (64-bit),这里面都是泪啊,有空再把这个坑填上。
这些步骤完成了,就可以开始运行程序了。
首先运行服务器端,需要带上相应的参数:
/usr/local/ngrok/bin/ngrokd -tlsKey=/usr/local/ngrok/server.key -tlsCrt=/usr/local/ngrok/server.crt -domain="ngrok.domain.com"
使用这个-domain参数就是对应你之前解析到服务器的二级域名ngrok和三级域名*.ngrok的,如果你想对应一级域名,这里可以用"domain.com"替换"ngrok.domain.com"。
小贴示:很多说明的文章里会带上端口的参数,其实可以不用填,在客户端运行时填写端口参数就可以了
运行客户端稍有点复杂,有几个步骤要做。
ngrok要穿透的域名和端口都需要通过参数文件表达,先来个最简单的吧,新建ngrok.cfg文件:
nano ngrok.cfg
文件要确保和之前生成的客户端执行文件在一个文件夹内。编辑文件内容:
server_addr: "ngrok.domain.com:4443"
trust_host_root_certs: false
保存退出。ngrok.domain.com
就是你的域名。
如果是在windows下,可以使用最简单的记事本新建,文件内容完全一致。编辑完成保存的时候一定要记得选择Utf-8编码方式,保存类型选择 所有文件*.*
,否则执行的时候会出错。
./ngrok -config=./ngrok.cfg -subdomain=域名前缀 80
确保在ngrok文件夹内,域名前缀
就是你需要访问的域名的前缀,比如www.domain.com
中的www
,最后的80就是你要穿透的端口号。
在windows下使用命令:
ngrok -config=ngrok.cfg -subdomain 域名前缀 80
这里的域名前缀和上面讲的是同一个内容。
运行成功后,命令窗口就会显示一个文字UI界面。到这里,我在内网的树莓派建立的Web程序宝塔Linux面板
就可以正常访问了,端口号80是默认端口,可以不用www.domain.com:80
这样输入,如果你用的是其他端口,就需要在域名后输入:端口号
,比如www.domain.com:8080
。
小贴示:到这个步骤,你已经成功设置一个域名的内网穿透了。
只穿透一个端口有点太浪费了,我决定多穿透几个,于是继续搜索文章,又让我找到了学习的对象,开始下一个步骤。
小贴示:程序的编译和服务器端的运行都不用改变,只需要改变客户端命令即可。
多个端口和一个端口的穿透最大的区别就在于ngrok.cfg
这个文件里的内容:
server_addr: "ngrok.domain.com:4443"
trust_host_root_certs: false
tunnels:
tunnel1:
subdomain: 域名前缀1
proto:
http: 80
forex:
subdomain: 域名前缀2
proto:
http: 8080
mysql:
remote_port: 3306
proto:
tcp: 3306
这里要介绍一个之前没有出现的概念——隧道 tunnels
,其实这才是Ngrok的核心,我还处于一知半解的状态,大家可以将它理解为你想要穿透的端口号,一个端口就需要一条tunnel
,同时可以有多条隧道运行。
这条命令多了几个参数:
./ngrok -config ngrok.cfg start tunnel1 forex mysql
多了start参数,以及三条隧道的名称。这其中tunnel1
和forex
都是http的穿透,适合Web应用程序,比如网站服务程序。而mysql
这条隧道是tcp协议穿透的,比如数据库连接。这里需要注意remote_port: 3306
这一行,这是为默认地址配置端口号,如果你不填写后面的数字,系统会自动分配一个,这会造成穿透失败,需要直接配置成和你的要穿透的端口一致的状态。
前面的命令我都是通过SSH连接执行的,只要关闭SSH连接窗口,命令就被终止了,所以需要后台运行程序。以下内容未在windows中尝试,如果有需要的请自行搜索。如果方便,也可以发邮件告诉我进行补充[email protected]
这里我们要用到nohup
命令和&
的组合:
nohup /usr/local/ngrok/bin/ngrokd -tlsKey=/usr/local/ngrok/server.key -tlsCrt=/usr/local/ngrok/server.crt -domain="ngrok.domain.com" &
运行后会提示nohup ignoring input and appending output to ‘nohup.out’
,这是代表执行结果记录日志文件不可写,重定向到nohup.out
这个文件了,说明已经执行成功了。运行成功后,窗口不会显示任何内容,之前执行的过程都隐藏了,这和使用了&
命令有关。
客户端后台运行不能使用&
命令,会直接出错,我不明白其中的原因。
执行一个端口穿透的命令:
nohup ./ngrok -config=./ngrok.cfg -subdomain=域名前缀 80
执行多个端口穿透的命令:
nohup ./ngrok -config ngrok.cfg start tunnel1 forex mysql
执行完成后,可以关闭窗口也不会终止服务。
重新使用SSH连接后,无论是服务器端还是客户端程序的运行情况都不会显示,我们无法确认是否正常运行,所以需要查看后台运行的程序:
ps -aux
运行这个命令就可以显示后台所有的程序,这里是三个参数的集合-a -u -x
,具体哪个是什么意思,大家可以去搜索学习。
显示的结果中注意看最右端,会看到/usr/local/ngrok/...
这样一行,这就是在后台运行的程序了。
关闭后台运行的程序需要用到kill
命令:
kill -9 程序ID
这个程序ID要在ps -aux
显示的结果中对应行左边查看,第一列是命令的用户,第二列就是程序ID。运行该命令就会关闭后台运行的程序。
到这里,Ngrok就可以为你正常提供服务了。这两天时间,我走了太多的弯路,重置过4次阿里云服务器系统盘。还好现在网上的相关资料非常丰富,让我可以尽情学习,谢谢各位前辈大公无私的奉献,这也是让我想要把自己的经验进行分享的最大动力。
想要在整体过程中做到知其然亦知其所以然还是比较困难的,除非你对Linux和Ngrok两者都非常熟悉,以及网络端口相关的知识。所以在这种情况下,我是追求能够正常运行,然后再逐渐学习相关内容,在实践中学习。
所有的操作我都是在root账号下进行的。
最后我把整个过程中我使用到的Linux命令都列出来,供大家搜索参考学习。
命令 | 用途 |
---|---|
cd 目录位置 | 变更目录,/ 代表根目录。 |
mkdir 文件夹名 | 创建文件夹。 |
apt-get | Debian安装软件命令。 |
nano | 一个字符终端的文本编辑器,简单易用。 |
nohup | 让进程后台运行,与SSH终端连接无关。 |
& | 让进程后台运行,SSH终端连接断开失效。 |
cp | 复制文件。 |
ps | 查看后台运行文件。 |
kill | 终止后台运行文件。 |
scp | 远程复制文件。 |
树莓派的Debian系统的root账号默认是关闭的,需要在Pi账号登录的情况下使用:
su root
进入root账号临时开启状态。
如果你之前没有启用过root账号,需要通过设置root账号密码的方式启用root账号,需要在Pi账号登录的情况下使用:
sudo passwd root
命令设置root密码。
你需要进行穿透的端口,一定要在服务器端设置为打开的状态,否则无法穿透。我使用的是阿里云服务器,在服务器实例的安全组下进行设置,具体操作请登陆阿里云进行查询。
你如果想要使用多个二级域名进行穿透,在服务器端设置的时候,记得使用顶级域名。
在客户端参数文件中也使用顶级域名。
每个域名穿透隧道的端口号要对应,以免出错。
数据库服务器穿透可以只设置一个,在安装Web程序时统一填入这个穿透的域名。
使用宝塔类面板程序时,新建网站填网址的时候一定记得要把端口号设置为你在客户端设置中与域名应对的端口号,否则访问不了。
最后:本文章是我花了四个小时完成的,算是站在巨人的肩膀上再发展的,如果有借用的,麻烦注明一下出处,也算是给我强大的动力。