说明
其实这就是让外网用户访问内网的服务,要求就是自己需要一个公网服务端。优点是方便,缺点就是有点脱了裤子(都有公网服务器了,还需要在内网做什么?不过确实还是有提供服务的,方便网友。你说懒得上传服务器,那好吧,这算是个优点。)
我已完成搭建,域名http://?.n.scwy.net,有需要的网友可以申请,做一些小量的测试使用还是可以的。比如我就用在Raspberry Pi上,安装一些服务之类的。
编译安装ngrok
安装GO环境
ngrok是使用GO进行开发的,所以首先需要安装GO环境,在CentOS中非常方便,直接使用 yum install golang -y 进行安装,安装完成之后在命令行中执行 go version 命令,如果出现版本号即表示安装成功。可以通过 go env 命令查看GO的环境信息。
下载ngrok
ngrok项目的官方地址是:https://github.com/inconshreveable/ngrok,可以通过 git clone https://github.com/tutumcloud/ngrok.git ngrok 进行安装,但发现在服务器上下载非常慢,也可以直接下载其源码的zip包,命令行如下(以安装到/usr/local/ngrok目录为例):
wget https://github.com/inconshreveable/ngrok/archive/master.zip -O /usr/local/ngrok.zip unzip /usr/local/ngrok.zip -d /usr/local/ mv /usr/local/ngrok-master/ /usr/local/ngrok/ export GOPATH=/usr/local/ngrok/
生成自签名证书
因为单独安装自己的ngrok,所以需要使用openssl生成自签名的SSL证书,使用下面的命令(需要将NGROK_DOMAIN替换成自己的域名):
cd /usr/local/ngrok NGROK_DOMAIN=“ngrok.example.com” 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 device.key 2048 openssl req -new -key device.key -subj “/CN=$NGROK_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 assets/client/tls/ngrokroot.crt cp device.crt assets/server/tls/snakeoil.crt cp device.key assets/server/tls/snakeoil.key
最后的复制命令是将生成的证书分别替换到 assets/client/tls和assets/server/tls 目录中,这两个目录分别存放着ngrok和ngrokd的默认证书。
最后的复制命令是将生成的证书分别替换到 assets/client/tls和assets/server/tls 目录中,这两个目录分别存放着ngrok和ngrokd的默认证书。
编译并启动服务端
ngrokd 为服务端的执行文件,ngrok为客户端的执行文件,我们先来编译ngrok的服务端程序,在ngrok目录下面执行下面的命令:
make release-server
首次编译的时候需要从远程下载一些依赖文件,所以时间有一些长。需要注意的是,第一次不能执行 make clean 命令,否则会出现错误,对GO不是很熟悉,有一些资料说是跟使用yum方式安装GO有关。
编译成功之后会在项目目录的bin目录下面生成一个 ngrokd 的文件,使用下面的命令启动服务:
bin/ngrokd -domain=“ngrok.example.com” -httpAddr=":8088" -httpsAddr=":8089" -tunnelAddr=":4000"
上面的参数中,domain表示服务的域名,httpAddr和httpsAddr分别表示HTTP和HTTPS的端口,tunnelAddr用来设置通道的端口,在客户端和服务端建立连接的端口,需要在防火墙中开放次端口(默认为4443)。
可以将命令加入到 /etc/rc.local 中使其开机启动,命令如下:
/usr/local/ngrok/bin/ngrokd -domain=“ngrok.example.com” -httpAddr=":8088" -httpsAddr=":8089" -tunnelAddr=":4000" > /dev/null 2>&1 &
其中 /usr/local/ngrok 是ngrok的安装目录,最后不显示运行的日志,并且在后台运行。
使用客户端调用
编译客户端
接下来要编译专用的客户端,首先进入项目的根目录,使用下面的命令编译专用的客户端文件:
GOOS=windows GOARCH=386 make release-client
其中GOOS用乱设置操作系统,GOARCH用来设置对应的架构(386,amd64或arm),其含义如下:
Linux 平台 32 位系统:GOOS=linux GOARCH=386 Linux 平台 64 位系统:GOOS=linux GOARCH=amd64 Windows 平台 32 位系统:GOOS=windows GOARCH=386 Windows 平台 64 位系统:GOOS=windows GOARCH=amd64 MAC 平台 32 位系统:GOOS=darwin GOARCH=386 MAC 平台 64 位系统:GOOS=darwin GOARCH=amd64 ARM 平台:GOOS=linux GOARCH=arm
上面的命令表示编译windows下使用的32位的客户端程序,编译好的文件在bin目录下对应平台的目录下面。
启动客户端
接下来就可以使用客户端了,首先创建一个ngrok的配置文件ngrok.cfg:
server_addr: “ngrok.example.com:4000” trust_host_root_certs: false
域名后面的端口是设置的通道端口。
接下来使用下面的命令运行客户端:
./ngrok -subdomain jet -config=ngrok.cfg 8080
其中jet是自定义的域名前缀,ngrok.cfg是上面的配置文件,8080是映射的本地到外网的端口,这样就可以使用 http://jet.ngrok.example.com:8088 访问本地8080的端口了。
另外,还可以使用 -proto 来指定协议的类型(默认是http协议),支持http、tcp等多种协议:
./ngrok -subdomain jet -config=ngrok.cfg -proto=tcp 8080
使用Nginx反向代理到80端口
上面通过子域名访问的时候不是默认的80端口,可以使用Nginx进行反向代理,配置信息如下:
upstream tdt_99tone_ngrok_server {
server 127.0.0.1:8088 weight=1 max_fails=3 fail_timeout=30s;
keepalive 64;
}
server {
listen 80;
server_name *.ngrok.example.com ngrok.example.com;
charset utf-8;
location / {
proxy_next_upstream http_502 http_504 error timeout invalid_header;
proxy_set_header Host $host:8088;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://tdt_99tone_ngrok_server;
proxy_redirect off;
}
access_log off;
log_not_found off;
}
外网访问内网ssh ngrok -config=./ngrok.cfg -proto=tcp 22
这里还介绍了为自己的服务器添加一个简单认证,免得随便谁都来使用。–> https://ask.csdn.net/questions/688161 实际是修改了 ngrok/src/ngrok/server/control.go文件
func NewControl(ctlConn conn.Conn, authMsg *msg.Auth) {
//省略
//读取文件方法
readLine := func(token string, filename string) (bool, error) {
if token == "" {
return false, nil;
}
f, err := os.Open(filename)
if err != nil {
return false, err
}
buf := bufio.NewReader(f)
for {
line, err := buf.ReadString('\n')
line = strings.TrimSpace(line)
if line == token {
return true, nil
}
if err != nil {
if err == io.EOF {
return false, nil
}
return false, err
}
}
return false, nil
}
//省略
//调用验证
authd, err := readLine(authMsg.User, "authtokens.txt")
if authd != true {
failAuth(fmt.Errorf("authtoken %s invalid", "is"));
return
}
//省略
}
当然你随意添加还是会有点错误提示,比如库没有引入,failAuth没定义之类的。会golang的自会处理。 重新编译服务端 , 在执行文件同目录建立一个 用户文件,“authtokens.txt” 在客户端使用的时候-authtoken “xxxxxxx” 对应txt中的其中一行即可: ngrok -subdomain=b -config=./ngrok.cfg -authtoken=abcdefg 8181 或者修改配置文件,例如:
server_addr: ngrok.testdomain.com:4443
trust_host_root_certs: true/false
auth_token: username:password
tunnels:
b:
subdomain: b
proto:
http: "80"
https: "8080"
然后启动.\ngrok.exe -log ngrok.log -config ngrok.cfg start b