我这两天在折腾服务器的时候,发现有个无公网IP的机器不能访问公网。
我就纳闷了,我只是不在公网暴露了,怎么网都直接断了,不应该跟家里的网络一样,通过路由器这个出口访问公网。后来搜索之后,发现这个现象是by design,默认没有出口。内网机器想要访问公网,需要经过NAT网关的转发。你可以购买现成的NAT服务,我看到它是按照小时算钱的,感觉不会便宜。还有一种方式,就是将有公网IP的机器配置为NAT网关,内网机器访问公网的流量都走它。
准备好一台有公网IP的机器(下文称网关服务器),本文以Ubuntu 22.04为例,通过以下三步来实现目标。
开启IP转发
一台机器默认情况下,只接收目标IP地址为自己的报文,其他地址的报文会被丢弃。Linux内核有专门的IP转发功能来控制这一行为,默认情况下这个功能是关闭的,我们需要将它打开,以转发内网机器的报文,充当路由器。
我们可以先通过以下两个命令之一查看当前系统IP转发能力是否已经开启:
cat /proc/sys/net/ipv4/ip_forward
sysctl net.ipv4.ip_forward
输出1表示开启,输出0表示关闭。如果你系统没有专门配置过,基本都会输出0。可以选择任一方式来修改:
# 修改内核参数的映射文件
sudo echo 1 > /proc/sys/net/ipv4/ip_forward
sudo echo 0 > /proc/sys/net/ipv4/ip_forward
# 使用sysctl命令修改参数
sudo sysctl -w net.ipv4.ip_forward=1
sudo sysctl -w net.ipv4.ip_forward=0
不过上面的修改只是临时的,重启系统过之后,这个参数就会恢复默认值,只适合你临时测试下。
如果要持久化修改,需要在/etc/sysctl.conf
中添加如下一行配置:
net.ipv4.ip_forward = 1
然后重新加载让它生效:
sudo sysctl -p # 此命令含义是从文件中读取配置,打印出来。别人都说这么做就会生效,那我姑且信了
更新路由表
记下来要告诉内网的机器,我们有了一台网关服务器,网络请求都可以交给它。
以阿里云为例,找到机器所在的VPC对应的路由表,添加一个路由条目。目标网段为0.0.0.0/0,表示所有目标都可以处理。下一跳的类型是ECS实例,并选择刚才配置好的网关服务器。
这样内网机器在访问网络的时候,路由器最终会将请求转发给网关服务器。
配置iptables
好了,网关服务器收到请求了,它也知道自己能转发报文了。下一步需要配置iptables。
我在网上搜索相关资料的时候,因为不熟悉iptables,导致运行的时候经常报错说是参数不对。作为一丝不苟的ISTJ,我实在是无法忍受复制粘贴带来的不确定性、不一致和不统一。但我还是克制住了自己,不要沉迷于研究iptables的机制,避免浪费过多的时间在上面,我这尿性,要是花时间把iptables研究透了,肯定就把初心仍在一边,又要专门再写一篇文章了😆。
直接贴出我尝试过之后可以生效的命令:
sudo iptables -t nat -A POSTROUTING -s [网段] -o eth0 -j MASQUERADE
命令含义大概是,在nat
表的POSTROUTING
链上,附加一条规则,所有从某个[网段]
来的报文,都伪装(MASQUERADE
)成从eth0网卡上发出的一样。也就是将报文的来源地址,改成网关服务器的eth0网卡的IP地址,而不是发出请求的子网机器的地址。这正反映了NAT的原本含义,也就是Network Address Translation,即网络地址转换。
其中的网段参数就是子网的网段,你可以查看VPC的网段,对于阿里云来说,大概都是以下其中一种:
10.0.0.0/8
172.16.0.0/12
192.168.0.0/16
配置完成之后,即刻就生效了,所有内网机器都可以访问公网,新购置的机器即使不做任何配置也能访问公网。不过目前还有最后一个问题:我们添加的规则,在重启之后,就失效了。得想办法让它持久化。
这个简单,安装个iptables插件,实现这个目的:
sudo apt install iptables-persistent
安装的过程就会提示你,是否将当前规则保存到/etc/iptables/rules.v4
,你选择是就行,它的内容大概是:
# Generated by iptables-save v1.8.7 on Mon Jul 1 23:44:58 2024
*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING -s 172.16.0.0/12 -o eth0 -j MASQUERADE
COMMIT
# Completed on Mon Jul 1 23:44:58 2024
这其实正是iptables-save
的输出。iptables-persistent
的守护进程会在启动的时候读取规则并自动应用,其实它八成执行的就是iptables-restore
命令来恢复规则。
为了做测试,我还真的重启了系统,最终在子网机器上尝试访问公网并成功了。
总结
感谢互联网,感谢在各种技术平台上总结自己经验的前辈们,让我完美地解决了此问题。同时我还得感谢阿里云的99计划,99元买到2核4G的机器,并且将宽带减配为0还能再退49,50元一年的机器简直划算极了。
最后修改于 2024-07-02