在 Hyper-V 中搭建固定 IP、固定网关、可上网且与宿主机互通的 Ubuntu 环境

一、需求背景

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.5114.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

就可以继续使用下面的配置。

如果显示的是 ens160enp1s0 等名称,需要将配置中的 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 后续再次更换网段,也不会影响这个固定网络环境。

相关推荐
abbgogo12 小时前
TCP/IP、OSI 与常见网络协议知识点总结
网络·网络协议·计算机网络
李昊哲小课13 小时前
fastapi sse websocket 奶茶店实时订单看板
人工智能·python·websocket·网络协议·fastapi·sse
abbgogo15 小时前
堆叠、DHCP 与链路聚合总结
网络·网络协议
初级炼丹师(爱说实话版)17 小时前
Ubuntu服务器配置docker
服务器·ubuntu·docker
bellus-20 小时前
Ubuntu 26.04 Miniforge3 安装与配置完整指南
linux·运维·ubuntu
今天AI了吗21 小时前
OpenCode AI 编程:Ubuntu 24.04 环境安装与使用指南
linux·人工智能·ubuntu
用什么都重名1 天前
Ubuntu 24.04 安装 NVIDIA 驱动:解决 “NVIDIA-SMI has failed“ 报错全记录
linux·运维·ubuntu
2401_873479401 天前
IPv6查出来的地理位置是错的?用双栈IP库解决定位偏差问题
网络·数据库·tcp/ip·ip
花生了什么事o1 天前
WebSocket 与 SSE:实时通信方案的选择
网络·websocket·网络协议