💡 导语:在网络架构中,NAT (网络地址转换) 是一项将数据包重定向到备用地址的强大技术。本文将详细教你如何通过 iptables 在 Linux 网关上进行端口转发配置,让外部请求也能安全、准确地访问到完全处于内网的服务器。
端口转发(Port Forwarding)是指将对特定端口的请求转发到另一个主机、网络或端口的过程。由于它在传输中修改了数据包的目的地,所以被认为是 NAT(网络地址转换)的一种操作。
实现端口转发,主要依赖于两种关键操作:
- DNAT (Destination NAT):修改入站数据包的“目标地址”。
- SNAT (Source NAT):修改出站数据包的“源地址”,确保响应的数据包能够正确地原路路由回去。
在这篇教程中,我们将学习如何在一台充当网关的 Linux 机器上使用 iptables 进行端口转发。具体来说,我们会利用 PREROUTING 和 POSTROUTING 链中的 DNAT 和 SNAT 规则,把发往网关 80 端口的流量转发给一台只能通过内部私有网络访问的 Web 服务器。
1. 原理核心与准备工作
要使用 iptables 成功实现端口转发,核心需要三部分组件配合:
- 内核级别的 IP 转发:通过
sysctl开启。 filter表中的FORWARD链规则:允许流量通过防火墙。nat表中的DNAT/SNAT规则:准确地修改目标地址和源地址。
我们在这个教程中的实验环境架构
为了便于理解,我们假设有两台服务器,它们都在同一个私有网络里。
内网 Web 服务器的细节:
- 公网 IP(不用):
203.0.113.1 - 私网 IP:
10.0.0.1 - 公网网卡:
eth0 - 私网网卡:
eth1
网关/防火墙服务器的细节:
- 公网 IP(流量入口):
203.0.113.2 - 私网 IP:
10.0.0.2 - 公网网卡:
eth0 - 私网网卡:
eth1
我们的目标是:当用户访问网关的公网 IP 203.0.113.2:80 时,请求会被转发到 Web 服务器的内网 IP 10.0.0.1:80 上。
2. 设置内网 Web 服务器 (Nginx)
首先登录到你的内网 Web 服务器(10.0.0.1)。
为了验证端口转发是否生效,我们需要安装一个 Nginx,并且严格限制 Nginx 只能监听私网接口。
sudo apt update
sudo apt install nginx
安装完成后,打开默认的站点配置文件:
sudo nano /etc/nginx/sites-enabled/default
找到关于 listen 的两行指令,修改为仅监听内网 IP。(本教程只演示 IPv4,如果不需要可以把 IPv6 的 listen 删掉):
server {
listen 10.0.0.1:80 default_server;
# ... 其他配置
}
保存并退出。测试语法无误后重启 Nginx:
sudo nginx -t
sudo systemctl restart nginx
这样,你的 Web 服务器就再也不会对外网暴露了,它变得非常安全。
3. 在网关服务器上配置防火墙 (Iptables)
接下来所有的操作都在网关/防火墙服务器(10.0.0.2)上进行。
3.1 开启内核级 IP 转发
Linux 系统默认是关闭了数据包转发功能的。你需要手动将它打开。
你想临时测试开启的话,可以运行:
echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward
但要想做到永久生效(重启后依然有效),请编辑 /etc/sysctl.conf 文件:
sudo nano /etc/sysctl.conf
取消 net.ipv4.ip_forward=1 这一行前面的注释(去掉 # 号),保存退出。
然后应用配置:
sudo sysctl -p
# 或者
sudo sysctl --system
3.2 在 FORWARD 链中放行流量
默认的安全防火墙模板通常会将 FORWARD 链的策略设置为 DROP。我们需要加两条规则,允许特定流量流经这台网关。
首先,我们在 FORWARD 链中,允许来自外网卡 eth0、目标为内网卡 eth1 的 80 端口 TCP 新建连接请求(NEW):
sudo iptables -A FORWARD -i eth0 -o eth1 -p tcp --syn --dport 80 -m conntrack --ctstate NEW -j ACCEPT
接着,依靠 conntrack (连接追踪),允许那些已经建立起来的、或是相关的双向回传流量(ESTABLISHED, RELATED):
# 从外网卡到内网卡
sudo iptables -A FORWARD -i eth0 -o eth1 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# 从内网卡到外网卡
sudo iptables -A FORWARD -i eth1 -o eth0 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
最后,确认一下你的 FORWARD 链的默认策略是不是还是 DROP(拦截一切其余不符合规则的包):
sudo iptables -P FORWARD DROP
这就好比给一堵密不透风的墙开了一扇带有身份验证机制的门。
3.3 配置 NAT 规则正确引导数据包
目前门虽然开了,但别人进来后根本不知道该往哪里走!这步就是配置向导服务(NAT)。
首先是 DNAT(目标地址转换)。当公网用户的请求到达网关的外网卡 eth0 时,我们要在路由判定之前(PREROUTING)就把数据包的目标地址偷梁换柱,改成真正的 Web 服务器内网 IP 10.0.0.1:
sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j DNAT --to-destination 10.0.0.1
这只完成了一半。此时数据包虽然成功发到了 Web 服务器,但该数据包的“寄件人”依然是公网客户端的原始真实 IP。如果 Web 服务器直接“回复”给这个真实 IP,会导致 TCP 连接无法建立,甚至会被底层的云服务商以反欺诈原因直接丢包。
因此,我们要进行 SNAT(源地址转换)。在数据包即将离开网关内网卡 eth1 奔向 Web 服务器之前(POSTROUTING),我们把它的源地址改成网关自己的内网 IP 10.0.0.2。
于是,Web 服务就只会把响应交还给网关,网关再顺水推舟把响应返回给公网客户端:
sudo iptables -t nat -A POSTROUTING -o eth1 -p tcp --dport 80 -d 10.0.0.1 -j SNAT --to-source 10.0.0.2
提示:SNAT vs MASQUERADE 如果我们的网关私网 IP 是固定的静态 IP(如本例的 10.0.0.2),用
SNAT性能更好。如果你的网关 IP 是通过 DHCP 动态获取的,那就没有固定 IP 可写,此时只能把最后修改成-j MASQUERADE。
至此,大功告成!找一台外网电脑执行:
curl http://203.0.113.2
你就能看到 Web 服务器内网机器上的 Nginx 初始界面的 HTML 代码了。
3.4 永久保存防火墙规则
一旦你重启服务器 iptables 规则就会清空。为了让刚才的配置硬化固化,你需要保存规则。
在 Ubuntu 等用 iptables-persistent 的系统中:
sudo service netfilter-persistent save
这会使当前所有活动规则写入到 /etc/iptables/rules.v4 当中。
4. 端口转发安全最佳实践指南
为了保障环境的安全可靠,当我们在 Linux 网关上做这种高级路由操作时,一些安全规范要时刻牢记:
- 精准限制端口映射:绝对不要开多余的端口,开哪个用哪个。每一个端口转发都在内部网络上撕开了一道口子。
- 尽量限制能够发起请求的来源 IP:比如,只有总部办公室的 IP 段
198.51.100.0/24允许访问,可以在PREROUTING时增加-s参数:sudo iptables -t nat -A PREROUTING -i eth0 -s 198.51.100.0/24 -p tcp --dport 80 -j DNAT --to-destination 10.0.0.1 - 针对 FORWARD 中的废弃包开启日志打点:在你的 DROP 规则之前插入一条
-j LOG,便于后续的入侵检测排查。 - 防御 SYN 洪水泛滥或暴力破解:利用 iptables 原生的
limit模块进行新建请求的限流(例如--limit 25/second --limit-burst 50)。 - 定期审计规则:常使用
iptables -t nat -L -v -n和iptables -L -v -n进行查看。
结尾
通过配置以上的规则,你现在已经在这台 Linux 机器上玩转了 Iptables 端口转发的核心理论。你会发现它并没有想象中那么神秘:无非就是内核准许通过、中间开个小门,接着来一手漂亮的前后门“目标-来源”地址掉包计。在这个基础之上,你就可以应对诸多更加复杂的内网代理需求了!