部署自己的Ngrok内网穿透服务

ngrok

说明

其实这就是让外网用户访问内网的服务,要求就是自己需要一个公网服务端。优点是方便,缺点就是有点脱了裤子(都有公网服务器了,还需要在内网做什么?不过确实还是有提供服务的,方便网友。你说懒得上传服务器,那好吧,这算是个优点。)

我已完成搭建,域名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