标签 企业号 下的文章

搭建自己的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

2014小结

2014年的最后一个工作日,这里写下有关2014年的一份小结。

年终总结本无固定格式,但写了若干年后,便有了自己的格式。但今年不打算遵循这个格式了,跳出自己的舒适区,随意写写。

2014年12月底,随着亚航QZ8501航班的最后一掉,航空史上都为数不多的灾难年终于画上了句号,留给人们的是久久的惊恐不安,留给遇难者 家属们的是无法释怀的悲伤。2014年12月31日15点,随着A股上证指数最后一个交易日收涨68.86点,稳稳站上3200点,让广大股民们 看到了2015年牛市持续赚钱的希望。不知为何,这个世界几乎总是同时上演着冰与火两种剧本。

短信与微信(包括其他X信)的博弈亦是如此。

短信,这一红极一时的让移动运营商赚得盆满钵满的廉价沟通工具如今却早已成明日黄花。不妨打开手机,翻看一下你的手机通信录,短信列表中是不是除 了验证码(登录、支付业务),就是各种营销垃圾广告,或者是移动运营商自有的客服信息呢。我相信我的情况应该可以代表广大群众了。

随着微信今年推出“企业号”,微信几乎完成了对短信的业务合围:

点对点短信 vs. 联系人、朋友圈、群
SP短信    vs. 订阅号、服务号
行业短信  vs. 服务号、企业号 (营销、售后、内部OA、CRM等)

今年年初招商银行信用卡将300以内的消费提醒短信取消,改为微信提醒,其实就是一个看高微信,看空短信的行为。只是考虑到到达率(用户未开网络时),没 有将大额消费全部转到微信上,而是短信和微信都做提醒。一旦无线网络接入、资费门槛下降、网络速度提升、终端实时在线不再是问题,达到率也将 不是问题时,微信会对短信发起最后的总攻。

这么对比其实也不公平,因为短信和微信本不是一个重量级的对手。从出生的那天起,微信就被赋予了崇高的使命,非短信可比。微信试图连接一切,做统 一入口,建立庞大生态圈;而短信仅仅是一个通道工具罢了。

面对移动短信市场的衰败,移动运营商也在挣扎,也在试图翻盘,或至少平起平坐,但就我了解到的移动运营商产品开发与运营的风格,想和互联网巨头T 掰手腕,下场必输无疑。中国移动年初也蛮拼的,喊出了"RCS(融合通信)"与微信抢手机社交入口,但这都到了2014最后一天了,RCS依旧不见踪 影。

短信免费或退出历史舞台就像周鸿祎在其书《周鸿祎自述:我的互联网方法论》中说的那样是“趋势”,不可违!

我们就是为中国移动短信业务提供服务端软件和方案的。短信若是没了(或变成鸡肋),我们干啥?冰冷的现实摆在大家面前,领导跟我 们说:“转型”。

2014年,至少我们依旧在转型中。老板们把“转型”依旧约束在“移动运营商”这棵大树下面,这让我们转的不那么纯粹,有些拖泥带水,可持续盈利 的业务方向并不明显。从目前来看,今年收入依旧靠传统业务渠道获得。

虽说要“转型”,但领导今年给我的任务却是做好守门员,守住现有市场份额,保证产品线上无事。这并非如我所愿,在一个业务线耕耘多年,业务和技术 能力均到达了天花板,对我个人来说,这不是一个很好的发展规划。但考虑到下面的技术负责人、员工在技术和业务火候儿还欠缺那么一些,我答应了留 守,但会投入部分精力做个人技术转型储备。

业务的转型需要技术做支撑,局限于传统后台服务系统的我们需要张开怀抱,拥抱那些“流行”的新玩意儿。我首先试水!从2014年我的博客中你也许 可以看得出来我试水过的技术,我在尝试跳出自己的各种舒适区,向一些近两年兴起的、将来比较有前途的技术方向靠拢,学习移动互联网的思维和潮流。

上半年曾尝试过终端产品开发的技术,还为此购入若干数码装备,但试过后才发现这仍然不是我的主菜,就和10年前Windows GUI程序开发不是我的菜一样。但这个过程并非没有收获,未来任何业务不与终端开发打交道是不可能的,这个接触过程让我了解到了终端开发的重点和难点,于 是总结经验,整理教训。

正当准备调整方向、重新上路之际,家里出现重大变故,耗费了我整整1个多月的时间,一切几乎都停滞了,直到10月份我才渐渐重新进入状态。

在公司内部技术社区看到公司CTO的一篇文章,讲述移动互联网正在由消费者驱动向企业驱动转变(来自麦肯锡报告),结合微信推出企业号、用友软件的转型来 看(今天听说用友软件更名为“用友网络”了,决心向互联网转型),这个趋势也是我比较认同的,这个方向以及相关技术也是我在正在涉猎以及即将涉猎的。不过 关于企业互联网服务以及平台,自己的相关业务经验、技术和积累还是甚少,征途必然坎坷,自己还需“拼”一下!关于微信这个平台,这个入口,它是腾讯未来战 略的核心,靠着腾讯这棵大树,至少未来几年发展应该还是不错的。

公司的大BOSS这两年一直提倡“创业者的精神",学会在逆境中成长,在困境中成功。但作为在短信这个行业内浸淫了十多年的部门,我们不免产生一些惰性, 更愿意躺在现有的温床上“享受生活”,立足于现有的平台做舒服的事情。经历过2014年的严峻形势,现在的我们应该清醒的认识到这样的舒服生活,温床和平 台都可能将远离我们。如果我们再不主动站起来,我们将再无力站起了。

2014年在个人发展方面做出了“妥协”,2015我打算轻装前行,这对我、对团队成员的成长都是有好处的。年底给领导发总结时,已经和领导书面提出退出 当前业务线的想法。虽然目前还没有收到回复,不过无论怎样,我都坚定了决心,自己作为这个产品线的负责人,已经起不到领路的作用了,是时候退出了。

2015,给自己的关键字是“创业”。《精益创业》一书中作者似乎有这样一句话:“你不一定非要在车库里折腾才算是创业”,在企业内部也可以“创业”,为创造某种新产品或新服务为目的而组建的一个团队或组织内的人都是“创业者”。

以往年份的小结,我总会总结一些数据,比如blog文章、读过多少本书等等。但今年这些数据就不统计了,自己对自己的考核指标"KPI"有所调整,以前哪些指标已经不算数了,列出也就无意义了。

2014这一年,LP给了我很大压力!我能理解,她期望我能取得更大的成功。这让我“亚历山大”啊,这回可是真的。

要说新年的愿望是什么?希望2015年年末时能为自己2015年的所作所为,所取得的进步和成果点个赞

如发现本站页面被黑,比如:挂载广告、挖矿等恶意代码,请朋友们及时联系我。十分感谢! Go语言第一课 Go语言精进之路1 Go语言精进之路2 商务合作请联系bigwhite.cn AT aliyun.com

欢迎使用邮件订阅我的博客

输入邮箱订阅本站,只要有新文章发布,就会第一时间发送邮件通知你哦!

这里是 Tony Bai的个人Blog,欢迎访问、订阅和留言! 订阅Feed请点击上面图片

如果您觉得这里的文章对您有帮助,请扫描上方二维码进行捐赠 ,加油后的Tony Bai将会为您呈现更多精彩的文章,谢谢!

如果您希望通过微信捐赠,请用微信客户端扫描下方赞赏码:

如果您希望通过比特币或以太币捐赠,可以扫描下方二维码:

比特币:

以太币:

如果您喜欢通过微信浏览本站内容,可以扫描下方二维码,订阅本站官方微信订阅号“iamtonybai”;点击二维码,可直达本人官方微博主页^_^:
本站Powered by Digital Ocean VPS。
选择Digital Ocean VPS主机,即可获得10美元现金充值,可 免费使用两个月哟! 著名主机提供商Linode 10$优惠码:linode10,在 这里注册即可免费获 得。阿里云推荐码: 1WFZ0V立享9折!


View Tony Bai's profile on LinkedIn
DigitalOcean Referral Badge

文章

评论

  • 正在加载...

分类

标签

归档



View My Stats