一、需求背景
Hyper-V 自带的 Default Switch 使用方便,虚拟机通常可以自动获取 IP 并访问互联网。但它的内部网段和网关由 Windows 自动管理,不适合作为长期固定网络使用。
例如,某次 Default Switch 的地址可能是:
172.26.96.1/20
之后又可能变成:
172.18.48.1/20
如果 Ubuntu 配置了静态 IP 和静态网关,一旦 Default Switch 的网段变化,Ubuntu 就会失去网络连接。
本文使用 Internal 类型的 Hyper-V 交换机配合 WinNAT,实现以下目标:
- Ubuntu 使用固定 IP;
- Ubuntu 使用固定网关;
- Ubuntu 可以访问互联网;
- Ubuntu 可以和 Windows 宿主机双向通信;
- 不再受
Default Switch网段变化影响。
微软官方的 Hyper-V NAT 方案也是先创建内部交换机,再为宿主机虚拟网卡配置网关地址,最后通过 New-NetNat 创建 NAT。WinNAT 本身不负责给普通虚拟机分配 IP,因此虚拟机需要手动设置 IP、网关和 DNS。
二、环境规划
本文使用下面的网络配置:
| 配置项 | 地址 |
|---|---|
| 虚拟交换机名称 | Ubuntu-FixedNAT |
| NAT 名称 | Ubuntu-FixedNAT |
| 内部网段 | 172.26.96.0/20 |
| 子网掩码 | 255.255.240.0 |
| Windows 宿主机地址 | 172.26.96.1 |
| Ubuntu 固定 IP | 172.26.107.185 |
| Ubuntu 默认网关 | 172.26.96.1 |
| Ubuntu DNS | 223.5.5.5、114.114.114.114 |
172.26.96.0/20 的地址范围为:
172.26.96.0 ~ 172.26.111.255
因此:
172.26.107.185/20
属于该网段,可以正常使用。
最终网络结构如下:
互联网
│
Windows 物理网卡
│
WinNAT
│
172.26.96.1/20
Windows 宿主机虚拟网卡
│
Ubuntu-FixedNAT
Hyper-V 内部交换机
│
172.26.107.185/20
Ubuntu VM
Internal 类型的交换机会在 Windows 宿主机上创建对应的虚拟网卡,因此宿主机和虚拟机可以通过这个内部网络直接通信;增加 NAT 后,虚拟机还可以通过宿主机访问外部网络。
三、配置前检查
以下 Windows 命令必须在 管理员 PowerShell 中执行。
首先查看当前 Hyper-V 交换机:
Get-VMSwitch |
Format-Table Name, SwitchType
查看已有 NAT:
Get-NetNat |
Format-Table Name, InternalIPInterfaceAddressPrefix
查看目标网段是否已经被使用:
Get-NetIPAddress -AddressFamily IPv4 |
Where-Object {
$_.IPAddress -like "172.26.*"
}
Get-NetRoute -AddressFamily IPv4 |
Where-Object {
$_.DestinationPrefix -eq "172.26.96.0/20"
}
如果目标网段已经被 VPN、Docker、Windows Containers、WSL 或其他虚拟网络使用,应当换一个网段,例如:
192.168.200.0/24
微软当前文档指出,一台 Windows 宿主机通常只支持一个 WinNAT 网络。如果 Get-NetNat 已经显示其他 NAT,不要直接删除,应先确认它是否由 Docker 或 Windows Containers 使用。
四、创建固定的 Hyper-V 内部交换机
执行:
New-VMSwitch `
-Name "Ubuntu-FixedNAT" `
-SwitchType Internal
检查创建结果:
Get-VMSwitch -Name "Ubuntu-FixedNAT" |
Format-List Name, SwitchType
应当看到:
Name : Ubuntu-FixedNAT
SwitchType : Internal
Windows 还会创建一个虚拟网卡:
vEthernet (Ubuntu-FixedNAT)
查看该网卡:
Get-NetAdapter -Name "vEthernet (Ubuntu-FixedNAT)"
微软支持使用 New-VMSwitch -SwitchType Internal 创建内部交换机;与外部交换机相比,内部交换机不会直接绑定物理网卡,一般对宿主机现有网络影响更小。
五、配置固定网关地址
获取虚拟网卡的接口编号:
$adapter = Get-NetAdapter `
-Name "vEthernet (Ubuntu-FixedNAT)"
$adapter |
Format-Table Name, ifIndex, Status
给该网卡配置固定地址:
New-NetIPAddress `
-InterfaceIndex $adapter.ifIndex `
-IPAddress 172.26.96.1 `
-PrefixLength 20
检查配置:
Get-NetIPAddress `
-InterfaceAlias "vEthernet (Ubuntu-FixedNAT)" `
-AddressFamily IPv4 |
Format-Table IPAddress, PrefixLength, InterfaceAlias
预期结果:
IPAddress PrefixLength InterfaceAlias
--------- ------------ --------------
172.26.96.1 20 vEthernet (Ubuntu-FixedNAT)
注意:这张 Windows 虚拟网卡不要设置默认网关。
这里的:
172.26.96.1
本身就是 Ubuntu 使用的网关地址。
如果重复执行命令时提示地址已存在,可以先确认:
Get-NetIPAddress `
-InterfaceAlias "vEthernet (Ubuntu-FixedNAT)" `
-AddressFamily IPv4
地址正确就不需要再次添加。
六、创建 WinNAT
执行:
New-NetNat `
-Name "Ubuntu-FixedNAT" `
-InternalIPInterfaceAddressPrefix "172.26.96.0/20"
查看 NAT:
Get-NetNat -Name "Ubuntu-FixedNAT" |
Format-List Name, InternalIPInterfaceAddressPrefix, Active
预期看到:
Name : Ubuntu-FixedNAT
InternalIPInterfaceAddressPrefix : 172.26.96.0/20
NAT 会把 Ubuntu 发往互联网的流量转换为 Windows 宿主机的外部地址。微软官方配置流程同样使用 New-NetNat 配置内部网络前缀。
七、将 Ubuntu 连接到新交换机
先查看虚拟机名称:
Get-VM |
Format-Table Name, State
建议关闭 Ubuntu:
Stop-VM -Name "Ubuntu"
将虚拟网卡连接到新交换机:
Connect-VMNetworkAdapter `
-VMName "Ubuntu" `
-SwitchName "Ubuntu-FixedNAT"
如果虚拟机实际名称不是 Ubuntu,需要替换成 Get-VM 显示的名称。
检查连接:
Get-VMNetworkAdapter -VMName "Ubuntu" |
Format-Table Name, SwitchName, MacAddress
应当看到:
SwitchName
----------
Ubuntu-FixedNAT
也可以通过 Hyper-V 管理器操作:
Hyper-V 管理器
→ 选择 Ubuntu 虚拟机
→ 设置
→ 网络适配器
→ 虚拟交换机
→ Ubuntu-FixedNAT
→ 确定
八、编写 Ubuntu 静态网络配置
当前 Ubuntu 配置为:
IP:172.26.107.185/20
网关:172.26.96.1
DNS:223.5.5.5、114.114.114.114
网卡:eth0
先启动 Ubuntu:
Start-VM -Name "Ubuntu"
建议通过 Hyper-V 控制台进入 Ubuntu,而不是通过 SSH 操作,因为配置网络时 SSH 可能中断。
1. 检查网卡名称
ip -br link
如果显示:
eth0 UP
就可以继续使用下面的配置。
如果显示的是 ens160、enp1s0 等名称,需要将配置中的 eth0 替换为实际名称。
2. 备份原有 Netplan 配置
查看现有文件:
ls -l /etc/netplan/
创建备份目录:
BACKUP_DIR="/root/netplan-backup-$(date +%Y%m%d-%H%M%S)"
sudo mkdir -p "$BACKUP_DIR"
sudo cp -a /etc/netplan/*.yaml "$BACKUP_DIR"/
你的原配置中同时存在:
dhcp4: true
以及:
dhcp4: false
addresses:
- 172.26.107.185/20
这说明 /etc/netplan/ 下可能存在多个 YAML 文件。为了避免 DHCP 配置和静态配置互相合并,建议最终只保留一份负责 eth0 的配置。
3. 禁止 cloud-init 重写网络配置
创建文件:
sudo tee /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg >/dev/null <<'EOF'
network: {config: disabled}
EOF
将 cloud-init 生成的配置文件移出 Netplan 目录:
if [ -f /etc/netplan/50-cloud-init.yaml ]; then
sudo mv \
/etc/netplan/50-cloud-init.yaml \
"$BACKUP_DIR/50-cloud-init.yaml"
fi
如果还有其他包含 eth0 的旧配置,可以先查看:
sudo grep -R -n "eth0\|172.26.107.185" /etc/netplan/
确认是旧配置后,将它移动到备份目录,不要让同一张网卡同时存在多个互相冲突的配置。
4. 创建静态配置
执行:
sudo tee /etc/netplan/99-hyperv-static.yaml >/dev/null <<'EOF'
network:
version: 2
renderer: networkd
ethernets:
eth0:
dhcp4: false
dhcp6: false
addresses:
- 172.26.107.185/20
routes:
- to: default
via: 172.26.96.1
nameservers:
addresses:
- 223.5.5.5
- 114.114.114.114
EOF
设置文件权限:
sudo chmod 600 /etc/netplan/99-hyperv-static.yaml
Netplan 的静态网络配置通过 addresses 设置 IP,通过默认路由的 via 设置网关,并通过 nameservers 设置 DNS。
九、验证并应用 Netplan
先检查 YAML 语法:
sudo netplan generate
查看 Netplan 合并后的最终配置:
sudo netplan get
应当包含:
eth0:
addresses:
- 172.26.107.185/20
dhcp4: false
routes:
- to: default
via: 172.26.96.1
建议先使用:
sudo netplan try
netplan try 会临时应用配置,如果管理员没有在规定时间内确认,它会尝试自动回滚,适合在修改网络配置时降低失联风险。
确认测试正常后按 Enter 保存。
也可以直接执行:
sudo netplan apply
十、检查 Ubuntu 网络状态
查看 IP:
ip -br -4 addr
预期结果:
eth0 UP 172.26.107.185/20
查看路由:
ip route
预期结果:
default via 172.26.96.1 dev eth0
172.26.96.0/20 dev eth0 proto kernel scope link src 172.26.107.185
查看 DNS:
resolvectl status eth0
或者:
netplan status eth0
十一、测试宿主机与虚拟机通信
Ubuntu 测试 Windows 宿主机
ping -c 4 172.26.96.1
成功表示:
Ubuntu → Hyper-V 内部交换机 → Windows 宿主机
通信正常。
Windows 测试 Ubuntu
在 Windows PowerShell 中执行:
ping 172.26.107.185
如果 Ubuntu 禁止 ICMP,ping 可能失败,可以测试实际服务端口:
Test-NetConnection `
-ComputerName 172.26.107.185 `
-Port 22
十二、测试 Ubuntu 访问互联网
先测试不依赖 DNS 的公网地址:
ping -c 4 1.1.1.1
如果成功,说明 NAT 正常。
再测试域名解析:
getent hosts www.baidu.com
或者:
ping -c 4 www.baidu.com
判断方式:
能访问 172.26.96.1
→ Ubuntu 与 Windows 宿主机通信正常
能访问 1.1.1.1
→ WinNAT 和互联网访问正常
能解析 www.baidu.com
→ DNS 配置正常
十三、配置 SSH 登录
Ubuntu 安装 SSH 服务:
sudo apt update
sudo apt install -y openssh-server
sudo systemctl enable --now ssh
如果启用了 UFW:
sudo ufw allow OpenSSH
查看状态:
sudo systemctl status ssh --no-pager
Windows 测试端口:
Test-NetConnection `
-ComputerName 172.26.107.185 `
-Port 22
连接 Ubuntu:
ssh ubuntu@172.26.107.185
完成后,无论 Windows 当前使用有线网络、无线网络,还是物理网卡地址发生变化,Windows 都可以继续通过固定地址访问 Ubuntu:
172.26.107.185
十四、一键创建 Windows 网络的 PowerShell 脚本
下面的脚本可以完成:
- 创建 Internal 交换机;
- 设置固定网关;
- 创建 WinNAT;
- 检查已有 NAT 冲突。
请在管理员 PowerShell 中执行:
$SwitchName = "Ubuntu-FixedNAT"
$NatName = "Ubuntu-FixedNAT"
$Gateway = "172.26.96.1"
$Prefix = 20
$Subnet = "172.26.96.0/20"
# 创建内部交换机
$switch = Get-VMSwitch `
-Name $SwitchName `
-ErrorAction SilentlyContinue
if (-not $switch) {
Write-Host "Creating Hyper-V internal switch: $SwitchName"
New-VMSwitch `
-Name $SwitchName `
-SwitchType Internal |
Out-Null
}
else {
Write-Host "Hyper-V switch already exists: $SwitchName"
}
# 获取宿主机虚拟网卡
$adapter = Get-NetAdapter `
-Name "vEthernet ($SwitchName)" `
-ErrorAction Stop
# 配置固定网关地址
$gatewayAddress = Get-NetIPAddress `
-InterfaceIndex $adapter.ifIndex `
-AddressFamily IPv4 `
-ErrorAction SilentlyContinue |
Where-Object {
$_.IPAddress -eq $Gateway -and
$_.PrefixLength -eq $Prefix
}
if (-not $gatewayAddress) {
Write-Host "Assigning gateway address: $Gateway/$Prefix"
New-NetIPAddress `
-InterfaceIndex $adapter.ifIndex `
-IPAddress $Gateway `
-PrefixLength $Prefix |
Out-Null
}
else {
Write-Host "Gateway address already exists: $Gateway/$Prefix"
}
# 检查指定 NAT
$nat = Get-NetNat `
-Name $NatName `
-ErrorAction SilentlyContinue
if (-not $nat) {
# Windows 通常只支持一个 WinNAT,发现其他 NAT 时停止
$otherNats = Get-NetNat -ErrorAction SilentlyContinue
if ($otherNats) {
Write-Host ""
Write-Host "Another WinNAT instance already exists:"
$otherNats |
Format-Table Name, InternalIPInterfaceAddressPrefix
throw "Check existing Docker, container, or virtual NAT networks before continuing."
}
Write-Host "Creating WinNAT: $NatName"
New-NetNat `
-Name $NatName `
-InternalIPInterfaceAddressPrefix $Subnet |
Out-Null
}
else {
Write-Host "WinNAT already exists: $NatName"
}
Write-Host ""
Write-Host "Configuration completed."
Write-Host "Switch : $SwitchName"
Write-Host "Gateway: $Gateway/$Prefix"
Write-Host "Subnet : $Subnet"
脚本执行完成后,再将 Ubuntu 连接到该交换机:
Get-VM
Connect-VMNetworkAdapter `
-VMName "Ubuntu" `
-SwitchName "Ubuntu-FixedNAT"
十五、常见问题排查
1. Ubuntu 无法 ping 通网关
检查虚拟机连接的是不是正确交换机:
Get-VMNetworkAdapter -VMName "Ubuntu" |
Format-Table SwitchName, Status, MacAddress
正确结果应为:
Ubuntu-FixedNAT
检查 Windows 网关:
Get-NetIPAddress `
-InterfaceAlias "vEthernet (Ubuntu-FixedNAT)" `
-AddressFamily IPv4
必须存在:
172.26.96.1/20
2. 可以 ping 网关,但不能访问互联网
检查 NAT:
Get-NetNat |
Format-List Name, InternalIPInterfaceAddressPrefix, Active
应当存在:
Ubuntu-FixedNAT
172.26.96.0/20
然后检查 Windows 宿主机本身是否可以上网。
VPN、安全软件或第三方防火墙也可能阻止 WinNAT 转发。
3. 可以访问公网 IP,但不能访问域名
这通常是 DNS 问题。
检查:
resolvectl status
重新应用配置:
sudo netplan generate
sudo netplan apply
测试 DNS:
getent hosts www.baidu.com
4. Netplan 报配置权限过宽
执行:
sudo chmod 600 /etc/netplan/99-hyperv-static.yaml
5. New-NetNat 提示已有 NAT
查看已有 NAT:
Get-NetNat |
Format-Table Name, InternalIPInterfaceAddressPrefix
不要直接运行:
Get-NetNat | Remove-NetNat
因为已有 NAT 可能属于 Docker 或 Windows Containers。微软文档明确提示 WinNAT 数量存在限制,并提供了多应用共享 NAT 的特殊配置流程。
十六、恢复到 Default Switch
如果需要撤销配置,先把 Ubuntu 切回默认交换机:
Connect-VMNetworkAdapter `
-VMName "Ubuntu" `
-SwitchName "Default Switch"
删除自定义 NAT:
Remove-NetNat `
-Name "Ubuntu-FixedNAT" `
-Confirm:$false
删除内部交换机:
Remove-VMSwitch `
-Name "Ubuntu-FixedNAT" `
-Force
如果恢复使用 Default Switch,Ubuntu 也需要改回 DHCP,否则原来的静态地址将无法匹配 Default Switch 当前网段。
十七、最终效果
配置完成后的固定环境为:
Hyper-V 交换机:
Ubuntu-FixedNAT
Windows 宿主机虚拟网卡:
172.26.96.1/20
Ubuntu:
172.26.107.185/20
Ubuntu 默认网关:
172.26.96.1
Ubuntu DNS:
223.5.5.5
114.114.114.114
Ubuntu 可以固定使用:
172.26.107.185
Windows 宿主机可以通过该地址访问 Ubuntu,Ubuntu 也可以通过:
172.26.96.1
访问 Windows 宿主机,并通过 WinNAT 访问互联网。即使 Hyper-V 的 Default Switch 后续再次更换网段,也不会影响这个固定网络环境。