Total Pageviews

Thursday, 21 April 2016

ngrok 是一个反向代理


gotunnel.org 是一个非官方的 ngrokd 服务器,由本人建立并部署在一台香港的 VPS 上。
ngrokd 版本: 1.7

什么是 ngrok

ngrok 是一个反向代理,用于从一个公共的节点创造一个安全的隧道到本地运行着的 web 服务。ngrok 捕捉并且分析所有通过该隧道的流量以便用来检查以及重播。
总之,这玩意很有用。

使用教程

Windows / Linux / Mac OS X 系统的使用方法均大同小异。

获取客户端

为了使用 gotunnel.org 的服务,首先你需要有一个客户端。
我们并没有使用自签名的证书,因此所有的客户端均可以用于连接 gotunnel.org
为了方便,我直接从官网把现有的编译好的客户端全部下载下来,并且转存到国内的服务器,方便大家进行下载。
https://imlonghao.com/upload/ngrok/%s.zip
%s 需替换成:
Windows64
Windows
MacOSX32
MacOSX
LinuxARM
Linux32
Linux
FreeBSD32
FreeBSD

创建配置文件

server_addr: "gotunnel.org:3334"
trust_host_root_certs: true
复制并保存上面的代码即可,这里我用 ngrok.cfg 作为文件名。
更多配置,请看 「翻译」ngrok 1.X 配置文档

启动 ngrok

ngrok -config ngrok.cfg -subdomain mysite 80
更多参数,请看 「翻译」ngrok 1.X 使用文档

其他说明

TCP 转发

ngrok 原生支持 TCP 转发,我并没有对 TCP 转发的端口进行限制,这就意味着你可以在合理的范围内进行 TCP 转发操作。

自定义域名

gotunnel.org 支持自定义域名,首先,你需要给你的域名设置一个 CNAME 记录,绑定到 gotunnel.org 上来。
关于自定义域名,请看 「翻译」ngrok 1.X 配置文档
(注:由于缺少认证,因此不排除你的域名被他人使用,建议使用完就把域名解析关闭掉

流量说明

gotunnel.org 禁止进行大流量的操作,仅允许在合理的范围内进行网页的调试,例如调试微信等等。

备案说明

gotunnel.org 该域名暂未有备案的打算,因此微信的 JS SDK 可能无法进行白名单的绑定
(不过不影响其他微信的调试)
from https://imlonghao.com/29.html#gotunnel.org
---------------------------------------------

编译ngrok服务器 (此文是此类文章中最早发表的)

首先安装go环境:

cd /usr/local/src/
git clone https://github.com/inconshreveable/ngrok.git
export GOPATH=/usr/local/src/ngrok/
export NGROK_DOMAIN="haiyun.me"
生成自签名SSL证书,ngrok为ssl加密连接:
1
2
3
4
5
6
7
8
9
10
11
12
cd ngrok
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
GOOS=linux GOARCH=386
make clean
make release-server release-client
如果一直停留在go get gopkg.in/yaml.v1参考:https://www.haiyun.me/archives/1011.html
启动SERVER:
1
bin/ngrokd -domain="$NGROK_DOMAIN" -httpAddr=":8000"
交叉编译windows客户端,最好安装最新版本Golang,使用yum安装的一直编译不通过。
1
2
3
4
cd /usr/local/go/src/
GOOS=windows GOARCH=386 CGO_ENABLED=0 ./make.bash
cd -
GOOS=windows GOARCH=386 make release-server release-client
客户端配置:
1
2
3
4
5
6
7
8
9
10
11
12
13
server_addr: "haiyun.me:4443"
trust_host_root_certs: false
tunnels:
  http:
    subdomain: "example"
    auth: "user:12345"
    proto:
      http: "80"
  ssh:
    remote_port: 2222
    proto:
      tcp: "22"
启动客户端:
1
bin/ngrok -config ngrok.conf start http ssh
注意所有domain要一致,不然会出现证书错误:
1
Failed to read message: remote error: bad certificate

from http://www.haiyun.me/archives/1012.html
---------------

编译ngrok服务端客户端,替代花生壳,跨平台

 

ngrok是一个ddns服务,可以像花生壳一样,为内网机器绑定一个公网域名,方便开发调试远程接口(如微信开发)。
很多人抱怨,微信开发的时候无法在本地实现接口调试,必须将项目放置到一个公网服务器上,有一个正式的域名能否访问,还得是80端口,这样微信那边才能和我们的项目进行通信。
但是,一般情况下我们的开发环境是在内网,外网无法访问到我们的电脑,而且就算是adsl拨号,电信运营商也不允许使用80端口对外提供服务。
在这种蛋疼的条件下,机智的程序员们还是有解决办法的:
  1. 用POSTMAN模拟接口访问,局限性很大,比如微信OAUTH授权流程走一个看看?
  2. 本机安装花生壳客户端,为本机绑定一个动态域名,这样只要访问指定的花生壳域名,由花生壳进行反向代理,外面的请求通过花生壳进行转发到本机127.0.0.1,响应包同样通过花生壳进行转发。
我选择第二种,但是我用不了花生壳,花生壳并没有提供mac os的客户端,所以只能寻找替代方案,答案就是 ngrok。
ngrok是一款开源的,用go语言开发的动态域名服务,含服务端和客户端,当然,是老外开发的。
ngrok官网提供了一个官方服务,我们只需要从官网下载客户端即可,很是方便。
但不幸的是,ngrok官方服务器国内已无法连通,不知道是人家屏蔽了我们,还是我们屏蔽了人家,大家心中有数哈。
这种境况下,我们大天朝码农还是有办法的,既然人家开源了,那我们自己编译服务端放在自己vps上就是,域名很多人都有吧,不然还搞个毛的web开发。
天朝已经有位玩家提供了免费的服务,大家到这里查看:http://www.tunnel.mobi/ 。我也用了一段时间,但是昨天突然抽风,给我的开发进度造成了一点损失,所以我决定自己编译一个服务端,接下来进入正题,介绍下我的编译流程。
编译分两块:
  1. 服务端
  2. 配套客户端
客户端是需要和服务端匹配的,在编译的时候是要指定域名证书的,所以不用担心别人用其他的客户端去连你的服务端。
编译准备
  1. 一个vps,阿里云或者其他,linux系统即可,这里我推荐debian或ubuntu.
  2. 一个域名,将域名泛解析到你的服务器上。
  3. 为服务器安装git和go
我就直接在我的博客服务器上编译了,我准备使用 ngrok.ekan001.com 作为动态域名的根,记得泛解析。
首先我们需要在服务器上安装go环境,我建议下载最新版的go包,直接解压到服务器 /usr/local/go 即可,然后将 /usr/local/go/bin/* 复制到 /usr/bin/
go的下载地址:http://www.golangtc.com/download 下载和你服务器系统对应的版本即可,这里我是linux 64位的,就选择下载 go1.4.2.linux-amd64.tar.gz 即可。
接着,下载ngrok源码:
cd /usr/local/src/
git clone https://github.com/inconshreveable/ngrok.git
export GOPATH=/usr/local/src/ngrok/
export NGROK_DOMAIN="ngrok.ekan001.com"
cd ngrok
开始编译
  1. 首先为根域名生成证书
    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
    
  2. 编译服务端
服务端比较容易,先指定一下我的环境变量,然后再make:
    GOOS=linux GOARCH=amd64
    #如果是32位系统,这里 GOARCH=386
然后make
    make release-server
按理讲,应该就可以编译成功了,但是我发现,编译的时候很多依赖包是需要自动下载的,有一个包 log4go 是在 code.google 上的,我们天朝服务器是无法访问google的,大家懂,所以我这里是这么处理的:修改源码,将该包改为 github 上的地址:
找到 /usr/local/src/ngrok/src/ngrok/log/logger.go ,第五行import中的 log 包,改为: log "github.com/keepeye/log4go"
然后重新 make release-server
接下来可能还会遇到一个问题,编译时在 go get gopkg.in/yaml.v1 步骤时候卡住,这是因为git版本太低,请将服务器git版本升级到1.7.9.5以上。
编译成功后,应该可以在 /usr/local/src/ngrok/bin 下生成了一个 ngrokd 可执行文件,这就是我们的服务端了,现在启动服务端试试:
bin/ngrokd -domain="$NGROK_DOMAIN" -httpAddr=":8000"
如果没有报错的话,会出现以下输出:
[10:05:48 CST 2015/04/17] [INFO] (ngrok/log.(*PrefixLogger).Info:83) [registry] [tun] No affinity cache specified
[10:05:48 CST 2015/04/17] [INFO] (ngrok/log.(*PrefixLogger).Info:83) [metrics] Reporting every 30 seconds
[10:05:48 CST 2015/04/17] [INFO] (ngrok/log.Info:112) Listening for public http connections on [::]:8000
[10:05:48 CST 2015/04/17] [INFO] (ngrok/log.Info:112) Listening for public https connections on [::]:443
[10:05:48 CST 2015/04/17] [INFO] (ngrok/log.Info:112) Listening for control and proxy connections on [::]:4443
现在先 ctrl+c 退出,我们还需要编译客户端呢。
  1. 编译客户端
我的本机系统是 mac osx ,64位,对应的 GOOS 和 GOARCH 是这样的:
GOOS=darwin GOARCH=amd64
然后我直接编译:
make release-client
编译是成功了,但是我发现编译出来的东西是 bin/ngrok ,它还是linux平台的包,我mac上无法执行。原因是我们没有为go生成交叉编译环境,需要补充下面的一个步骤:
前文说到,我们的 go 安装在 /usr/local/go ,现在我们执行下面的命令:
cd /usr/local/go/src
GOOS=darwin GOARCH=amd64 ./make.bash
然后回去ngrok目录,接着编译:
cd -
GOOS=darwin GOARCH=amd64 make release-client
完了以后可以在 /usr/local/src/ngrok/bin/darwin_amd64/ 下发现 ngrok 文件,将它拷贝到我的mac上。
如果是windows下的客户端,是这样的:
cd /usr/local/go/src
GOOS=windows GOARCH=amd64 ./make.bash
cd -
GOOS=windows GOARCH=amd64 make release-client
#同理,这里的amd64是64位系统,32位改成386
#应该会在 bin/windows_amd64 目录下生成ngrok客户端程序
到这里,编译就完成了,现在让我们把应用跑起来:
按之前的方式启动服务端ngrokd,有以下提示:
Listening for public http connections on [::]:8000
Listening for control and proxy connections on [::]:4443
记住这两个端口 8000 和 4443 。
现在我们来到自己电脑上,准备启动客户端。在启动之前,我们需要为客户端编写一个配置文件 ngrok.cfg :
server_addr: "ngrok.ekan001.com:4443"
trust_host_root_certs: false
注意,配置文件中用的是4443端口。
然后启动客户端,假设我们要分配一个域名 test.ngrok.ekan001.com 执行以下命令:
./ngrok -config=./ngrok.cfg -subdomain=test 80
解释一下参数:
-config 就是上面配置文件ngrok.cfg的路径
-subdomain 就是需要分配域名的前缀部分
80 就是本机websever的端口,比如apache监听的端口,一会ngrok会将请求映射到该端口上。
如果没错误,应该会出现以下的输出:
Tunnel Status                 online
Version                       1.7/1.7
Forwarding                    http://test.ngrok.ekan001.com:8000 -> 127.0.0.1:80
Forwarding                    https://test.ngrok.ekan001.com:8000 -> 127.0.0.1:80
Web Interface                 127.0.0.1:4040
# Conn                        0
Avg Conn Time                 0.00ms
现在,访问 test.ngrok.ekan001.com:8000 ,ngrok服务端就会讲请求转发到我们本地客户端,再由客户端转发给我们的webserver 80端口。所以,我们只需要配置apache或nginx,添加虚拟主机,绑定域名 test.ngrok.ekan001.com 即可。
事情还没有结束!
我们前面提到,微信开发中的api地址,是不认80以外的端口的,所以如果我们将 test.ngrok.ekan001.com:8000 作为接口域名,得到的只能是 非法地址 或 配置失败 这个提示。
为什么在启动服务端的时候,端口不指定为80呢?就像下面:
bin/ngrokd -domain="$NGROK_DOMAIN" -httpAddr=":80"
很遗憾,因为这台vps不是只用来做ngrok服务的,我博客还在上面呢,80端口已经被nginx占用了。
那怎么办?
不得不提nginx是个牛逼的软件,我们可以在nginx中配置一个server,就绑定 test.ngrok.ekan001.com 域名,然后将所有请求转发到后端 :8000 端口上,这就是反向代理。我发一下自己的nginx配置:
#ngrok.ekan001.com.conf
upstream nodejs {
    server 127.0.0.1:8000;
    keepalive 64;
}

server {
    listen 80;
    server_name *.ngrok.ekan001.com;
    access_log /home/wwwlogs/ngrok.ekan001.log;
    location / {
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host  $http_host:8000;
        proxy_set_header X-Nginx-Proxy true;
        proxy_set_header Connection "";
        proxy_pass      http://nodejs;

    }

}
总结:
生命在于折腾,enjoy it!
--------------------------------------------

通过ngrok把本地Web app映射到外网

背景

开发第三方支付, 需要接收第三方回调(即在外网上暴露api), 发现ngrok可以完成该业务, 下面具体介绍其使用.

下载并运行

下载

解压

  • unzip ngrok_2.0.19_darwin_amd64.zip -d /path/to/ngrok

运行

  • cd /path/to/ngrok
  • ngrok -h

映射本地端口

  • ngrok http 8080(映射本地8080端口到外网)





1
2
3
4
5
6
7
8
9
10
11

ngrok by @inconshreveable                                       (Ctrl+C to quit)
                                                                                
Tunnel Status                 online                                            
Version                       2.0.19/2.0.19                                     
Web Interface                 http://127.0.0.1:4040                             
Forwarding                    http://430ca81c.ngrok.io -> localhost:8080        
Forwarding                    https://430ca81c.ngrok.io -> localhost:8080       
                                                                                
Connections                   ttl     opn     rt1     rt5     p50     p90       
                              0       0       0.00    0.00    0.00    0.00

可以通过http://127.0.0.1:4040登录控制台查看配置等参数.

付费功能

ngrok自动映射的subDomain是随机的, 关闭重启将改变, 可升级为付费用户自定义subDomain, 详情见高级特性.

服务被墙了怎么办

自建Tunnel

国内有位工程师搭了个服务, 开箱即用

使用步骤:





1
2
例如 ngrok -config ngrok.cfg -subdomain example 8080
意为将本地的8080端口链接到example.tunnel.mobi

  • 更多使用技巧,可见文档
-----------------------------------------------

搭建自己的ngrok服务


在国内开发微信公众号企业号以及做前端开发的朋友想必对ngrok都不陌生吧,就目前来看,ngrok可是最佳的在内网调试微信服务的tunnel工 具。记得今年春节前,ngrok.com提供的服务还一切正常呢,但春节后似乎就一切不正常了。ngrok.com无法访问,ngrok虽然能连上 ngrok.com提供的服务,但微信端因为无法访问ngrok.com,导致消息一直无法发送到我们的服务地址上,比如xxxx.ngrok.com。 这一切都表明,ngork被墙了。没有了ngrok tunnel,一切开始变得困难且没有效率起来。内网到外部主机部署和调试是一件慢的让人想骂街的事情。
ngrok不能少。ngrok以及其服务端ngrokd都是开源的,之前我也知道通过源码可以自搭建ngrok服务。请求搜索引擎后,发现国内有个朋友已经搭建了一个www.tunnel.mobi的ngrok公共服务,与ngrok.com类似,我也实验了一下。
编写一个ngrok.cfg,内容如下:
server_addr: "tunnel.mobi:44433"
trust_host_root_certs: true
用ngrok最新客户端1.7版本执行如下命令:
$ngrok -subdomain tonybaiexample -config=ngrok.cfg 80
可以顺利建立一个tunnel,用于本机向外部提供"tonybaiexample.tunnel.mobi"服务。
Tunnel Status                 online
Version                       1.7/1.7
Forwarding                    http://tonybaiexample.tunnel.mobi -> 127.0.0.1:80
Forwarding                    https://tonybaiexample.tunnel.mobi -> 127.0.0.1:80
Web Interface                 127.0.0.1:4040
# Conn                        0
Avg Conn Time                 0.00ms
而且国内的ngrok服务显然要远远快于ngrok.com提供的服务,消息瞬间即达。
但这是在公网上直接访问的结果。放在公司内部,我看到的却是另外一个结果:
Tunnel Status                 reconnecting
Version                       1.7/
Web Interface                 127.0.0.1:4040
# Conn                        0
Avg Conn Time                 0.00ms
我们无法从内网建立tunnel,意味着依旧不方便和低效,因为很多基础服务都在内网部署,内外网之间的交互十分不便。但内网连不上tunnel.mobi也是个事实,且无法知道原因,因为看不到server端的连接错误日志。
于是我决定自建一个ngrok服务。
一、准备工作
搭建ngrok服务需要在公网有一台vps,去年年末曾经在Amazon申请了一个体验主机EC2,有公网IP一个,这次就打算用这个主机作为ngrokd服务端。
需要一个自己的域名。已有域名的,可以建立一个子域名,用于关联ngrok服务,这样也不会干扰原先域名提供的服务。(不用域名的方式也许可以,但我没有试验过。)
搭建的参考资料主要来自下面三个:
1) ngrok的官方SELFHOST指南:https://github.com/inconshreveable/ngrok/blob/master/docs/SELFHOSTING.md
2) 国外一哥们的博客:http://www.svenbit.com/2014/09/run-ngrok-on-your-own-server/
3) "海运的博客"中的一篇文章:http://www.haiyun.me/archives/1012.html
二、实操步骤
我的AWS EC2实例安装的是Ubuntu Server 14.04 x86_64,并安装了golang 1.4(go version go1.4 linux/amd64)。Golang是编译ngrokd和ngrok所必须的,建议直接从golang官方下载对应平台的二进制安装包(国内可以从 golangtc.com上下载,速度慢些罢了)。
1、下载ngrok源码
(GOPATH=~/goproj)
$ mkdir ~/goproj/src/github.com/inconshreveable
$ git clone https://github.com/inconshreveable/ngrok.git
$ export GOPATH=~/goproj/src/github.com/inconshreveable/ngrok
2、生成自签名证书
使用ngrok.com官方服务时,我们使用的是官方的SSL证书。自建ngrokd服务,我们需要生成自己的证书,并提供携带该证书的ngrok客户端。
证书生成过程需要一个NGROK_BASE_DOMAIN。 以ngrok官方随机生成的地址693c358d.ngrok.com为例,其NGROK_BASE_DOMAIN就是"ngrok.com",如果你要 提供服务的地址为"example.tunnel.tonybai.com",那NGROK_BASE_DOMAIN就应该 是"tunnel.tonybai.com"。
我们这里以NGROK_BASE_DOMAIN="tunnel.tonybai.com"为例,生成证书的命令如下:
$ cd ~/goproj/src/github.com/inconshreveable/ngrok
$ openssl genrsa -out rootCA.key 2048
$ openssl req -x509 -new -nodes -key rootCA.key -subj "/CN=
tunnel.tonybai.com" -days 5000 -out rootCA.pem
$ openssl genrsa -out device.key 2048
$ openssl req -new -key device.key -subj "/CN=
tunnel.tonybai.com" -out device.csr
$ openssl x509 -req -in device.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out device.crt -days 5000
执行完以上命令,在ngrok目录下就会新生成6个文件:
-rw-rw-r– 1 ubuntu ubuntu 1001 Mar 14 02:22 device.crt
-rw-rw-r– 1 ubuntu ubuntu  903 Mar 14 02:22 device.csr
-rw-rw-r– 1 ubuntu ubuntu 1679 Mar 14 02:22 device.key
-rw-rw-r– 1 ubuntu ubuntu 1679 Mar 14 02:21 rootCA.key
-rw-rw-r– 1 ubuntu ubuntu 1119 Mar 14 02:21 rootCA.pem
-rw-rw-r– 1 ubuntu ubuntu   17 Mar 14 02:22 rootCA.srl
ngrok通过bindata将ngrok源码目录下的assets目录(资源文件)打包到可执行文件(ngrokd和ngrok)中 去,assets/client/tls和assets/server/tls下分别存放着用于ngrok和ngrokd的默认证书文件,我们需要将它们替换成我们自己生成的:(因此这一步务必放在编译可执行文件之前)
cp rootCA.pem assets/client/tls/ngrokroot.crt
cp device.crt assets/server/tls/snakeoil.crt
cp device.key assets/server/tls/snakeoil.key
3、编译ngrokd和ngrok
在ngrok目录下执行如下命令,编译ngrokd:
$ make release-server
不过在我的AWS上,出现如下错误:
GOOS="" GOARCH="" go get github.com/jteeuwen/go-bindata/go-bindata
bin/go-bindata -nomemcopy -pkg=assets -tags=release \
        -debug=false \
        -o=src/ngrok/client/assets/assets_release.go \
        assets/client/…
make: bin/go-bindata: Command not found
make: *** [client-assets] Error 127
go-bindata被安装到了$GOBIN下了,go编译器找不到了。修正方法是将$GOBIN/go-bindata拷贝到当前ngrok/bin下。
$ cp /home/ubuntu/.bin/go14/bin/go-bindata ./bin
再次执行make release-server。
~/goproj/src/github.com/inconshreveable/ngrok$ make release-server
bin/go-bindata -nomemcopy -pkg=assets -tags=release \
        -debug=false \
        -o=src/ngrok/client/assets/assets_release.go \
        assets/client/…
bin/go-bindata -nomemcopy -pkg=assets -tags=release \
        -debug=false \
        -o=src/ngrok/server/assets/assets_release.go \
        assets/server/…
go get -tags 'release' -d -v ngrok/…
code.google.com/p/log4go (download)
go: missing Mercurial command. See http://golang.org/s/gogetcmd
package code.google.com/p/log4go: exec: "hg": executable file not found in $PATH
github.com/gorilla/websocket (download)
github.com/inconshreveable/go-update (download)
github.com/kardianos/osext (download)
github.com/kr/binarydist (download)
github.com/inconshreveable/go-vhost (download)
github.com/inconshreveable/mousetrap (download)
github.com/nsf/termbox-go (download)
github.com/mattn/go-runewidth (download)
github.com/rcrowley/go-metrics (download)
Fetching https://gopkg.in/yaml.v1?go-get=1
Parsing meta tags from https://gopkg.in/yaml.v1?go-get=1 (status code 200)
get "gopkg.in/yaml.v1": found meta tag main.metaImport{Prefix:"gopkg.in/yaml.v1", VCS:"git", RepoRoot:"https://gopkg.in/yaml.v1"} at https://gopkg.in/yaml.v1?go-get=1
gopkg.in/yaml.v1 (download)
make: *** [deps] Error 1
又出错!提示找不到hg,原来是aws上没有安装hg。install hg后(sudo apt-get install mercurial),再编译。
$ make release-server
bin/go-bindata -nomemcopy -pkg=assets -tags=release \
        -debug=false \
        -o=src/ngrok/client/assets/assets_release.go \
        assets/client/…
bin/go-bindata -nomemcopy -pkg=assets -tags=release \
        -debug=false \
        -o=src/ngrok/server/assets/assets_release.go \
        assets/server/…
go get -tags 'release' -d -v ngrok/…
code.google.com/p/log4go (download)
go install -tags 'release' ngrok/main/ngrokd
同样编译ngrok:
$ make release-client
bin/go-bindata -nomemcopy -pkg=assets -tags=release \
        -debug=false \
        -o=src/ngrok/client/assets/assets_release.go \
        assets/client/…
bin/go-bindata -nomemcopy -pkg=assets -tags=release \
        -debug=false \
        -o=src/ngrok/server/assets/assets_release.go \
        assets/server/…
go get -tags 'release' -d -v ngrok/…
go install -tags 'release' ngrok/main/ngrok
AWS上ngrokd和ngrok被安装到了$GOBIN下。
三、调试
1、启动ngrokd
$ ngrokd -domain="tunnel.tonybai.com" -httpAddr=":8080" -httpsAddr=":8081"
[03/14/15 04:47:24] [INFO] [registry] [tun] No affinity cache specified
[03/14/15 04:47:24] [INFO] [metrics] Reporting every 30 seconds
[03/14/15 04:47:24] [INFO] Listening for public http connections on [::]:8080
[03/14/15 04:47:24] [INFO] Listening for public https connections on [::]:8081
[03/14/15 04:47:24] [INFO] Listening for control and proxy connections on [::]:4443

… …
2、公网连接ngrokd
将生成的ngrok下载到自己的电脑上。
创建一个配置文件ngrok.cfg,内容如下:
server_addr: "tunnel.tonybai.com:4443"
trust_host_root_certs: false
执行ngrok:
$ ngrok -subdomain example -config=ngrok.cfg 80
Tunnel Status                 reconnecting
Version                       1.7/
Web Interface                 127.0.0.1:4040
# Conn                        0
Avg Conn Time                 0.00ms
连接失败。此刻我的电脑是在公网上。查看ngrokd的日志,没有发现连接到达Server端。试着在本地ping tunnel.tonybai.com这个地址,发现地址不通。难道是DNS设置的问题。之前我只是设置了"*.tunnel.tonybai.com"的A地址,并未设置"tunnel.tonybai.com"。于是到DNS管理页面,添加了"tunnel.tonybai.com"的A记录。
待DNS记录刷新OK后,再次启动ngrok:
Tunnel Status online
Version 1.7/1.7
Forwarding http://epower.tunnel.tonybai.com:8080 -> 127.0.0.1:80
Forwarding https://epower.tunnel.tonybai.com:8080 -> 127.0.0.1:80
Web Interface 127.0.0.1:4040
# Conn 0
Avg Conn Time 0.00ms
这回连接成功了!
3、内网连接ngrokd
将ngrok拷贝到内网的一台PC上,这台PC设置了公司的代理。
按照同样的步骤启动ngrok:
$ ngrok -subdomain example -config=ngrok.cfg 80
Tunnel Status                 reconnecting
Version                       1.7/
Web Interface                 127.0.0.1:4040
# Conn                        0
Avg Conn Time                 0.00ms
不巧,怎么又失败了!从Server端来看,还是没有收到客户端的连接,显然是连接没有打通公司内网。从我自己的squid代理服务器来看,似乎只有443端口的请求被公司代理服务器允许通过,4443则无法出去。
1426301143.558 9294 10.10.126.101 TCP_MISS/000 366772 CONNECT api.equinox.io:443 – DEFAULT_PARENT/proxy.xxx.com -   通过了
1426301144.441 27 10.10.126.101 TCP_MISS/000 1185 CONNECT tunnel.tonybai.com:4443 – DEFAULT_PARENT/proxy.xxx.com -  似乎没有通过
只能修改server监听端口了。将-tunnelAddr由4443改为443(注意AWS上需要修改防火墙的端口规则,这个是实时生效的,无需重启实例):
$ sudo ngrokd -domain="tunnel.tonybai.com" -httpAddr=":8080" -httpsAddr=":8081" -tunnelAddr=":443"
[03/14/15 04:47:24] [INFO] [registry] [tun] No affinity cache specified
[03/14/15 04:47:24] [INFO] [metrics] Reporting every 30 seconds
[03/14/15 04:47:24] [INFO] Listening for public http connections on [::]:8080
[03/14/15 04:47:24] [INFO] Listening for public https connections on [::]:8081
[03/14/15 04:47:24] [INFO] Listening for control and proxy connections on [::]:443

… …
将ngrok.cfg中的地址改为443:
server_addr: "tunnel.tonybai.com:443"
再次执行ngrok客户端:
Tunnel Status                 online
Version                       1.7/1.7
Forwarding                    http://epower.tunnel.tonybai.com:8080 -> 127.0.0.1:80
Forwarding                    https://epower.tunnel.tonybai.com:8080 -> 127.0.0.1:80
Web Interface                 127.0.0.1:4040
# Conn                        0
Avg Conn Time                 0.00ms
这回成功连上了。
4、80端口
是否大功告成了呢?我们看看ngrok的结果,总感觉哪里不对呢?噢,转发的地址怎么是8080端口呢?为何不是80?微信公众号/企业号可只是支持80端口啊!
我们还需要修改一下Server端的参数,将-httpAddr从8080改为80。
$ sudo ngrokd -domain="tunnel.tonybai.com" -httpAddr=":80" -httpsAddr=":8081" -tunnelAddr=":443"
这回再用ngrok连接一下:
Tunnel Status                 online
Version                       1.7/1.7
Forwarding                    http://epower.tunnel.tonybai.com -> 127.0.0.1:80
Forwarding                    https://epower.tunnel.tonybai.com -> 127.0.0.1:80
Web Interface                 127.0.0.1:4040
# Conn                        0
Avg Conn Time                 0.00ms
这回与我们的需求匹配上了。
5、测试
在内网的PC上建立一个简单的http server 程序:hello
//hello.go
package main
import "net/http"
func main() {
    http.HandleFunc("/", hello)
    http.ListenAndServe(":80", nil)
}
func hello(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("hello!"))
}
$ go build -o hello hello.go
$ sudo ./hello
通过公网浏览器访问一下“http://epower.tunnel.tonybai.com”这个地址,如果你看到浏览器返回"hello!"字样,那么你的ngrokd服务就搭建成功了!
四、注意事项
客户端ngrok.cfg中server_addr后的值必须严格与-domain以及证书中的NGROK_BASE_DOMAIN相同,否则Server端就会出现如下错误日志:
[03/13/15 09:55:46] [INFO] [tun:15dd7522] New connection from 54.149.100.42:38252
[03/13/15 09:55:46] [DEBG] [tun:15dd7522] Waiting to read message
[03/13/15 09:55:46] [WARN] [tun:15dd7522] Failed to read message: remote error: bad certificate
[03/13/15 09:55:46] [DEBG] [tun:15dd7522] Closing.
from http://tonybai.com/2015/03/14/selfhost-ngrok-service/
-------------

ngrok - Introspected tunnels to localhost (homepage)

”I want to expose a local server behind a NAT or firewall to the internet.”

What is ngrok?

ngrok is a reverse proxy that creates a secure tunnel from a public endpoint to a locally running web service. ngrok captures and analyzes all traffic over the tunnel for later inspection and replay.

ngrok 2.x

ngrok 2.x is the successor to 1.x and the focus of all current development effort. Its source code is not available.
NOTE This repository contains the code for ngrok 1.x.

Status of the ngrok 1.x project

ngrok 1.x is no longer developed, supported or maintained by its author, except to ensure that the project continues to compile. The contribution policy has the following guidelines:
  1. All issues against this repository will be closed unless they demonstrate a crash or other complete failure of ngrok's functionality.
  2. All issues against this repository are for 1.x only, any issues for 2.x will be closed.
  3. No new features will be added. Any pull requests with new features will be closed. Please fork the project instead.
  4. Pull requests fixing existing bugs or improving documentation are welcomed.

The ngrok 1.x hosted service

ngrok.com ran a pay-what-you-want hosted service of 1.x from early 2013 until April 7, 2016. Afterwards, it only runs 2.x service.

Production Use

DO NOT RUN THIS VERSION OF NGROK (1.X) IN PRODUCTION. Both the client and server are known to have serious reliability issues including memory and file descriptor leaks as well as crashes. There is also no HA story as the server is a SPOF. You are advised to run 2.0 for any production quality system. 

What can I do with ngrok?

  • Expose any http service behind a NAT or firewall to the internet on a subdomain of ngrok.com
  • Expose any tcp service behind a NAT or firewall to the internet on a random port of ngrok.com
  • Inspect all http requests/responses that are transmitted over the tunnel
  • Replay any request that was transmitted over the tunnel

What is ngrok useful for?

  • Temporarily sharing a website that is only running on your development machine
  • Demoing an app at a hackathon without deploying
  • Developing any services which consume webhooks (HTTP callbacks) by allowing you to replay those requests
  • Debugging and understanding any web service by inspecting the HTTP traffic
  • Running networked services on machines that are firewalled off from the internet

Developing on ngrok



from  https://github.com/inconshreveable/ngrok
-------------

内网穿透利器-ngrok服务器搭建

有时候我们会需要将内网的网站发给外网用户查看,或者通过外网管理家里的电脑上运行的某些软件。这些需求通常可以通过配置路由器的端口转发来实现,但是有些网络服务商并不给用户提供外网IP地址,于是就有了一些内网穿透的方法,比如:花生壳、n2n。

今天在这里推荐一个非常好用的内网穿透软件ngrok。ngrok 是一个反向代理,通过在公共的端点和本地运行的 Web 服务器之间建立一个安全的通道。ngrok 可捕获和分析所有通道上的流量,便于后期分析和重放。(来自百度百科)

编译Ngrok

1.安装配置Golang环境:  
yum install golang

也可以自己配置:Linux下配置Golang环境

2.安装必要的工具
   
yum install -y make mercurial git

3.下载ngrok源码  
git clone https://github.com/inconshreveable/ngrok.git

4.生成自己的证书:
   
cd ngrok
NGROK_DOMAIN="ngrok.kuoruan.com"
openssl genrsa -out base.key 2048
openssl req -new -x509 -nodes -key base.key -days 10000 -subj "/CN=$NGROK_DOMAIN" -out base.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 base.pem -CAkey base.key -CAcreateserial -days 10000 -out server.crt

目录下会生成6个文件:
   
-rw-r--r-- 1 root root  997 May 24 21:05 server.crt
-rw-r--r-- 1 root root   17 May 24 21:05 base.srl
-rw-r--r-- 1 root root  903 May 24 21:05 server.csr
-rw-r--r-- 1 root root 1675 May 24 21:05 server.key
-rw-r--r-- 1 root root 1115 May 24 21:05 base.pem
-rw-r--r-- 1 root root 1675 May 24 21:05 base.key

然后将生成的文件替换掉 ngrok 的默认证书:
   
cp base.pem assets/client/tls/ngrokroot.crt
cp server.crt assets/server/tls/snakeoil.crt
cp server.key assets/server/tls/snakeoil.key

5.开始编译
   
make release-server release-client

可能会出现错误,找不到go-bindata:
   
go fmt ngrok/...
GOOS="" GOARCH="" go get github.com/jteeuwen/go-bindata/go-bindata
bin/go-bindata -nomemcopy -pkg=assets -tags=debug \
  -debug=true \
  -o=src/ngrok/client/assets/assets_debug.go \
  assets/client/...
make: bin/go-bindata: Command not found

解决方案是拷贝 go/bin 目录下的 go-bindata 到 ngrok/bin:
mkdir bin
cp /usr/local/go/bin/go-bindata bin/

6.编译成功之后,可以在 ngrok 下的 bin 中找到 ngrok ngrokd 两个文件,如果没有,请查看 go/bin 目录。
运行服务端:  
./bin/ngrokd -tlsKey=server.key -tlsCrt=server.crt -domain="ngrok.kuoruan.com" -httpAddr=":8081" -httpsAddr=":8082"

会有如下输出:
   
[21:28:58 CST 2016/05/24] [INFO] (ngrok/log.(*PrefixLogger).Info:83) [registry] [tun] No affinity cache specified
[21:28:58 CST 2016/05/24] [INFO] (ngrok/log.Info:112) Listening for public http connections on [::]:8081
[21:28:58 CST 2016/05/24] [INFO] (ngrok/log.Info:112) Listening for public https connections on [::]:8082
[21:28:58 CST 2016/05/24] [INFO] (ngrok/log.Info:112) Listening for control and proxy connections on [::]:4443
[21:28:58 CST 2016/05/24] [INFO] (ngrok/log.(*PrefixLogger).Info:83) [metrics] Reporting every 30 seconds

8081是http的访问端口,8082是https的访问端口。

如果想要后台运行:
nohup ./bin/ngrokd -tlsKey=server.key -tlsCrt=server.crt -domain="ngrok.kuoruan.com" -httpAddr=":8081" -httpsAddr=":8082" &

如果需要停止服务:  
ps -A
21902 pts/0    00:00:00 ngrokd
kill PID

现在访问:http://ngrok.kuoruan.com:8081 会显示 :
   
Tunnel ngrok.kuoruan.com:8081 not found

客户端

bin目录下的 ngrok 就是客户端文件,可以直接放到Linux下运行。如果需要在Windows下运行,需要重新编译。
   
GOOS=windows GOARCH=amd64 make release-client

然后就能看到 bin/windows_amd64 下生成的 ngrok.exe 文件,将exe文件下载到本地。

新建一个配置文件:
   
server_addr: ngrok.kuoruan.com:4443
trust_host_root_certs: false

然后在Windows CMD运行:  
ngrok -proto=http -config=ngrok.cfg -subdomain test 80

1.指定子域、要转发的协议和端口,以及配置文件,运行客户端

2.注意:如果不加参数-subdomain=test,将会随机自动分配子域名。

然后外网就可以通过 http://test.ngrok.kuoruan.com:8081 访问到本地的网站了.
-------------------

部署ngrok

什么是Ngrok

Ngrok是一款用go语言开发的开源软件,它是一个反向代理。通过在公共的端点和本地运行的Web服务器之间建立一个安全的通道。Ngrok可捕获和分析所有通道上的流量,便于后期分析和重放。

应用场景

用于对处在内网环境中,无外网IP的计算机的远程连接。
Ngrok可以做TCP端口转发,对于Linux可以将其映射到22端口进行SSH连接。Windows的远程桌面可以将其映射到3389端口来实现。同理,如果要做MySQL的远程连接,只需映射3306端口即可。
用作临时搭建网站并分配二级域名,可用作微信二次开发的本地调试。
微信公众平台二次开发时,服务器必须要能通过外网访问,而且必须是80接口。我们一般会在自己的电脑上写代码,但是由于电信运营商将80端口屏蔽 了,甚至很多人通过无线路由器上网,根本就没有公网ip。在这种情况下,我们每次都要上传代码到服务器对微信公众平台进行接口调试,十分的不方便。而 Ngrok可以将内网映射到一个公网地址,这样就完美的解决了我们的问题。
Ngrok官方为我们免费提供了一个服务器,我们只需要下载Ngrok客户端即可正常使用,但是后来官方的服务越来越慢,直到Ngrok官网被完全 屏蔽。现在我们已经无法使用ngrok官方的服务器了。所以,接下来我们自行搭建属于自己的ngrok服务器,为自己提供方便快捷又稳定的服务,一劳永 逸。
注意:ngrok.com 提供的服务是基于 ngrok 2.0,github 上目前只有 1.0 的源码,二者功能和命令有一些区别,用的时候别搞混了

编译ngrok

安装go get工具




1
2
3
4
5
6
7
8
#ubuntu
apt-get install build-essential golang mercurial git

#centos
yum install mercurial git bzr subversion  golang

#git版本需要在1.7.9.5以上,如果不符合条件需要将git版本升级。
yum --disablerepo=base,updates --enablerepo=rpmforge-extras update git

获取ngrok源码




1
2
3
4
5
6
7
8
9
10
11
12
13
14
GOPATH=~/goproj
mkdir ~/goproj/src/github.com/inconshreveable
cd ~/goproj/src/github.com/inconshreveable
#官方地址编译时要报错
git clone https://github.com/inconshreveable/ngrok.git
#请使用下面的地址,修复了无法访问的包地址
git clone https://github.com/tutumcloud/ngrok.git ngrok
export GOPATH=~/goproj/src/github.com/inconshreveable/ngrok

修改源代码中库引用的错误
由于google code的关闭,所以我们要把作者代码中的库引用地址修改一下
修改src/ngrok/log/logger.go文件
log "code.google.com/p/log4go" 改为log "github.com/alecthomas/log4go"
注:最新github.com上的代码这个问题已修复

生成自签名证书

使用ngrok.com官方服务时,我们使用的是官方的SSL证书。自建ngrokd服务,我们需要生成自己的证书,并提供携带该证书的ngrok客户端。生成并替换源码里默认的证书,注意域名修改为你自己的。(之后编译出来的服务端客户端会基于这个证书来加密通讯,保证了安全性)
证书生成过程需要一个NGROK_DOMAIN。以ngrok官方随机生成的地址693c358d.ngrok.com为例,其NGROK_DOMAIN就是”ngrok.com”,如果你要提供服务的地址为”example.tunnel.imike.me”,那NGROK_BASE_DOMAIN就应该是”tunnel.imike.me”。



1
2
3
4
5
6
7
cd ngrok
NGROK_DOMAIN="tunnel.imike.me"
openssl genrsa -out base.key 2048
openssl req -new -x509 -nodes -key base.key -days 10000 -subj "/CN=$NGROK_DOMAIN" -out base.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 base.pem -CAkey base.key -CAcreateserial -days 10000 -out server.crt
执行完以上命令,在ngrok目录下就会新生成6个文件



1
2
3
4
5
6
7
8
ls -lt                           
总用量 56
-rw-r--r-- 1 root root  973 3月  23 11:23 server.crt
-rw-r--r-- 1 root root   17 3月  23 11:23 base.srl
-rw-r--r-- 1 root root  891 3月  23 11:23 server.csr
-rw-r--r-- 1 root root 1675 3月  23 11:23 server.key
-rw-r--r-- 1 root root 1115 3月  23 11:23 base.pem
-rw-r--r-- 1 root root 1679 3月  23 11:23 base.key
Ngrok通过bindata将ngrok源码目录下的assets目录(资源文件)打包到可执行文件(ngrokd和ngrok)中去,assets/client/tls和assets/server/tls下分别存放着用于ngrok和ngrokd的默认证书文件,我们需要将它们替换成我们自己生成的(因此这一步务必放在编译可执行文件之前)



1
2
3
cp base.pem assets/client/tls/ngrokroot.crt
cp server.crt assets/server/tls/snakeoil.crt
cp server.key assets/server/tls/snakeoil.key

编译Linux服务端和客户端




1
make release-server release-client
编译之后,就会在ngrok源码的bin目录下生成两个可执行文件:ngrokd、ngrok。其中ngrokd就是ngrok的服务端程序,ngrok就是ngrok的客户端程序。

编译Linux客户端




1
make release-client

编译window版本客户端

上述编译过程生成的服务端和客户端都是linux下的,不能在windows下用。如果想编译生成windows客户端,需要重新配置环境并编译。交叉编译过程如下:



1
2
3
4
5
6
7
进入go目录,进行环境配置
cd  /usr/local/go/src/
GOOS=windows GOARCH=amd64 CGO_ENABLED=0 ./make.bash  
进入ngrok目录重新编译
GOOS=windows GOARCH=amd64 make release-client
编译后,就会在bin目录下生成windows_amd64目录,其中就包含着windows下运行的服务器和客户端程序。
#以上GOARCH=amd64指的是编译为64位版本,如需32位改成GOARCH=386即可

编译arm客户端




1
2
3
cd /usr/lib/golang/src/
sudo GOOS=linux GOARCH=arm CGO_ENABLED=0 ./make.bash
sudo GOOS=linux GOARCH=arm make release-client

编译mac版本客户端




1
GOOS=darwin GOARCH=amd64 make  release-client

设置域名解析

添加两条A记录:tunnel.imike.me和*.tunnel.imike.me,指向所在的Ngrok服务器ip。

运行Ngrok

服务端启动

指定证书、域名和端口启动它(证书就是前面生成的,注意修改域名)



1
2
3
4
5
6
./bin/ngrokd -tlsKey=server.key -tlsCrt=server.crt -domain="tunnel.imike.me" -httpAddr=":8081" -httpsAddr=":8082"
[14:54:30 CST 2016/03/23] [INFO] (ngrok/log.(*PrefixLogger).Info:83) [registry] [tun] No affinity cache specified
[14:54:30 CST 2016/03/23] [INFO] (ngrok/log.(*PrefixLogger).Info:83) [metrics] Reporting every 30 seconds
[14:54:30 CST 2016/03/23] [INFO] (ngrok/log.Info:112) Listening for public http connections on [::]:8081
[14:54:30 CST 2016/03/23] [INFO] (ngrok/log.Info:112) Listening for public https connections on [::]:8082
[14:54:30 CST 2016/03/23] [INFO] (ngrok/log.Info:112) Listening for control and proxy connections on [::]:4443
到这一步,ngrok 服务已经跑起来了,可以通过屏幕上显示的日志查看更多信息。httpAddr、httpsAddr 分别是ngrok用来转发http、https服务的端口,可以随意指定。ngrokd还会开一个4443端口用来跟客户端通讯(可通过-tunnelAddr=”:xxx” 指定),如果你配置了iptables 规则,需要放行这三个端口上的TCP协议。
现在通过http://tunnel.imike.me:8081https://tunnel.imike.me:8082就可以访问到ngrok提供的转发服务。

设置开机自动启动ngrok服务




1
2
3
4
vim /etc/init.d/ngrok_start:
cd /root/goproj/src/github.com/inconshreveable
./bin/ngrokd -tlsKey=server.key -tlsCrt=server.crt -domain="tunnel.imike.me" -httpAddr=":8081" -httpsAddr=":8082"
chmod 755 /etc/init.d/ngrok_start

客户端启动

使用默认配置文件启动
对默认设置文件 ~/.ngrok 进行编辑:



1
2
3
4
5
6
7
8
9
10
11
12
server_addr: tunnel.imike.me:4443
trust_host_root_certs: false
tunnels:
    #http:subdomain: "test"
    web:
        #auth: "AuthUser:AuthPassWord"
        proto:
            http: 80
    ssh:
        remote_port: 12222
        proto:
            tcp: 22
从命令行运行:



1
./bin/ngrok start web ssh
当客户端使用http/https协议连接,可指定一个二级域名,服务端会分配该二级域名给客户端作为入口,比如web.tunnel.imike.me;
当客户端使用tcp 协议连接,则服务端不会分配二级域名,改为监控一个随机端口,比如 tunnel.imike.me:12345,remote_port可由客户端对该端口进行指定,比如tunnel.imike.me:12222。
使用自定义配置文件
创建一个配置文件ngrok.cfg,内容如下:



1
2
3
vim ngrok.cfg:
server_addr: tunnel.imike.me:4443
trust_host_root_certs: false

映射HTTP



1
2
3
4
5
6
7
8
9
10
11
12
13
14
#启动ngrok客户端
#指定子域、要转发的协议和端口,以及配置文件,运行客户端:
#注意:如果不加参数-subdomain=test,将会随机自动分配子域名。
./bin/ngrok -subdomain web -proto=http -config=ngrok.cfg 80

#客户端ngrok正常执行显示的内容
ngrok                                                  (Ctrl+C to quit)

Tunnel Status     online
Version           1.7/1.7
Forwarding        http://web.tunnel.imike.me:8081 -> 127.0.0.1:80
Web Interface     127.0.0.1:4040
# Conn            0
Avg Conn Time     0.00ms
打开浏览器,分别在地址栏中输入http://localhosthttp://web.tunnel.imike.me:8081,如果后者正常显示并且和http://localhost显示的内容相同,则证明我们已经成功了。
映射TCP
有时候,我们使用远程桌面功能,或者在linux中进行SSH连接,对于处在内网环境中的计算机,我们可以对该端口进行TCP映射。



1
2
3
4
5
6
7
8
9
10
11
12
13
#这里以SSH连接Linux时的22端口为例
./bin/ngrok -config=ngrok.cfg -proto=tcp 22
映射成功的话,会显示如下内容:
#客户端ngrok正常执行显示的内容

ngrok                                                  (Ctrl+C to quit)

Tunnel Status     online
Version           1.7/1.7
Forwarding        tcp://imike.me:12222 -> 127.0.0.1:22
Web Interface     127.0.0.1:4040
# Conn            0
Avg Conn Time     0.00ms
现在,在putty等ssh工具中即可连接imike.me。切记端口是号12222,是随机分配的一个端口号,而不是默认的22端口了。Windows的远程桌面可以将其映射到3389端口来实现。同理,如果要做MySQL的远程连接,只需映射3306端口即可。FTP可映射21端口。
注意:客户端必须使用自己编译的ngrok文件

管理界面

Ngrok客户端运行后,有一个Web Interface地址,这是ngrok 提供的监控界面。通过这个界面可以看到远端转发过来的http 详情,包括完整的request/response 信息,可以不刷新页面通过replay按钮重新发出请求,非常方便。
访问管理界面:http://127.0.0.1:4040

后续定制及优化

通过以上操作,我们的ngrok服务器就已经成功搭建了,客户端也成功的跑了起来。但是,如果我们想要对ngrok进行一些定制和优化,可以参考这些后续定制及优化的方法。

为什么在启动服务端的时候,端口不指定为80

很遗憾,因为这台vps不是只用来做ngrok服务的,我博客还在上面呢,80端口已经被nginx占用了。
那怎么办?不得不提nginx是个牛逼的软件,我们可以在nginx中配置一个server,就绑定web.tunnel.imike.me域名,然后将所有请求转发到后端:8081端口上,这就是反向代理。我发一下自己的nginx配置:



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#ngrok.imike.me.conf
upstream ngrok {
    server 127.0.0.1:8000;
    keepalive 64;
}

server {
    listen 80;
    server_name *.tunnel.imike.me;
    access_log /var/log/nginx/ngrok_access.log;
    location / {
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host  $http_host:8081;
        proxy_set_header X-Nginx-Proxy true;
        proxy_set_header Connection "";
        proxy_pass      http://ngrok;

    }

}

修改客户端ngrok默认服务地址

客户端每次还需要加载配置文件,这样显得有些麻烦。能不能像官方服务那样直接执行命令 ngrok 80就能使用呢?我们只需要在编译客户端之前,稍作修改即可。同样,如果需要指定域名可以执行命令 ngrok -subdomain=test 80来运行客户端。

修改默认服务地址




1
2
3
vim ./src/ngrok/client/model.go
找到第23行,将 defaultServerAddr = "ngrokd.ngrok.com:443"
修改为defaultServerAddr = "tunnel.mydomain:4443" 即可。

运行客户端后,我们会发现在客户端左上角会有一个蓝色字体的”ngrok”字样的文字logo,如果觉得不太喜欢,或者想修改一下的话,可以在编译客户端之前,作如下修改。



1
2
3
4
5
6
Vim ./src/ngrok/client/views/term/view.go
找到第100行,将
v.APrintf(termbox.ColorBlue|termbox.AttrBold, 0, 0, "ngrok")
修改为
v.APrintf(termbox.ColorBlue|termbox.AttrBold, 0, 0, "your logo")
即可。

修改客户端帮助信息

Ngrok客户端默认的帮助信息很少,我们可以在编译客户端之前,自己定制帮助内容。

修改客户端默认帮助信息




1
2
vim ./src/ngrok/client/client/cli.go
找到第14行,修改 const usage2 string的值即可。

客户端程序加壳优化

编译好的Windows客户端ngrok.exe大小为10MB,感觉有点大,这样加载到内存中,需要读取硬盘的内容也相对较多,影响速度。所以,我们来给客户端程序加个压缩壳,对程序进行压缩。
这里采用mpress进行加壳,先从网上下载mpress.exe,之后将ngrok.exe拖放到mpress.exe的图标上,就能完成加壳操作。我们可以看到,加壳后的程序只有1.94MB,压缩率不到20%,大大节省了磁盘空间。同时小文件加载起来,速度会更快。

常见错误

在编译ngrok的时候,安装yaml的时候不能下载,无反应




1
2
3
4
5
gopkg.in/inconshreveable/go-update.v0  (download)
或者
gopkg.in/yaml.v1 (download)
原因git版本太低,需>= 1.7.9.5,通过RPMForge源安装最新版本git解决:
yum --enablerepo=rpmforge-extras install git

把编译出来的32位客户端放在64位上运行时会报错




1
2
3
4
/lib/ld-linux.so.2: bad ELF interpreter
 
#解决方法
yum install -y glibc.i686

在ngrok目录下执行如下命令,编译ngrokd




1
2
3
4
5
6
7
8
9
10
11
12
13
$ make release-server

出现如下错误:
GOOS="" GOARCH="" go get github.com/jteeuwen/go-bindata/go-bindata
bin/go-bindata -nomemcopy -pkg=assets -tags=release \
        -debug=false \
        -o=src/ngrok/client/assets/assets_release.go \
        assets/client/…
make: bin/go-bindata: Command not found
make: *** [client-assets] Error 127
go-bindata被安装到了$GOBIN下了,go编译器找不到了。修正方法是将$GOBIN/go-bindata拷贝到当前ngrok/bin下。

$cp /home/ubuntu/.bin/go14/bin/go-bindata ./bin

客户端ngrok.cfg中server_addr后的值必须严格与-domain以及证书中的NGROK_BASE_DOMAIN相同,否则Server端就会出现如下错误日志




1
2
3
4
[03/13/15 09:55:46] [INFO] [tun:15dd7522] New connection from 54.149.100.42:38252
[03/13/15 09:55:46] [DEBG] [tun:15dd7522] Waiting to read message
[03/13/15 09:55:46] [WARN] [tun:15dd7522] Failed to read message: remote error: bad certificate
[03/13/15 09:55:46] [DEBG] [tun:15dd7522] Closing

一此国内的Ngrok免费服务

http://www.ittun.com
http://qydev.com/
http://natapp.cn/
http://www.ngrok.cc/
----------------------------

搭建ngrok服务器

一、ngrok简介及作用

ngrok 是一款用go语言开发的开源软件,它是一个反向代理,通过在公共的端点和本地运行的 Web 服务器之间建立一个安全的通道。。

ngrok可捕获和分析所有通道上的流量,便于后期分析和重放。

这些看上去很麻烦,我们更需要的是了解ngrok的用途。

    完美代替“花生壳”软件。

“花生壳”是一款老牌的内网穿透软件,一年的内网版服务要两百多块钱,都快可以买一年垃圾点的VPS服务器了。而免费版的“花生壳”稳定性较差,隔三差五的不能访问,每个月只有1G流量,以前做项目没少被坑。ngrok是一款免费开源的软件,稳定性极强,我曾做过测试,将ngrok客户端所在计算机的网络断开一阵子,再连接另一个网络,ngrok很快会自动重连,几乎不受影响。

    用于对处在内网环境中,无外网IP的计算机的远程连接。

ngrok可以做TCP端口转发,对于Linux可以将其映射到22端口进行SSH连接。Windows的远程桌面可以将其映射到3389端口来实现。同理,如果要做MySQL的远程连接,只需映射3306端口即可。

    用作临时搭建网站并分配二级域名,可用作微信二次开发的本地调试。

微信公众平台二次开发时,服务器必须要能通过外网访问,而且必须是80接口。我们一般会在自己的电脑上写代码,但是由于电信运营商将80端口屏蔽了,甚至很多人通过无线路由器上网,根本就没有公网ip。在这种情况下,我们每次都要上传代码到服务器对微信公众平台进行接口调试,十分的不方便。而ngro可以将内网映射到一个公网地址,这样就完美的解决了我们的问题。

ngrok官方为我们免费提供了一个服务器,我们只需要下载ngrok客户端即可正常使用,但是后来官方的服务越来越慢,直到ngrok官网被完全屏蔽。现在我们已经无法使用ngrok官方的服务器了。所以,接下来我们自行搭建属于自己的ngrok服务器,为自己提供方便快捷又稳定的服务,一劳永逸。
二、环境准备
VPS

这里以阿里云ECS为例,操作系统为CentOS7(64位)。
域名

将一个域名或二级域名泛解析到VPS服务器上。例如将*.tunnel.mydomain.com解析到VPS的IP。要注意,此时还需要将tunnel.mydomain.com的A记录设置为VPS的IP。
安装git

#安装git
yum install git
#注意git版本应大于1.7.9.5
   
#安装git
yum install git
#注意git版本应大于1.7.9.5

配置go环境

下载go1.4.2源码包并解压:
wget http://www.golangtc.com/static/go/1.4.2/go1.4.2.linux-amd64.tar.gz
#解压到/usr/local/
tar -C /usr/local/ -zxf ./go1.4.2.linux-amd64.tar.gz

vim /ect/profile
在最后面添加:
export GOROOT=/usr/local/go
export PATH=$GOROOT/bin:$PATH

保存并退出,然后
source /ect/profile

查看go环境是否配置成功:
go version


三、准备编译Ngrok
下载Ngrok源码包
cd ~
git clone https://github.com/inconshreveable/ngrok.git
cd ngrok/
   
为Base域名生成自签名证书

ngrok需要一个域名作为base域名,ngrok会为客户端分配base域名的子域名。例如:ngrok的base域名为tunnel.mydomain.com,客户端即可被分配子域名test.tunnel.mydomain.com。

使用ngrok官方服务时,base域名是ngrok.com,并且使用默认的SSL证书。现在自建ngrok服务器,所以需要重新为自己的base域名生成证书。

#为base域名tunnel.mydomain.com生成证书
openssl genrsa -out rootCA.key 2048
openssl req -x509 -new -nodes -key rootCA.key -subj "/CN=tunnel.mydomain.com" -days 5000 -out rootCA.pem
openssl genrsa -out device.key 2048
openssl req -new -key device.key -subj "/CN=tunnel.mydomain.com" -out device.csr
openssl x509 -req -in device.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out device.crt -days 5000


执行完上述命令,正常情况下,该目录会多出device.crt、device.csr、device.key、rootCA.key、rootCA.pem、rootCA.srl六个文件,用它们来替换默认的证书文件即可。默认的证书文件在“./assets/client/tls”和“./assets/server/tls/”目录中

#替换默认的证书文件
cp rootCA.pem assets/client/tls/ngrokroot.crt
cp device.crt assets/server/tls/snakeoil.crt
cp device.key assets/server/tls/snakeoil.key

修改代码
按理来说,跳过这一步直接进行后续的编译工作没有什么问题。但是由于google无法访问,造成编译的时候从code.google.com上自动下载依赖包log4go超时而编译失败。

所以,我们需要将依赖包的下载地址改为github上的地址。

#修改依赖包log4go下载地址
vim ./src/ngrok/log/logger.go

找到第4行,将 log "code.google.com/p/log4go"
改为 log "github.com/keepeye/log4go"即可。

四、开始编译ngrok
编译服务器端ngrokd

ngrokd就是ngrok服务器端,默认编译为Linux的执行文件,我们的VPS本身就是Linux的,所以直接make编译就好。

#编译ngrokd(服务器端)
make release-server

显示以下内容,没有任何报错的话,服务器端ngrokd就编译成功了。

#服务器端ngrokd编译成功显示的内容
GOOS="" GOARCH="" go get github.com/jteeuwen/go-bindata/go-bindata
bin/go-bindata -nomemcopy -pkg=assets -tags=release \
 -debug=false \
 -o=src/ngrok/client/assets/assets_release.go \
 assets/client/...
bin/go-bindata -nomemcopy -pkg=assets -tags=release \
 -debug=false \
 -o=src/ngrok/server/assets/assets_release.go \
 assets/server/...
go get -tags 'release' -d -v ngrok/...
github.com/gorilla/websocket (download)
github.com/inconshreveable/go-vhost (download)
github.com/inconshreveable/mousetrap (download)
github.com/keepeye/log4go (download)
github.com/nsf/termbox-go (download)
github.com/mattn/go-runewidth (download)
github.com/rcrowley/go-metrics (download)
Fetching https://gopkg.in/inconshreveable/go-update.v0?go-get=1
Parsing meta tags from https://gopkg.in/inconshreveable/go-update.v0?go-get=1 (status code 200)
get "gopkg.in/inconshreveable/go-update.v0": found meta tag main.metaImport{Prefix:"gopkg.in/inconshreveable/go-update.v0", VCS:"git", RepoRoot:"https://gopkg.in/inconshreveable/go-update.v0"} at https://gopkg.in/inconshreveable/go-update.v0?go-get=1
gopkg.in/inconshreveable/go-update.v0 (download)
github.com/kardianos/osext (download)
github.com/kr/binarydist (download)
Fetching https://gopkg.in/inconshreveable/go-update.v0/check?go-get=1
Parsing meta tags from https://gopkg.in/inconshreveable/go-update.v0/check?go-get=1 (status code 200)
get "gopkg.in/inconshreveable/go-update.v0/check": found meta tag main.metaImport{Prefix:"gopkg.in/inconshreveable/go-update.v0", VCS:"git", RepoRoot:"https://gopkg.in/inconshreveable/go-update.v0"} at https://gopkg.in/inconshreveable/go-update.v0/check?go-get=1
get "gopkg.in/inconshreveable/go-update.v0/check": verifying non-authoritative meta tag
Fetching https://gopkg.in/inconshreveable/go-update.v0?go-get=1
Parsing meta tags from https://gopkg.in/inconshreveable/go-update.v0?go-get=1 (status code 200)
Fetching https://gopkg.in/yaml.v1?go-get=1
Parsing meta tags from https://gopkg.in/yaml.v1?go-get=1 (status code 200)
get "gopkg.in/yaml.v1": found meta tag main.metaImport{Prefix:"gopkg.in/yaml.v1", VCS:"git", RepoRoot:"https://gopkg.in/yaml.v1"} at https://gopkg.in/yaml.v1?go-get=1
gopkg.in/yaml.v1 (download)
go install -tags 'release' ngrok/main/ngrokd

我们可以在./bin/目录中找到文件ngrokd。可以先运行测试一下。

#执行ngrokd:
./bin/ngrokd -domain="tunnel.mydomain.com" -httpAddr=":8080"
   
出现类似以下内容,则说明我们的服务器端ngrokd正常运行了.
#服务器端ngrokd正常执行的显示
[02/12/16 17:30:59] [INFO] [registry] [tun] No affinity cache specified
[02/12/16 17:30:59] [INFO] [metrics] Reporting every 30 seconds
[02/12/16 17:30:59] [INFO] Listening for public http connections on [::]:8080
[02/12/16 17:30:59] [INFO] Listening for public https connections on [::]:443
[02/12/16 17:30:59] [INFO] Listening for control and proxy connections on [::]:4443

之后Ctrl+C退出ngrokd,继续来编译ngrok客户端。

编译客户端ngrok
编译linux客户端很简单,一条命令就搞定:
make release-client

显示以下内容,没有任何报错的话,客户端ngrok就编译成功了,我们在./bin/目录下就可以找到执行文件ngrok。

#客户端ngrok编译成功显示的内容
bin/go-bindata -nomemcopy -pkg=assets -tags=release \
 -debug=false \
 -o=src/ngrok/client/assets/assets_release.go \
 assets/client/...
bin/go-bindata -nomemcopy -pkg=assets -tags=release \
 -debug=false \
 -o=src/ngrok/server/assets/assets_release.go \
 assets/server/...
go get -tags 'release' -d -v ngrok/...
go install -tags 'release' ngrok/main/ngrok

但是,我们现在需要在windows下运行ngrok客户端。所以,重点是我们需要编译Windows版的ngrok客户端。那么我们难道要安装WIndows版的go环境,在Windows下编译吗?那太麻烦了,不用这样。go开发环境为我们提供了强大的跨平台交叉编译功能,在Linux下即可完成Windows版的编译。

#切到go的安装目录
cd /usr/local/go/src
#给Go编译器加上交叉编译windows/amd64程序的功能
GOOS=windows GOARCH=amd64 ./make.bash

如果这里提示错误
./make.bash: eval: line 135: syntax error near unexpected token `('
有可能是之前使用yum安装过go,通过命令 yum remove go 卸载当前的go并按照本文的方法重新安装。

#切回到ngrok目录
cd -
#执行如下命令编译Windows 64位客户端
GOOS=windows GOARCH=amd64 make release-client
#以上GOARCH=amd64指的是编译为64位版本,如需32位改成GOARCH=386即可

没有错误的话,Windows客户端ngrok就编译成功了,我们可以在./bin/windows_amd64/目录下找到执行文件ngrok.exe。将其下载到Windows上。

五、运行并测试
启动服务器端ngrokd

这个很简单,首先执行VPS上的服务器端ngrokd,这里的8080指的是服务器启用8080端口,就是说内网穿透后的域名为xxx.tunnel,mydomain.com:8080。如果在80端口未作他用的情况下,也可将8080端口改为80,这样更方便些。而如果我们VPS的80端口被占用了,但是我们还想用80端口作为服务端口,那么可以使用nginx做一个xxx.tunnel.mydomain.com的反向代理。

#执行ngrokd:
./bin/ngrokd -domain="tunnel.mydomain.com" -httpAddr=":8080"
   
写客户端配置文件
在ngrok.exe所在目录下建立文件ngrok.cfg,用记事本等文本编辑器写入以下内容并保存。
#配置文件ngrok.cfg的内容:
server_addr: "tunnel.mydomain.com:4443"
trust_host_root_certs: false
   
映射HTTP,
之后打开Windows服务器,这里以80端口为例。打开命令提示符,切到ngrok.exe所在目录,并执行以下命令。

#启动ngrok客户端
#注意:如果不加参数-subdomain=test,将会随机自动分配子域名。
ngrok -config=ngrok.cfg -subdomain=test 80
   
#启动ngrok客户端
#注意:如果不加参数-subdomain=test,将会随机自动分配子域名。
ngrok -config=ngrok.cfg -subdomain=test 80

正常情况下,客户端上会显示以下内容,表示成功连接到服务器端。

#客户端ngrok正常执行显示的内容
ngrok                                                  (Ctrl+C to quit)

Tunnel Status     online
Version           1.7/1.7
Forwarding        http://test.tunnel.mydomain.com:8080 -> 127.0.0.1:80
Forwarding        https://test.tunnel.mydomain.com:8080 -> 127.0.0.1:80
Web Interface     127.0.0.1:4040
# Conn            0
Avg Conn Time     0.00ms
   
打开浏览器,分别在地址栏中输入http://localhost和http://test.tunnel.mydomain.com:8080,如果后者正常显示并且和http://localhost显示的内容相同,则证明我们已经成功了。

映射TCP
有时候,我们使用远程桌面功能,或者在linux中进行SSH连接,对于处在内网环境中的计算机,我们可以对该端口进行TCP映射.

#这里以SSH连接Linux时的22端口为例
./ngrok -proto=tcp 22
   
映射成功的话,会显示如下内容:
#客户端ngrok正常执行显示的内容
ngrok                                                  (Ctrl+C to quit)

Tunnel Status     online
Version           1.7/1.7
Forwarding        tcp://tunnel.mydomain.com:49805 -> 127.0.0.1:22
Web Interface     127.0.0.1:4040
# Conn            0
Avg Conn Time     0.00ms

现在,在putty等ssh工具中即可连接tunnel.mydomain.com。切记端口是号49805,是随机分配的一个端口号,而不是默认的22端口了。

Windows的远程桌面可以将其映射到3389端口来实现。同理,如果要做MySQL的远程连接,只需映射3306端口即可。FTP可映射21端口。

六、后续定制及优化

通过以上操作,我们的ngrok服务器就已经成功搭建了,客户端也成功的跑了起来。但是,如果我们想要对ngrok进行一些定制和优化,可以参考这些后续定制及优化的方法。
修改客户端ngrok默认服务地址

客户端每次还需要加载配置文件,这样显得有些麻烦。能不能像官方服务那样直接执行命令 ngrok 80就能使用呢?我们只需要在编译客户端之前,稍作修改即可。同样,如果需要指定域名可以执行命令 ngrok -subdomain=test 80来运行客户端。

#修改默认服务地址
vim ./src/ngrok/client/model.go

找到第23行,将 defaultServerAddr = "ngrokd.ngrok.com:443"
修改为 defaultServerAddr = "tunnel.mydomain:4443" 即可。
修改客户端ngrok左上角蓝色文字logo

运行客户端后,我们会发现在客户端左上角会有一个蓝色字体的“ngrok”字样的文字logo,如果觉得不太喜欢,或者想修改一下的话,可以在编译客户端之前,作如下修改。

#修改客户端蓝色文字logo
Vim ./src/ngrok/client/views/term/view.go

找到第100行,将
v.APrintf(termbox.ColorBlue|termbox.AttrBold, 0, 0, "ngrok")
修改为
v.APrintf(termbox.ColorBlue|termbox.AttrBold, 0, 0, "your logo")
即可。

修改客户端帮助信息
ngrok客户端默认的帮助信息很少,我们可以在编译客户端之前,自己定制帮助内容。

#修改客户端默认帮助信息
vim ./src/ngrok/client/client/cli.go

找到第14行,修改 const usage2 string的值即可。
客户端程序加壳优化

编译好的Windows客户端ngrok.exe大小为10MB,感觉有点大,这样加载到内存中,需要读取硬盘的内容也相对较多,影响速度。所以,我们来给客户端程序加个压缩壳,对程序进行压缩。

这里采用mpress进行加壳,先从网上下载mpress.exe,之后将ngrok.exe拖放到mpress.exe的图标上,就能完成加壳操作。我们可以看到,加壳后的程序只有1.94MB,压缩率不到20%,大大节省了磁盘空间。同时,小文件加载起来,速度会更快。