docker宿主机iptables配置

背景

之前服务器都是直接配置LNMP环境,最近手头正好有一台须要从新配置,想尝试使用docker来配置多PHP版本环境。docker配置十分顺利,感谢有明大佬的小册,和DNMP项目git

待解决

服务器配置好后,在几天的试用过程当中,发现以下两个问题:github

  • NGINX PHP容器中没法获取request的真实IP
  • PHP容器中没法访问公网

过程

没法访问公网,没法获取真实IP,首先想到了防火墙的问题;关闭iptables,问题解决。但是iptables不能关呀,虽然说如今云服务器都有安全组过滤,但防火墙是最后一道防线,不能在云厂商的怀抱里裸奔啊……docker

查看了docker的网络部分,docker暴露容器端口是由docker-proxy来实现的,至于docker-proxy是什么略过不表。确定是iptables影响了docker-proxy致使数据包的源ip发生了改变,没法获取真实IP;没法访问公网,则是数据包找不到出口,被iptables拦截掉了,在内网转圈圈shell

  • 既然docker的各容器处于内网中,因而我想到了iptables的转发功能。

解决

  • 假设个人公网IP为 117.25.140.71api

  • NGINX容器内网IP为 172.18.0.2安全

  • PHP容器内网IP为 172.18.0.3 172.19.0.3服务器

把公网来的数据包直接转发给NGINX容器,跳过docker-proxy

添加以下规则网络

-A PREROUTING -d 117.25.140.71 -p tcp -m tcp --dport 80 -j DNAT --to-destination 172.18.0.2:80
-A PREROUTING -d 117.25.140.71 -p tcp -m tcp --dport 443 -j DNAT --to-destination 172.18.0.2:443
复制代码

重启iptables 没法获取真实IP问题解决tcp

将内网的数据包转发到公网

个人PHP容器访问公网,需求大抵是发送短信之类(无邮件发送),用的都是http协议,因此这里我没有选择所有转发,而是只转发目的端口为80和443的数据包spa

添加以下规则

-A POSTROUTING -s 172.19.0.3 -p tcp -m tcp --dport 80 -j SNAT --to 117.25.140.71
-A POSTROUTING -s 172.19.0.3 -p tcp -m tcp --dport 443 -j SNAT --to 117.25.140.71
复制代码

重启iptables发现仍然没法访问公网,是否是落下了什么。。 对了,既然http协议访问其余域名提供的api服务,怎么能少了DNS解析呢?添加DNS的支持(注意:DNS解析使用的是udp协议)

补充以下规则

-A POSTROUTING -s 172.19.0.3 -p udp -m udp --dport 53 -j SNAT --to 117.25.140.71
复制代码

重启iptables,大功告成!

最后总结几点:

  • 之因此能用宿主机iptables实现转发,是由于宿主机是内网的网关
  • 我限制了PHP容器访问公网的目的端口,若是须要发送邮件或者访问8080等其余端口,仍需单独添加规则或者不限制具体端口号
  • 转发内网数据包到公网,不要使用地址假装(MASQUERADE),不然会影响本文中添加的PREROUTING规则,仍然没法获取request的真实IP(使用其余方法除外)
  • 若是直接service iptables stop,这篇文章就不用看了。。。
相关文章
相关标签/搜索