编辑/etc/network/interfaces 网络配置
nano /etc/network/interfaces
黏贴配置信息
auto lo
iface lo inet loopback
# 物理口
iface eno1 inet manual
iface eno2 inet manual
# ===== 外网桥 =====
auto vmbr0
iface vmbr0 inet static
address 51.77.64.81/24
gateway 51.77.64.254
bridge-ports eno1
bridge-stp off
bridge-fd 0
# 出站 DNS(也可写到 /etc/resolv.conf.d 或 systemd-resolved)
dns-nameservers 8.8.8.8 2001:4860:4860::8888
# IPv6(OVH 样式 /128 + 非直连网关)
iface vmbr0 inet6 static
address 2001:41d0:700:2251::1/128
# 给“非直连”的 IPv6 网关先加一条到网关本身的直连路由,再加默认路由(onlink)
post-up ip -6 route add 2001:41d0:0700:22ff:00ff:00ff:00ff:00ff dev vmbr0 || true
post-up ip -6 route add default via 2001:41d0:0700:22ff:00ff:00ff:00ff:00ff dev vmbr0 onlink || true
pre-down ip -6 route del default via 2001:41d0:0700:22ff:00ff:00ff:00ff:00ff dev vmbr0 || true
pre-down ip -6 route del 2001:41d0:0700:22ff:00ff:00ff:00ff:00ff dev vmbr0 || true
# ===== 内网桥(NAT)=====
auto vmbr1
iface vmbr1 inet static
address 10.10.10.1/24
bridge-ports none
bridge-stp off
bridge-fd 0
# NAT44
post-up iptables -t nat -C POSTROUTING -s 10.10.10.0/24 -o vmbr0 -j MASQUERADE 2>/dev/null || iptables -t nat -A POSTROUTING -s 10.10.10.0/24 -o vmbr0 -j MASQUERADE
post-up iptables -C FORWARD -i vmbr1 -o vmbr0 -j ACCEPT 2>/dev/null || iptables -A FORWARD -i vmbr1 -o vmbr0 -j ACCEPT
post-up iptables -C FORWARD -i vmbr0 -o vmbr1 -m state --state RELATED,ESTABLISHED -j ACCEPT 2>/dev/null || iptables -A FORWARD -i vmbr0 -o vmbr1 -m state --state RELATED,ESTABLISHED -j ACCEPT
pre-down iptables -t nat -D POSTROUTING -s 10.10.10.0/24 -o vmbr0 -j MASQUERADE 2>/dev/null || true
pre-down iptables -D FORWARD -i vmbr1 -o vmbr0 -j ACCEPT 2>/dev/null || true
pre-down iptables -D FORWARD -i vmbr0 -o vmbr1 -m state --state RELATED,ESTABLISHED -j ACCEPT 2>/dev/null || true
# 内网 IPv6:使用 ULA 前缀 + NAT66 以便 VMs 能出 IPv6(你只有 /128 无法下发可路由段)
iface vmbr1 inet6 static
address fd10:10:10::1/64
post-up ip6tables -t nat -C POSTROUTING -s fd10:10:10::/64 -o vmbr0 -j MASQUERADE 2>/dev/null || ip6tables -t nat -A POSTROUTING -s fd10:10:10::/64 -o vmbr0 -j MASQUERADE
post-up ip6tables -C FORWARD -i vmbr1 -o vmbr0 -j ACCEPT 2>/dev/null || ip6tables -A FORWARD -i vmbr1 -o vmbr0 -j ACCEPT
post-up ip6tables -C FORWARD -i vmbr0 -o vmbr1 -m state --state RELATED,ESTABLISHED -j ACCEPT 2>/dev/null || ip6tables -A FORWARD -i vmbr0 -o vmbr1 -m state --state RELATED,ESTABLISHED -j ACCEPT
pre-down ip6tables -t nat -D POSTROUTING -s fd10:10:10::/64 -o vmbr0 -j MASQUERADE 2>/dev/null || true
pre-down ip6tables -D FORWARD -i vmbr1 -o vmbr0 -j ACCEPT 2>/dev/null || true
pre-down ip6tables -D FORWARD -i vmbr0 -o vmbr1 -m state --state RELATED,ESTABLISHED -j ACCEPT 2>/dev/null || true
source /etc/network/interfaces.d/*
打开内核转发,永久生效
nano /etc/sysctl.conf
net.ipv4.ip_forward=1
net.ipv6.conf.all.forwarding=1
net.ipv6.conf.all.accept_ra=0
生效:
sysctl --system
配置DHCP 信息
安装DHCP服务器
apt-get update
apt-get install -y isc-dhcp-server
配置/etc/default/isc-dhcp-server
nano /etc/default/isc-dhcp-server
INTERFACESv4="vmbr1"
INTERFACESv6=""
配置/etc/dhcp/dhcpd.conf
nano /etc/dhcp/dhcpd.conf
# /etc/dhcp/dhcpd.conf — ISC DHCP server v4 配置
# 作用:给 vmbr1(10.10.10.0/24)下的虚拟机自动分配 IPv4 地址
# 全局参数
default-lease-time 600; # 10 分钟
max-lease-time 7200; # 2 小时
authoritative; # 本服务器为该网段权威 DHCP
# 可选:设定一个自定义域名(按需修改/删除)
option domain-name "lan.local";
# 内网子网配置(vmbr1 = 10.10.10.1/24)
subnet 10.10.10.0 netmask 255.255.255.0 {
# 动态地址池
range 10.10.10.100 10.10.10.200;
# 网关(缺省路由)
option routers 10.10.10.1;
# DNS 服务器
option domain-name-servers 8.8.8.8, 1.1.1.1;
# 广播地址(可选)
option broadcast-address 10.10.10.255;
}
# === 示例:静态保留(可按需添加/删除)===
# 说明:指定设备 MAC,固定一个 IP;请修改硬件地址和 IP
# host vm1 {
# hardware ethernet aa:bb:cc:dd:ee:ff;
# fixed-address 10.10.10.10;
# }
启动DHCP
systemctl enable --now isc-dhcp-server
systemctl status isc-dhcp-server --no-pager
IPv6:用 radvd 做 RA(SLAAC),配合 NAT66 出口
编辑/etc/radvd.conf
nano /etc/radvd.conf
interface vmbr1 {
AdvSendAdvert on;
MaxRtrAdvInterval 30;
prefix fd10:10:10::/64 {
AdvOnLink on;
AdvAutonomous on; # SLAAC
};
RDNSS 2001:4860:4860::8888 2001:4860:4860::8844 {
AdvRDNSSLifetime 600;
};
};
安装并启用
apt-get install -y radvd
systemctl enable --now radvd
使网络配置生效
ifreload -a 2>/dev/null || { systemctl restart networking || (ifdown vmbr0 && ifup vmbr0); }
查看DHCP状态
systemctl restart isc-dhcp-server
systemctl status isc-dhcp-server --no-pager
宿主加静态DNS配置
echo "nameserver 8.8.8.8" >> /etc/resolv.conf
echo "nameserver 2001:4860:4860::8888" >> /etc/resolv.conf
创建IPv4 + IPv6 端口映射的脚本
nano setup_nat_port_forward.sh
#!/usr/bin/env bash
# =========================================================
# setup_nat_port_forward.sh — 一键安装/加载 IPv4+IPv6 端口转发
# 适配 Debian/Proxmox (iptables-nft + ip6tables-nft)
# 管理文件:/etc/nat_port_forwards.conf
# =========================================================
set -Eeuo pipefail
# ===== 基础参数(按需修改) =====
EXT_IF="vmbr0" # 外网接口/桥
CONF="/etc/nat_port_forwards.conf" # 端口映射配置文件
COMMENT_TAG="DNAT-MGR"
HOOK_UP="/etc/network/if-up.d/nat-dnat"
HOOK_DOWN="/etc/network/if-down.d/nat-dnat"
die(){ echo "❌ Error: $*" >&2; exit 1; }
need(){ command -v "$1" >/dev/null 2>&1 || die "缺少命令: $1"; }
need iptables
need ip6tables
# ===== 首次运行生成模板 =====
if [ ! -f "$CONF" ]; then
cat >"$CONF" <<'EOF'
# /etc/nat_port_forwards.conf
# 一行一条映射,格式:
# v4 <公网端口> <协议> <内网IPv4> <内网端口>
# v6 <公网端口> <协议> <内网IPv6> <内网端口>
# 协议可写:tcp / udp / tcp+udp
#
# 例:把公网 45678 → Win 的 RDP 3389(IPv4 + IPv6)
v4 45678 tcp 10.10.10.100 3389
v6 45678 tcp fd10:10:10::100 3389
EOF
echo "✅ 已创建默认配置:$CONF"
fi
echo "🧹 清理旧 DNAT 规则..."
# 清理旧 v4
iptables -t nat -S 2>/dev/null | grep "$COMMENT_TAG" || true | while read -r L; do
# 形如:-A PREROUTING ... -m comment --comment DNAT-MGR
# 转换成 -D 命令以删除
iptables -t nat ${L/-A /-D } || true
done
iptables -S 2>/dev/null | grep "$COMMENT_TAG" || true | while read -r L; do
iptables ${L/-A /-D } || true
done
# 清理旧 v6
ip6tables -t nat -S 2>/dev/null | grep "$COMMENT_TAG" || true | while read -r L; do
ip6tables -t nat ${L/-A /-D } || true
done
ip6tables -S 2>/dev/null | grep "$COMMENT_TAG" || true | while read -r L; do
ip6tables ${L/-A /-D } || true
done
echo "⚙️ 应用新映射..."
while read -r line; do
[[ -z "$line" || "$line" =~ ^# ]] && continue
set -- $line
family="$1"; pub_port="$2"; proto="$3"; dst_ip="$4"; dst_port="$5"
if [[ "$family" == "v4" ]]; then
if [[ "$proto" == *tcp* ]]; then
iptables -t nat -A PREROUTING -i "$EXT_IF" -p tcp --dport "$pub_port" -j DNAT --to-destination "${dst_ip}:${dst_port}" -m comment --comment "$COMMENT_TAG"
iptables -A FORWARD -p tcp -d "$dst_ip" --dport "$dst_port" -j ACCEPT -m comment --comment "$COMMENT_TAG"
fi
if [[ "$proto" == *udp* ]]; then
iptables -t nat -A PREROUTING -i "$EXT_IF" -p udp --dport "$pub_port" -j DNAT --to-destination "${dst_ip}:${dst_port}" -m comment --comment "$COMMENT_TAG"
iptables -A FORWARD -p udp -d "$dst_ip" --dport "$dst_port" -j ACCEPT -m comment --comment "$COMMENT_TAG"
fi
elif [[ "$family" == "v6" ]]; then
if [[ "$proto" == *tcp* ]]; then
ip6tables -t nat -A PREROUTING -i "$EXT_IF" -p tcp --dport "$pub_port" -j DNAT --to-destination "[${dst_ip}]:${dst_port}" -m comment --comment "$COMMENT_TAG"
ip6tables -A FORWARD -p tcp -d "$dst_ip" --dport "$dst_port" -j ACCEPT -m comment --comment "$COMMENT_TAG"
fi
if [[ "$proto" == *udp* ]]; then
ip6tables -t nat -A PREROUTING -i "$EXT_IF" -p udp --dport "$pub_port" -j DNAT --to-destination "[${dst_ip}]:${dst_port}" -m comment --comment "$COMMENT_TAG"
ip6tables -A FORWARD -p udp -d "$dst_ip" --dport "$dst_port" -j ACCEPT -m comment --comment "$COMMENT_TAG"
fi
else
echo "⚠️ 跳过未知 family: $family"
fi
done < "$CONF"
echo "✅ 规则已加载完毕"
# ===== 持久化钩子:网络起来时自动套用 =====
mkdir -p /etc/network/if-up.d /etc/network/if-down.d
cat >"$HOOK_UP" <<EOF
#!/bin/bash
[ "\$IFACE" = "$EXT_IF" ] || exit 0
bash $0 || true
EOF
cat >"$HOOK_DOWN" <<'EOF'
#!/bin/bash
# 简单清理 nat 表,避免接口下线残留
iptables -t nat -F || true
ip6tables -t nat -F || true
EOF
chmod +x "$HOOK_UP" "$HOOK_DOWN"
echo "🔁 已注册网络钩子:$HOOK_UP / $HOOK_DOWN"
给与权限
chmod +x /root/setup_nat_port_forward.sh
增加或减少映射就编辑/etc/nat_port_forwards.conf
nano /etc/nat_port_forwards.conf
示例
# IPv4 映射
v4 5666 tcp 10.10.10.50 5666
v4 45678 tcp+udp 10.10.10.51 3389
# IPv6 映射(可选)
v6 8080 tcp fd10:10:10::50 80
v6 8443 tcp fd10:10:10::51 443
执行加载生效
bash /root/setup_nat_port_forward.sh
验证结果
iptables -t nat -S | grep DNAT-MGR
ip6tables -t nat -S | grep DNAT-MGR
转发脚本pve启动自动运行
固化脚本位置
install -m 0755 setup_nat_port_forward.sh /usr/local/sbin/setup_nat_port_forward.sh
新增 systemd 服务(开机自动跑一次 + 等待 vmbr0 就绪)
cat >/etc/systemd/system/nat-dnat.service <<'EOF'
[Unit]
Description=Load IPv4+IPv6 DNAT port forwards (setup_nat_port_forward.sh)
# 等待网络完全就绪 & PVE 服务起来(避免太早执行)
Wants=network-online.target
After=network-online.target pve-cluster.service
# 如启用PVE自带防火墙,可按需再加:After=pve-firewall.service
[Service]
Type=oneshot
# 先等 vmbr0 真正 UP(最多等 30s),再执行主脚本
ExecStartPre=/bin/sh -lc 'for i in $(seq 1 30); do ip link show vmbr0 2>/dev/null | grep -q "state UP" && exit 0; sleep 1; done; echo "vmbr0 not UP, continue anyway"'
# 如需等地址就绪,可改成:ip -4 addr show dev vmbr0 | grep -q "inet "
ExecStart=/usr/bin/env bash -lc '/usr/local/sbin/setup_nat_port_forward.sh'
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable nat-dnat.service
systemctl start nat-dnat.service
(可选但推荐)保留 ifup 钩子,处理“接口重启”场景
你的脚本已经会写入 /etc/network/if-up.d/nat-dnat,只要确认它是可执行的即可:
chmod +x /etc/network/if-up.d/nat-dnat /etc/network/if-down.d/nat-dnat
这样即使你将来 ifreload -a 或某次 vmbr0 单独 down/up,也会自动重载规则。
开机后验证
重启整机后检查是否已经自动加载:
iptables -t nat -S | grep DNAT-MGR
iptables -S | grep DNAT-MGR
ip6tables -t nat -S | grep DNAT-MGR
ip6tables -S | grep DNAT-MGR
能看到带 DNAT-MGR 的 PREROUTING/FORWARD 规则就 OK 了。
评论区