本文介绍Ngrok服务搭建。Ngrok和花生壳类似都是内网穿透工具,了解更多可以查看另外一篇专门介绍内网穿透工具的文章:内网穿透的几种方式

Ngrok介绍

Ngrok官网

Ngrok官方介绍是:一个通过任何NAT或防火墙为您的本地主机服务器提供即时,安全的URL的命令。

官方提供了免费的服务器,申请账号后下载客户端就可以直接使用,不过有一些其他限制,比如带宽很小。1.0的客户端和服务端都是开源的,2.0的版本没开源,而且官网找不到开源代码的链接。

Ngrok分为客户端和服务端,使用官网提供的服务,我们就只需要下载一个客户端就可以了,本文不做介绍,我们的重点是,自己搭建服务器。

资源链接

安装服务端

我比较喜欢使用Dcoker,就直接以Docker为例,喜欢安装到本地的,自己去编译源代码。官方的Docker镜像有问题,有个命令使用不兼容,会导致一直无法找到CA文件而启动失败,可以直接使用我重新编译的Docker镜像

准备证书

推荐使用这篇文章来申请证书文件:免费通配符域名CA证书。通过这种方式生成的证书包括了cert.pem和privkey.pem。

$ mkdir certs

拷贝cert.pem和privkey.pem到certs目录,还需要转换以下格式:

$ openssl rsa -in privkey.pem -out server.key
$ openssl x509 -in cert.pem -out server.crt
$ cp server.crt ca.crt

现在certs目录看起来像:

.
├── ca.crt
├── cert.pem
├── privkey.pem
├── server.crt
├── server.key

直接运行docker

docker run -d --net host \
    -e DOMAIN="your.domain" \
    -v  ./certs/server.key:/server.key \
    -v  ./certs/server.crt:/server.crt \
    -v  ./certs/ca.crt:/ngrok/assets/client/tls/ngrokroot.crt \
    -v  ./bin:/ngrok/bin \
    yangqiang/ngrok-server

主要会做两件事:
* 会编译好服务端和客户端程序:bin/ngrokd、bin/ngrok
* 会通过编译好的ngrokd程序,启动服务端

到目前位置,服务端就启动好了,客户端可以拷贝到其他机器上去连接到服务端。

通过docker-compse运行

ngrok-server:
  restart: always
  container_name : 'ngrok-server'
  image : 'yangqiang/ngrok-server'
  environment :
    TZ: 'Asia/Shanghai'
    DOMAIN: "your.domain"
  volumes :
    - './certs/server.key:/server.key'
    - './certs/server.crt:/server.crt'
    - './certs/ca.crt:/ngrok/assets/client/tls/ngrokroot.crt'
    - './bin:/ngrok/bin'

客户端使用

生成的服务端和客户端程序在./bin目录。服务端会自动启动,需要客户端的话拷贝出去。首先需要准备域名*.your.domain,通过这个通配域名指向服务端的服务器IP,ngrok会自动分配子域名。

创建配置文件ngrok.yml

server_addr: your.domain:4443
trust_host_root_certs: false
tunnels:
    gitlab:
        subdomain: gitlab
        proto:
            https: 10104
            http: 10104

简答做一个说明:

  • server_addr:是服务端的地址,通过这个地址和端口连接到服务端。
  • tunnels:通道,通过通道可以建立很多http、https、tcp等连接。
  • subdomain:子域名
  • proto:连接协议:http、https、tcp等

上面的配置文件的意思是可以通过:gitlab.your.domain访问内网的10104端口的gitlab服务。可以通过http和https两种方式。

客户端连接

拷贝刚刚服务器在certs目录同级的bin目录中的ngrok到本机。

$ chmod +x ngrok
$ ./ngrok -config=ngrok.yml start gitlab

如果有多个可以按照gitlab的配置方式配置,然后启动的时候也需要加上:

server_addr: your.domain:4443
trust_host_root_certs: false
tunnels:
    gitlab:
        subdomain: gitlab
        proto:
            https: 10104
            http: 10104
    test:
        subdomain: test
        proto:
            http: 8080

然后启动的时候加上新的通道:

$ ./ngrok -config=ngrok.yml start gitlab test

启动成功后,应该是这个界面:

ngrok
                                                              (Ctrl+C to quit)

Tunnel Status                 online
Version                       1.7/1.7
Forwarding                    https://gitlab.your.domain -> 127.0.0.1:10104
Forwarding                    http://gitlab.your.domain -> 127.0.0.1:10104
Forwarding                    http://test.your.domain -> 127.0.0.1:8080
Web Interface                 127.0.0.1:4040

现在就可以通过gitlab.your.domain访问内网的127.0.0.1:10104啦。

如何通过SSH让外网访问内网呢?

我们有服务器internal(内网服务器)和一个外网能访问的服务器external。怎么让内网的服务器也能够被外网访问呢?我们可以通过external来做中转。

准备

  • 内网服务器,可以访问外网:internal
  • 外网服务器:external

原理

ssh工具是一个非常强大的工具,除了能够远程连接,还能建立隧道,转发端口。利用这个特性就可以把外网的端口请求,连接到内网端口。ssh本身的连接并不稳定,借助工具autossh可以很稳定的建立隧道,因为失败或者其他网络情况下,autossh会自动维护和保持连接。

安装

  • 安装autossh
    1)下载:http://www.harding.motd.ca/autossh/
    2)安装
$ wget http://www.harding.motd.ca/autossh/autossh-1.4f.tgz
$ gunzip -c autossh-1.4f.tgz | tar xvf -
$ cd autossh-1.4f
$ ./configure
$ make && make install

建立连接

第一步:连接内网到远程

autossh -M 60102 \
-fN -o "PubkeyAuthentication=yes" \
-o "StrictHostKeyChecking=false" -o "ServerAliveInterval 60" -o "ServerAliveCountMax 3" \
-R localhost:60002:localhost:10110 \
-p 2222 root@yangqiang.im

这一段命令的意思就是把internal内网端口10110连接到external:yangqiang.im的60002端口,external:yangqiang.im的ssh端口是2222,autossh数据监听端口是60102,-o 的参数和ssh的-o是一致的。

点击查看参数详情

  • -M <端口> [:echo_port] 指定要使用的基本监听端口,或者指定echo端口。
    • 当没有指定接收端口时,echo端口号就是监听端口号临近的端口(端口+1)要保证这个这个端口没有被占用。使用:autossh将在基本监控中发送测试数据端口,并在上面的端口上接收它。例如,如果你指定“-M 20000”,autossh将设置为可以在端口20000上发送数据并在20001上接收它。
    • 另外,远程echo端口可能是指定的。如果你想使用标准的inetd echo服务,这个端口这应该是7。当指定了echo端口时,只会使用指定的监听端口,并且它监听接收和发送的双向消息。
    • 很多人禁用了echo服务,甚至禁用了inetd,因此请检查此服务是否可用于远程机。有些操作系统允许用户指定服务只监听本地主机(环回接口),这足以满足这种用途。
    • echo服务也可能更复杂一些:也许是监听一组ssh隧道的守护进程。
    • -M 0将关闭监控,并且autossh只有在ssh退出的时候才会重启ssh。
    • 例如,如果使用的是最新版本的OpenSSH,那么不妨探索一下使用ServerAliveInterval和ServerAliveCountMax选项让SSH客户端退出的时候,发现自己不再连接到服务器。在许多方面这可能是比监控端口更好的解决方案。
  • -f 在运行ssh之前让autossh后台运行。-f标志从传递给ssh的参数中剥离。 请注意ssh的-f与autossh的-f之间的关键区别:使用autossh时,ssh将 无法 使用密码或密钥。 当使用-f时,starting gatetime(请参阅AUTOSSH_GATETIME)将设置为0。

第二步,把外网访问流量连接到external监听端口

ssh -p 2222 -fNTCL *:80:localhost:60002 localhost

这一段命令的意思就是把external外网机的80端口流量转发到本机external的60002上面。因为60002是和internal的10110连接的,所以现在可以直接通过外网80端口访问到内网的10110。