KVM 虚拟机端口转发配置
KVM 虚拟机端口转发配置
通过 iptables 将物理机端口转发到 KVM 虚拟机,实现公网访问虚拟机内部服务。
网络拓扑
1 | |
快速开始
1 | |
脚本说明
| 文件 | 功能 | 说明 |
|---|---|---|
| Makefile | 快捷命令 | setup/remove/debug,支持自定义参数 |
| setup-port-forward.sh | 配置端口转发 | 配置 6 条规则:IP转发 + 5个iptables规则 |
| remove-port-forward.sh | 删除端口转发 | 循环删除所有匹配规则并验证 |
| debug-port-forward.sh | 诊断配置问题 | 检查 7 项(消除重复检查,性能优化) |
iptables 规则详解
setup-port-forward.sh 配置了 6 条规则:
| 序号 | 规则 | 必须 | 作用 |
|---|---|---|---|
| 1 | IP 转发 | ✓ | 允许内核在网络接口之间转发数据包 |
| 2 | INPUT | ✓ | 允许外部流量进入物理机端口(公网访问必需) |
| 3 | PREROUTING (DNAT) | ✓ | 将外部流量目标地址改为虚拟机(核心规则) |
| 4 | OUTPUT (DNAT) | ✗ | 处理物理机访问自己 IP 的流量(本地测试用) |
| 5 | FORWARD | ✓ | 允许数据包在物理机和虚拟机之间双向转发 |
| 6 | POSTROUTING (MASQUERADE) | ✓ | 源地址改为物理机 IP(虚拟机内网 IP 无法被公网识别) |
流量路径详解
外部访问流程(公网 → 虚拟机):
1 | |
物理机本地测试流程:
1 | |
手动配置
如果需要手动配置(按数据流入顺序):
1 | |
测试指南
本地测试
1 | |
公网测试
重要: 从物理机访问公网 IP 会失败(hairpin NAT 问题),这是正常的。
正确的测试方法:
从外部机器测试(推荐)
1
2# 从另一台电脑、云服务器执行
curl http://116.6.197.242:16589从手机测试
- 手机连接 4G/5G(不要连 WiFi)
- 浏览器访问
http://116.6.197.242:16589
使用在线工具
路由器配置
确保路由器已配置端口转发:
1 | |
故障排查
运行诊断脚本
1 | |
诊断脚本会检查(所有检查只执行一次,消除重复):
- 物理机端口监听状态
- NAT PREROUTING(外部流量转发)
- NAT OUTPUT(本机流量转发)
- INPUT(公网访问必需)
- FORWARD(流量转发)
- NAT POSTROUTING(源地址转换)
- IP 转发状态
- 虚拟机连通性
- 虚拟机端口状态
- 路由器配置提示
- 抓包监控命令
最后给出诊断总结,检查 7 项核心配置:
- NAT PREROUTING, NAT OUTPUT, INPUT, FORWARD, NAT POSTROUTING
- IP 转发, 虚拟机端口
常见问题
虚拟机服务未监听
1
2
3# 在虚拟机内检查
ss -tlnp | grep 16589
# 确保监听在 0.0.0.0:16589 而不是 127.0.0.1:16589物理机防火墙阻止
1
2
3
4# 检查 INPUT 链
sudo iptables -L INPUT -n -v
# 添加允许规则
sudo iptables -I INPUT -p tcp --dport 16589 -j ACCEPT路由器端口转发未生效
1
2# 在物理机上抓包,从外部访问时观察
sudo tcpdump -i ens2f1 port 16589 -nIP 转发未启用
1
2
3
4# 检查
cat /proc/sys/net/ipv4/ip_forward
# 启用
echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward
常见错误和解决方案
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 公网访问失败 | INPUT 规则未配置 | sudo iptables -I INPUT -p tcp --dport 16589 -j ACCEPT |
| 物理机本地测试失败 | OUTPUT 规则未配置 | 运行 sudo ./setup-port-forward.sh |
| 虚拟机端口无响应 | 服务未运行或监听 127.0.0.1 | 检查服务,确保监听 0.0.0.0:16589 |
| 从物理机访问公网 IP 失败 | hairpin NAT 问题 | 正常现象,从外部机器测试 |
| IP 转发未启用 | 系统配置 | echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward |
| 规则删不干净 | 重复添加 | 使用 sudo ./remove-port-forward.sh(循环删除) |
持久化配置
使用 iptables-persistent (Debian/Ubuntu):
1 | |
自定义配置
使用 Makefile 自定义参数:
1 | |
或直接设置环境变量:
1 | |
注意事项
MASQUERADE 的必要性
- 虚拟机 IP (192.168.122.79) 是内网地址,公网无法识别
- 没有 MASQUERADE,虚拟机无法正确回复公网客户端
- MASQUERADE 让虚拟机以为请求来自物理机,回复也发给物理机
虚拟机服务配置
1
2# 在虚拟机内启动测试服务
python3 -m http.server 16589- 必须监听
0.0.0.0:16589,不能只监听127.0.0.1 - 检查虚拟机内防火墙是否允许端口
- 必须监听
路由器配置
- 必须配置端口转发:
公网端口 → 物理机IP:端口 - 使用
tcpdump验证路由器是否转发流量
- 必须配置端口转发:
端口选择
- 避免运营商封禁的端口(80, 443, 8080 等)
- 建议使用高端口 (10000-65535)
持久化
- iptables 规则重启后会丢失
- 使用
iptables-persistent持久化
快速参考
常用命令
1 | |
验证配置
1 | |
相关链接
KVM 虚拟机端口转发配置
https://realwujing.github.io/linux/kernel/net/port-forward/README/