1. 背景
公司的生产环境是部署在阿里云上的。Zabbix最初装在一台没有外网连接的ECS上,通过Nginx进行访问。但是后来发现如果需要报警,需要从Zabbix这台主机访问微信公众号服务器(qyapi.weixin.qq.com)。运维的兄弟最初选择了固定带宽的网络,但是考虑到费用问题,后期想切换到按量付费的网络,但是阿里云居然不支持这种切换(这里吐槽一下阿里的设计)。
由于该主机是按照包月包年方式购买的,退掉重新申请主机安装Zabbix显然不划算。在主机到期之前,必须想办法实现在没有外网的情况下访问微信服务器(考虑到费用问题,原先固定带宽已经被修改成了0M,也就没有费用了)。
2. 解决
考虑到整个生产环境中有多台能够访问Internet的主机,所以自然的想到是不是可以通过其他主机中转这种访问呢?
2.1 Nginx
最先想到的方案是通过Nginx,通过Nginx做一个正向代理,代理到微信公众号服务器( https://qyapi.weixin.qq.com ),然后通过从Zabbix访问Nginx代理后的站点。但是通过搜索发现,Nginx不支持这种代理方式(Forward Proxy)连接https服务器。具体的可以看附录中的连接。以下是Nginx作者的答复:
1> Is there any schedule to support the feathure, forward proxy ?
2Not in near future: there is alreay good forward proxy Squid.
2.2 iptables
然后又想到是不是可以使用iptables进行端口转发呢?但是可能是我对iptables还不够熟悉,按照附录4的命令总也调试不成功,总是会返回超时。这个方法没有解决问题。
2.3 socat
这时想起以前用过一个小工具socat
,用它将一个unix socket
转换成一个tcp socket
,它的用处就是将一个流转换成另一个流。经过尝试果然可以。命令也很简单:
1socat TCP-LISTEN:443,fork,reuseaddr TCP:140.207.127.79:443
然后在Zabbix主机上使用curl访问试试:
1root@prd-zabbix:~# curl https://192.168.61.64
2curl: (51) SSL: certificate subject name 'qy.weixin.qq.com' does not match target host name '192.168.61.64'
已经可以访问了,说明服务已经中转到微信的服务器上了。
3. 后续操作
3.1 域名
上面使用curl出现的提示表明,我们必须使用域名进行访问才能够被正确处理。这一点可以通过本地域名映射进行解决。可以通过修改/etc/hosts
增加映射的方式解决。因为我们本地的Zabbix是通过Docker运行的,这个修改就要通过Docker运行。我们使用的是docker-compose,在docker-compose.yaml
中增加如下配置即可:
1extra_hosts:
2 - "qyapi.weixin.qq.com:192.168.61.64"
这样,在Zabbix运行的容器中,域名qyapi.weixin.qq.com
指向了192.168.61.64
这台主机。而对这台主机上的443端口的访问被重定向到了140.207.127.79:443
,从而实现了对微信公众号服务器的访问。
3.2 多服务器
使用nslookup查询可以知道对应于域名qyapi.weixin.qq.com
,微信是提供了多台服务器的:
1root@prd-zabbix:~# nslookup qyapi.weixin.qq.com
2Server: 100.100.2.138
3Address: 100.100.2.138#53
4
5Non-authoritative answer:
6qyapi.weixin.qq.com canonical name = qy.weixin.qq.com.
7Name: qy.weixin.qq.com
8Address: 140.207.189.106
9Name: qy.weixin.qq.com
10Address: 140.207.127.79
上面的解决方案中只指向了一台服务器,这样如果这台服务器出现问题的时候可能会导致访问失败。可以考虑的一个方案是在另一台主机上使用socat做同样的转发工作,只是转发给另一台主机。这样应该可以解决部分问题。但是还不是最完美的解决方案。有待于以后继续研究。
3.3 自启动
需要考虑服务器重启的情况下,要自动启动socat。这个在Ubuntu上可以通过修改/etc/rc.local
文件解决:
1socat TCP-LISTEN:443,fork,reuseaddr TCP:140.207.127.79:443 &
2exit 0
附录A. 参考资料
- Re: https and nginx as forward proxy
- Nginx as forward proxy for HTTPS
- Lets Talk About Proxies, Pt. 2: Nginx as a Forward HTTP Proxy - See more at: https://blog.opendns.com/2015/11/03/lets-talk-about-proxies-pt-2-nginx-as-a-forward-http-proxy/
- Forward a TCP port to another IP or port using NAT with Iptables
- socat port forwarding for https
- Execute a Script at Startup and Shutdown on Ubuntu