阿里云主机CentOS 7下编译安装ngrok

ngrok等隧道工具是Web程序员开发的神器!

配置微信及支付宝等接口,需要回调自己的公网服务器地址。开发过程中程序是跑在程序员自己的电脑上的,如果想在开发过程中调试接口的请求,必须想办法将本地应用穿透到公网上去,才能让微信或支付宝的服务器能访问到。

传统的硬派做法是在路由器上做端口映射,极其不便。有了ngrok这个神器,程序员可以很方便的将自己的应用临时公开在公网地上,然后在自己的电脑上观察和调试来自外界的访问。

ngrok的开源版本可以从github上获得。开源版本是老版本,该神器的作者已不再维护老版本,而将精力放在在线商业服务ngrok.com上了。选择使用ngrok的在线服务,免掉了自己搭建服务器的辛苦,还有确保用到最新的ngrok软件,安全性比较高。理论上选择这种云隧道服务是最便捷的方式,但是在国内使用公开的云隧道,有以下几个明显的问题:

  1. 由于“你懂得”的存在,ngrok.com在国内的访问不稳定,时不时会访问不到。
  2. 微信及支付宝的接口在对接时,需要审查接口地址的域名是否ICP备案,是否是签约域名等,这就限制了无法随意使用一个第三方的域名地址做隧道的公网地址。
  3. 微信或者支付宝平台很容易封杀一些用户量比较大的隧道提供商的域名。
  4. 如果选择一些不知名的第三方隧道提供者,很难确保信息不会恶意截获。

因此我的观点是如果是国内开发团队的话,一定要搭建一个自己的隧道服务器。ngrok的开源版本(老版本)虽然据作者说存在安全隐患,但是如果仅作为调试用的话应该问题不大吧。期待作者能将最新版也开源化。

前提条件:

  1. 云服务器,例如:阿里云主机, ip地址 xxx.xxx.xxx.xxx
  2. 云服务器安装Linux 64位操作系统,推荐CentOS 7.2 64位
  3. ICP备案过的域名,例如: mydomain.com
  4. 准备一个二级域名,例如: dev.mydomain.com
  5. 在域名解析服务器上做两条A记录,指向上面的阿里云主机IP地址,例如
dev.mydomain.com 指向 xxx.xxx.xxx.xxx
*.dev.mydomain.com 指向 xxx.xxx.xxx.xxx

补充说明:

  • 在CentOS7下安装ngrok比较省心,使用yum默认安装的编译环境即可满足要求。
  • CentOS6下也可以安装ngrok的,但是由于yum默认安装的git及go版本比较老,很多软件需要手工下载最新版去编译安装。
  • CentOS7已经不是新鲜事物了,完全可以用于生产环境。如果不是特殊情况下非要运行一些老版本的软件,不建议用CentOS6。
  • CentOS7与6的差别比较大,尤其是service的启动及防火墙的设置。如果是第一次使用CentOS7,一定要提前预习一下systemctlfirewalld的用法,不然装上去会找不到北。

一、编译ngrok

  1. 安装编译所需软件

    # 注意:git版本不能低于1.8,版本太低可能会导致编译失败
    yum install -y git
    yum install -y perl-ExtUtils-MakeMaker mercurial
    yum install -y golang
    
  2. 从github下载ngrok源代码

    cd /opt
    git clone https://github.com/inconshreveable/ngrok.git ngrok
    
  3. 生成二级子域名的秘钥

    # 修改成自己的子用户名,例如dev.mydomain.com
    cd /opt/ngrok
    openssl genrsa -out base.key 2048
    openssl req -new -x509 -nodes -key base.key -days 10000 -subj "/CN=dev.mydomain.com" -out base.pem
    openssl genrsa -out server.key 2048
    openssl req -new -key server.key -subj "/CN=dev.mydomain.com" -out server.csr
    openssl x509 -req -in server.csr -CA base.pem -CAkey base.key -CAcreateserial -out server.crt -days 5000
    
  4. 将生成的秘钥复制到编译目录中

    cp server.crt assets/server/tls/snakeoil.crt
    cp server.key assets/server/tls/snakeoil.key
        
    cp base.pem assets/client/tls/ngrokroot.crt
    
  5. 编译ngrok服务器端

    # 编译后的可执行文件的位置: `/opt/ngrok/bin/ngrokd`
    make release-server
    
    • 第一次执行编译时候,由于编译过程中会从github中获取依赖的包(大约60多MB),所以耗时主要取决于github的访问速度。
    • 如果阿里云访问github速度很慢,需要忍耐或者想办法解决。
    • 如果出错,重新执行该命令,会断点续传。出错的原因一般是github被你懂的中断。
    • 如果有国外的服务器,也可以在国外的服务器上进行编译。
    • 第二次编译时候,由于不再需要下载一些依赖包,所以编译会瞬间完成 (我在阿里云主机上下载用了大约30多分钟,中间反复执行了该命令三次,问候了墙无数次)
  6. 编译不同平台的客户端

    # 编译Linux64位版(生成:/opt/ngrok/bin/ngrok)
    make release-client
        
    # 编译Mac版 (生成:/opt/ngrok/bin/darwin_amd64/ngrok)
    GOOS=darwin GOARCH=amd64 make release-client
        
    # 编译Windows64位版 (生成:/opt/ngrok/bin/windows_amd64/ngrok.exe)
    GOOS=windows GOARCH=amd64 make release-client
        
    # 编译Windows32位版 (生成:/opt/ngrok/bin/windows_386/ngrok.exe)
    GOOS=windows GOARCH=386 make release-client
    

将客户端程序下载并保存起来,分发给开发组的小伙伴们。

二、服务器端设置方法

  1. CentOS云服务器设置防火墙,然后公开需要监听的端口

    # 启动防火墙
    systemctl start firewalld
    systemctl enable firewalld
        
    # 放行ngrok需要的4443端口
    firewall-cmd --zone=public --add-port=4443/tcp --permanent
        
    # 放行80及443端口
    firewall-cmd --add-service=http --permanent
    firewall-cmd --add-service=https --permanent
        
    # 放行自定义端口,例如:TCP 7070及7071端口
    firewall-cmd --zone=public --add-port=7070/tcp --permanent
    firewall-cmd --zone=public --add-port=7071/tcp --permanent
    firewall-cmd --zone=public --add-port=7443/tcp --permanent
        
    # 重新加载防火墙规则
    firewall-cmd --reload  
    
  2. 服务器端启动ngrok

    # 样例1:监听80口及443端口 (请将dev.mydomain.com修改成自己的域名)
    /opt/ngrok/bin/ngrokd -tlsKey=/opt/ngrok/server.key -tlsCrt=/opt/ngrok/server.crt -domain=dev.mydomain.com -httpAddr=:80 -httpsAddr=:443 -tunnelAddr=:4443 > /opt/ngrok/ngrok.log &
        
    # 样例2:监听7070口及7071端口 (请将dev.mydomain.com修改成自己的域名)
    /opt/ngrok/bin/ngrokd -tlsKey=/opt/ngrok/server.key -tlsCrt=/opt/ngrok/server.crt -domain=dev.mydomain.com -httpAddr=:7070 -httpsAddr=:7071 -tunnelAddr=:7443 > /opt/ngrok/ngrok.log &
    

如果需要开机自启动,可以将该命令行写入到/etc/rc.local,或者编辑一个service脚本用于自动启动。

三、客户端设置方法

以Macos系统为例做说明:

  1. 在自己的用户目录下创建一个文件夹,例如my_ngrok

    mkdir ~/my_ngrok
    cd ~/my_ngrok
    
  2. 将编译好的ngrok客户端直接下载保存,或者用scp工具下载

    scp root@服务器host:/opt/ngrok/bin/darwin_amd64/ngrok ./
    
  3. 在当前目录下编辑一个配置文件ngrok.cfg,内容如下:(请将dev.mydomain.com修改成自己的域名)

    server_addr: dev.mydomain.com:4443
    trust_host_root_certs: false
    
  4. 运行客户端程序

    cd ~/my_ngrok
    ./ngrok -subdomain abc -proto=http -config=./ngrok.cfg 3000
    
    • 请将例子中的动态子域名abc修改成自己想要的子域名
    • 请将本地应用服务器对应的端口3000修改成自己实际的端口,例如tomcat的8080
    • 为了便于使用,推荐创建一个Shell启动脚本
    • 如果出现Tunnel Status online的字样,说明配置成功了。可以通过公网的地址来访问。
    • 退出客户端请用Ctrl+C
    Tunnel Status                 online                                                                                                                                          
    Version                       1.7/1.7
    Forwarding                    http://abc.dev.mydomain.com -> 127.0.0.1:3000
    Web Interface                 127.0.0.1:4040
    # Conn                        0
    Avg Conn Time                 0.00ms
    
  5. 在浏览器打开http://abc.dev.mydomain.com,确认能正常访问。 在微信公众等平台上填写API地址时,填写自己的http://abc.dev.mydomain.com/访问目录

  6. 访问http://127.0.0.1:4040,就可以看到所有来自外部的请求内容。

四、与nginx共存的设置方法

如果服务器上已经启动了80端口的nginx,那么ngrok服务器端就不能在80口启动。这时候ngrok只能启动在其他端口,例如在7070端口监听http请求。

# 监听7070口及7071端口 (请将dev.mydomain.com修改成自己的域名)
/opt/ngrok/bin/ngrokd -tlsKey=/opt/ngrok/server.key -tlsCrt=/opt/ngrok/server.crt -domain=dev.mydomain.com -httpAddr=:7070 -httpsAddr=:7071 -tunnelAddr=:7443 > /opt/ngrok/ngrok.log &

这种情况下仍然希望用80端口访问ngrok的话,可以在/etc/nginx/conf.d/目录下配置一个nginx服务器的虚拟站点,例如: ngrok.conf,使用代理转发的方式将80端口的请求转发到ngrok的实际端口上。nginx的虚拟站点的配置文件示例:

# 配置文件:/etc/nginx/conf.d/ngrok.conf
# 请根据自己的实际情况调整端口及dev.mydomain.com的二级域名。
map $scheme $proxy_port {
    "http"  "7070";
    "https" "7071";
    default "7070";
}
    
server {
    listen      80;
    listen      [::]:80;
    listen      443;
    listen      [::]:443;
    server_name *.dev.mydomain.com;
    
    location / {
        resolver 114.114.114.114 valid=2s;
        proxy_pass  $scheme://$host:$proxy_port;
        proxy_redirect off;
        client_max_body_size 10m;   
        client_body_buffer_size 128k; 
        proxy_connect_timeout 90; 
        proxy_read_timeout 90;
        proxy_buffer_size 4k;       
        proxy_buffers 6 128k;        
        proxy_busy_buffers_size 256k;
        proxy_temp_file_write_size 256k; 
    }
    
    ssl on;
    ssl_certificate  /opt/ngrok/server.crt;
    ssl_certificate_key  /opt/ngrok/server.key;
    
    access_log off;
    log_not_found off;
}
    

配置完成后,重启nginx服务器

systemctl restart nginx

用这种方式就可以与其他nginx上的站点共存在一台服务器上了。

参考文章:

类似的应用(未尝试过): - frp

Share Comments
comments powered by Disqus