iptables 完全指南 / 第 11 章:端口转发与代理
第 11 章:端口转发与代理
本章目标:掌握使用 iptables 实现端口转发、反向代理、简单负载均衡和透明代理的方法,能够解决常见的内网服务暴露和流量调度问题。
11.1 端口转发基础
11.1.1 什么是端口转发
端口转发(Port Forwarding)是将发送到某个 IP:端口 的流量重新定向到另一个 IP:端口的过程。它是 DNAT 的一种典型应用。
外部用户 NAT 网关 内网服务器
──────────→ eth0: 203.0.113.1 10.0.0.10:80
请求 203.0.113.1:80 ──── DNAT ────→ 请求 10.0.0.10:80
←────────── ←──────────
响应 ←── 反向 NAT ── 响应
11.1.2 基本端口转发配置
#!/bin/bash
# ═══════════════════════════════════════════════════
# 基本端口转发:公网 80 → 内网 10.0.0.10:80
# ═══════════════════════════════════════════════════
# 启用 IP 转发
sysctl -w net.ipv4.ip_forward=1
# DNAT:将入站 HTTP 流量转发到内网 Web 服务器
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 \
-j DNAT --to-destination 10.0.0.10:80
# 允许转发该流量
iptables -A FORWARD -i eth0 -o eth1 -p tcp --dport 80 \
-d 10.0.0.10 -j ACCEPT
# SNAT:确保内网服务器的回复经过网关返回
iptables -t nat -A POSTROUTING -o eth1 -p tcp --dport 80 \
-d 10.0.0.10 -j SNAT --to-source 10.0.0.1
11.1.3 跨端口转发
# 将公网 8080 端口转发到内网 80 端口
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 8080 \
-j DNAT --to-destination 10.0.0.10:80
# 将公网 8443 端口转发到内网 443 端口
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 8443 \
-j DNAT --to-destination 10.0.0.10:443
# FORWARD 链允许
iptables -A FORWARD -i eth0 -o eth1 -p tcp -m multiport \
--dports 80,443 -d 10.0.0.10 -j ACCEPT
11.1.4 多端口转发脚本
#!/bin/bash
# ═══════════════════════════════════════════════════
# 多服务端口转发脚本
# ═══════════════════════════════════════════════════
WAN_IF="eth0"
LAN_IF="eth1"
GATEWAY_IP="10.0.0.1"
# 定义端口映射规则(公网端口:内网IP:内网端口)
declare -A PORT_MAP=(
["80"]="10.0.0.10:80" # Web HTTP
["443"]="10.0.0.10:443" # Web HTTPS
["2222"]="10.0.0.5:22" # SSH 跳板
["3306"]="10.0.0.200:3306" # MySQL
["5432"]="10.0.0.200:5432" # PostgreSQL
["6379"]="10.0.0.200:6379" # Redis
["8080"]="10.0.0.11:8080" # Tomcat
["9090"]="10.0.0.12:9090" # Prometheus
)
# 启用转发
sysctl -w net.ipv4.ip_forward=1
# 清空 NAT 和 FORWARD 链
iptables -t nat -F PREROUTING
iptables -t nat -F POSTROUTING
iptables -F FORWARD
# 允许已建立的连接
iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# 应用端口映射
for PUB_PORT in "${!PORT_MAP[@]}"; do
TARGET="${PORT_MAP[$PUB_PORT]}"
INTERNAL_IP=$(echo $TARGET | cut -d: -f1)
INTERNAL_PORT=$(echo $TARGET | cut -d: -f2)
echo "映射: $PUB_PORT → $INTERNAL_IP:$INTERNAL_PORT"
# DNAT
iptables -t nat -A PREROUTING -i $WAN_IF -p tcp --dport $PUB_PORT \
-j DNAT --to-destination $INTERNAL_IP:$INTERNAL_PORT
# FORWARD
iptables -A FORWARD -i $WAN_IF -o $LAN_IF -p tcp \
--dport $INTERNAL_PORT -d $INTERNAL_IP -j ACCEPT
done
# SNAT
iptables -t nat -A POSTROUTING -o $LAN_IF -s 10.0.0.0/24 \
-j SNAT --to-source $GATEWAY_IP
# 默认策略
iptables -P FORWARD DROP
echo "Port forwarding configured."
11.2 本机端口转发
11.2.1 使用 REDIRECT
# 将本机 8080 端口的流量重定向到 80 端口
iptables -t nat -A PREROUTING -p tcp --dport 8080 \
-j REDIRECT --to-port 80
# 将本机 8443 端口的流量重定向到 443 端口
iptables -t nat -A PREROUTING -p tcp --dport 8443 \
-j REDIRECT --to-port 443
# 也影响本机进程发出的请求
iptables -t nat -A OUTPUT -p tcp --dport 8080 \
-j REDIRECT --to-port 80
11.2.2 使用 socat 实现端口转发
# socat 可以实现更灵活的端口转发
# 安装:apt install socat
# 将本地 8080 转发到远程 10.0.0.10:80
socat TCP-LISTEN:8080,fork,reuseaddr TCP:10.0.0.10:80 &
# 将本地 8443 转发到远程 10.0.0.10:443
socat TCP-LISTEN:8443,fork,reuseaddr TCP:10.0.0.10:443 &
11.3 内网穿透
11.3.1 场景说明
内网穿透用于让外部网络能够访问位于 NAT 后面的内网服务。
外部用户 公网服务器 (跳板) 内网服务器
203.0.113.1 10.0.0.10
│ │
───→ 端口 2222 ─────┤ │
├── DNAT ──→ 端口 22 ────┤
│ │
←─── 响应 ←────┤←── 反向 NAT ──────────←─┤
11.3.2 使用 iptables + SSH 隧道
# ─── 步骤 1:在内网服务器上建立 SSH 反向隧道 ───
# 在内网服务器上执行:
ssh -R 2222:localhost:22 user@203.0.113.1 -N
# ─── 步骤 2:在公网服务器上配置 DNAT ───
# 在公网服务器上执行:
iptables -t nat -A PREROUTING -p tcp --dport 2222 \
-j DNAT --to-destination 127.0.0.1:2222
# ─── 步骤 3:外部用户通过公网服务器访问内网 SSH ───
ssh -p 2222 user@203.0.113.1
11.3.3 使用 iptables 实现固定端口映射
#!/bin/bash
# 公网服务器:将多个高端口映射到不同内网服务器
# 内网服务器 1 的 SSH
iptables -t nat -A PREROUTING -p tcp --dport 2201 \
-j DNAT --to-destination 10.0.0.10:22
# 内网服务器 2 的 SSH
iptables -t nat -A PREROUTING -p tcp --dport 2202 \
-j DNAT --to-destination 10.0.0.11:22
# 内网服务器 1 的 Web
iptables -t nat -A PREROUTING -p tcp --dport 8001 \
-j DNAT --to-destination 10.0.0.10:80
# 内网服务器 2 的 Web
iptables -t nat -A PREROUTING -p tcp --dport 8002 \
-j DNAT --to-destination 10.0.0.11:80
# FORWARD 规则
iptables -A FORWARD -i eth0 -o eth1 -p tcp \
-m multiport --dports 22,80 -d 10.0.0.0/24 -j ACCEPT
11.4 简单负载均衡
11.4.1 基于 statistic 模块的随机负载均衡
#!/bin/bash
# ═══════════════════════════════════════════════════
# iptables 简单负载均衡
# 将 HTTP 流量分发到 3 台后端 Web 服务器
# ═══════════════════════════════════════════════════
# 后端服务器列表
BACKENDS=("10.0.0.10" "10.0.0.11" "10.0.0.12")
NUM_BACKENDS=${#BACKENDS[@]}
# 第一台:1/3 概率
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 \
-m statistic --mode random --probability 0.33 \
-j DNAT --to-destination ${BACKENDS[0]}:80
# 第二台:剩余流量的 1/2(即总体 1/3)
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 \
-m statistic --mode random --probability 0.50 \
-j DNAT --to-destination ${BACKENDS[1]}:80
# 第三台:剩余所有流量(即总体 1/3)
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 \
-j DNAT --to-destination ${BACKENDS[2]}:80
# HTTPS 负载均衡
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 443 \
-m statistic --mode random --probability 0.33 \
-j DNAT --to-destination ${BACKENDS[0]}:443
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 443 \
-m statistic --mode random --probability 0.50 \
-j DNAT --to-destination ${BACKENDS[1]}:443
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 443 \
-j DNAT --to-destination ${BACKENDS[2]}:443
11.4.2 基于 nth 模式的轮询负载均衡
# 每 3 个包轮询一次
# 第 1 个包 → 服务器 1
iptables -t nat -A PREROUTING -p tcp --dport 80 \
-m statistic --mode nth --every 3 --packet 0 \
-j DNAT --to-destination 10.0.0.10:80
# 第 2 个包 → 服务器 2
iptables -t nat -A PREROUTING -p tcp --dport 80 \
-m statistic --mode nth --every 2 --packet 0 \
-j DNAT --to-destination 10.0.0.11:80
# 第 3 个包 → 服务器 3
iptables -t nat -A PREROUTING -p tcp --dport 80 \
-j DNAT --to-destination 10.0.0.12:80
11.4.3 负载均衡注意事项
| 维度 | iptables 方案 | 专业方案(Nginx/HAProxy) |
|---|---|---|
| 算法 | 随机/轮询 | 轮询/最少连接/IP哈希/权重 |
| 健康检查 | 不支持 | 支持 |
| 会话保持 | 不支持 | 支持(cookie/IP哈希) |
| SSL 终止 | 不支持 | 支持 |
| 性能 | 高(内核态) | 中(用户态) |
| 适用场景 | 简单场景 | 生产环境 |
建议:对于简单场景或作为底层流量分发,iptables 负载均衡足够;对于生产环境,建议使用 Nginx、HAProxy 或 LVS。
11.5 透明代理
11.5.1 透明代理原理
透明代理(Transparent Proxy)在客户端无感知的情况下拦截 HTTP 流量并转发给代理服务器处理。
客户端 网关 (iptables) Squid 代理 互联网
│ │ │ │
│── HTTP 请求 ────────→│ │ │
│ │── REDIRECT ─────────→│ │
│ │ (端口 3128) │── 转发请求 ─────→│
│ │ │←── 响应 ─────────│
│←── 响应 ─────────────│←── 代理响应 ─────────│ │
11.5.2 Squid 透明代理配置
#!/bin/bash
# ═══════════════════════════════════════════════════
# Squid 透明代理配置
# ═══════════════════════════════════════════════════
# ─── Squid 配置(/etc/squid/squid.conf)───
# http_port 3128 transparent
# acl localnet src 10.0.0.0/24
# http_access allow localnet
# http_access deny all
# ─── iptables 配置 ───
# 启用转发
sysctl -w net.ipv4.ip_forward=1
# 将内网的 HTTP 流量重定向到 Squid
iptables -t nat -A PREROUTING -i eth1 -p tcp --dport 80 \
-j REDIRECT --to-port 3128
# 允许 Squid 发起的出站连接
iptables -A OUTPUT -m owner --uid-owner proxy -j ACCEPT
# 允许已建立的连接
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# 允许回环
iptables -A INPUT -i lo -j ACCEPT
# 允许 Squid 访问 DNS
iptables -A OUTPUT -p udp --dport 53 -j ACCEPT
# 默认策略
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT DROP
11.5.3 HTTPS 透明代理(SSL 拦截)
注意:HTTPS 透明代理需要 SSL 中间人攻击(MITM),在企业环境中使用需遵守相关法规和员工知情同意。
# 将 HTTPS 流量重定向到 Squid 的 SSL 端口
iptables -t nat -A PREROUTING -i eth1 -p tcp --dport 443 \
-j REDIRECT --to-port 3129
11.5.4 使用 TPROXY 实现透明代理
#!/bin/bash
# TPROXY 方式透明代理(不修改数据包,更高效)
# ─── 步骤 1:在 raw 表跳过连接跟踪 ───
iptables -t raw -A PREROUTING -p tcp --dport 80 -j NOTRACK
# ─── 步骤 2:在 mangle 表使用 TPROXY ───
iptables -t mangle -A PREROUTING -p tcp --dport 80 \
-j TPROXY --tproxy-mark 0x1/0x1 --on-port 3129
# ─── 步骤 3:策略路由 ───
ip rule add fwmark 1 lookup 100
ip route add local 0.0.0.0/0 dev lo table 100
11.6 端口转发的安全加固
11.6.1 限制来源 IP
# 只允许特定 IP 访问转发的端口
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 3306 \
-s 192.168.1.100 -j DNAT --to-destination 10.0.0.200:3306
# 只允许特定网段访问
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 22 \
-s 10.0.0.0/8 -j DNAT --to-destination 10.0.0.5:22
11.6.2 限制连接速率
# 限制转发端口的新连接速率
iptables -A FORWARD -i eth0 -o eth1 -p tcp --dport 80 \
-d 10.0.0.10 --syn \
-m hashlimit --hashlimit-above 100/sec \
--hashlimit-mode srcip --hashlimit-name web_limit \
-j DROP
11.6.3 隐藏内部拓扑
# MASQUERADE 确保内网服务器看不到外部真实 IP
iptables -t nat -A POSTROUTING -o eth1 -p tcp --dport 80 \
-d 10.0.0.10 -j MASQUERADE
# 或使用 SNAT
iptables -t nat -A POSTROUTING -o eth1 -p tcp --dport 80 \
-d 10.0.0.10 -j SNAT --to-source 10.0.0.1
11.7 完整业务场景
11.7.1 企业级端口转发网关
#!/bin/bash
# ═══════════════════════════════════════════════════
# 企业级端口转发网关
# 网络拓扑:
# eth0: 公网 203.0.113.1
# eth1: 内网 10.0.0.1/24
# eth2: DMZ 172.16.0.1/24
# ═══════════════════════════════════════════════════
# 启用转发
sysctl -w net.ipv4.ip_forward=1
# ─── 清空规则 ───
iptables -F
iptables -t nat -F
iptables -X
# ─── 默认策略 ───
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT
# ─── 已建立的连接 ───
iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# ─── 回环接口 ───
iptables -A INPUT -i lo -j ACCEPT
# ─── 管理访问 ───
iptables -A INPUT -p tcp --dport 22 -s 192.168.1.0/24 -j ACCEPT
# ─── 端口转发规则 ───
# Web 服务 → DMZ Web 服务器
iptables -t nat -A PREROUTING -i eth0 -p tcp -m multiport \
--dports 80,443 -j DNAT --to-destination 172.16.0.10
iptables -A FORWARD -i eth0 -o eth2 -p tcp -m multiport \
--dports 80,443 -d 172.16.0.10 -j ACCEPT
# SSH 跳板 → 内网管理服务器
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 2222 \
-j DNAT --to-destination 10.0.0.5:22
iptables -A FORWARD -i eth0 -o eth1 -p tcp --dport 22 \
-d 10.0.0.5 -j ACCEPT
# 邮件服务 → DMZ 邮件服务器
iptables -t nat -A PREROUTING -i eth0 -p tcp -m multiport \
--dports 25,110,143,465,587,993 -j DNAT --to-destination 172.16.0.20
iptables -A FORWARD -i eth0 -o eth2 -p tcp -m multiport \
--dports 25,110,143,465,587,993 -d 172.16.0.20 -j ACCEPT
# ─── DMZ 访问内网数据库(仅限 MySQL)───
iptables -A FORWARD -i eth2 -o eth1 -p tcp --dport 3306 \
-s 172.16.0.10 -d 10.0.0.200 -j ACCEPT
# ─── 内网和 DMZ 出站 ───
iptables -A FORWARD -i eth1 -o eth0 -j ACCEPT
iptables -A FORWARD -i eth2 -o eth0 -j ACCEPT
# ─── SNAT ───
iptables -t nat -A POSTROUTING -o eth0 -s 10.0.0.0/24 \
-j SNAT --to-source 203.0.113.1
iptables -t nat -A POSTROUTING -o eth0 -s 172.16.0.0/24 \
-j SNAT --to-source 203.0.113.1
# ─── 日志 ───
iptables -A FORWARD -m limit --limit 5/min \
-j LOG --log-prefix "IPT-FWD-DROP: "
echo "Enterprise gateway configured."
11.8 注意事项
⚠️ IP 转发必须启用:所有转发场景都需要
net.ipv4.ip_forward = 1。
⚠️ FORWARD 链必须允许:DNAT 只改变目的地址,FORWARD 链仍然需要显式允许转发流量。
⚠️ iptables 负载均衡不支持健康检查:如果后端服务器宕机,流量仍会被分发到它。生产环境建议使用 LVS + keepalived 或 Nginx/HAProxy。
⚠️ conntrack 与端口转发:大量短连接会快速填满 conntrack 表。根据并发连接数合理调整
nf_conntrack_max。
11.9 扩展阅读
| 资源 | 说明 |
|---|---|
| LVS(Linux Virtual Server) | 内核级四层负载均衡 |
| HAProxy | 高性能七层负载均衡 |
| Nginx | Web 服务器和反向代理 |
| Squid | HTTP 代理服务器 |
man ssh | SSH 隧道和端口转发 |
本章小结
| 技术 | 命令/模块 | 用途 |
|---|---|---|
| 端口转发 | DNAT | 将流量从公网端口转发到内网 |
| 本机重定向 | REDIRECT | 将本机端口流量重定向 |
| 简单负载均衡 | statistic + DNAT | 随机/轮询分发流量 |
| 透明代理 | REDIRECT / TPROXY | 无感知 HTTP 代理 |
| 内网穿透 | SSH -R + DNAT | 从外部访问内网服务 |
下一章:第 12 章:安全加固规则,将学习防扫描、防 DDoS 和速率限制等安全规则。