Hyper-V: Isolated NAT Network with Port Forwarding

This guide describes how to create an isolated NAT network for virtual machines in Hyper-V — the equivalent of VirtualBox's "NAT" mode — and how to expose selected services from that network to the host and to other machines on the local network.

Result: the virtual machine has outbound internet access but stays invisible to the LAN. The host can reach it directly by its IP address, and other computers on the LAN can reach selected ports through the host's address in the form host-ip:port.

How it works

Hyper-V has no ready-made "NAT" mode like VirtualBox. The same behaviour is achieved by combining three separate components:

  • Internal virtual switch — a private network between the host and the virtual machines, with no connection to the physical network adapter. The virtual machine is therefore not visible from the LAN.
  • IP address on the host adapter — this makes the host the default gateway for virtual machines on that private network.
  • NetNat — the Windows component that translates addresses from the private network out through the host's internet connection, and can also forward selected inbound ports back in.

The traffic flow looks like this:

Other PCs on the LAN  ──►  Host 192.168.1.50:8080
                                    │  NAT + port forwarding
                                    ▼
                              vEthernet (NATSwitch) = 192.168.100.1
                                    │
                                    ▼
                              VM 192.168.100.10:80  ──►  internet via NAT

Hyper-V does offer a built-in Default Switch that also performs NAT, but its address range changes after a host reboot and port forwarding cannot be configured on it. For a stable environment you need your own switch, as described in this guide.

Values used

The whole guide uses the values below. Feel free to replace them with your own — just make sure you change them consistently in every command.

Item

Value

Switch name

NATSwitch

NAT name

NATNetwork

Subnet

192.168.100.0/24

Host IP (gateway)

192.168.100.1

Virtual machine IP

192.168.100.10

Service inside the VM

TCP port 80

Port exposed on the host

TCP port 8080

The chosen subnet must not overlap with your corporate or home network. If your LAN is, for example, 192.168.1.0/24, then 192.168.100.0/24 is safe to use.

Prerequisites

  • Windows 10/11 Pro, Enterprise or Education, or Windows Server, with the Hyper-V role enabled. The Home edition does not include Hyper-V.
  • All commands on the host must be run in PowerShell started as Administrator.
  • Only one NetNat instance is allowed per host.

Before you start, check whether a NAT already exists on the machine:

Get-NetNat

If the command returns an existing NAT (typically created by WSL2, Docker Desktop or an earlier attempt), you have two options: reuse its subnet for your virtual machine, or remove it with Remove-NetNat -Name "<name>". Only remove it if you are certain nothing else depends on it — otherwise Docker containers, for example, will lose network connectivity.

Procedure

1. Create the internal switch

New-VMSwitch -SwitchName "NATSwitch" -SwitchType Internal

This creates a virtual switch with no connection to the physical network adapter, plus a new virtual adapter on the host named vEthernet (NATSwitch).

2. Assign the gateway IP address to the host adapter

New-NetIPAddress -IPAddress 192.168.100.1 -PrefixLength 24 -InterfaceAlias "vEthernet (NATSwitch)"

The host now owns the address 192.168.100.1 on this network. This address will act as the default gateway for the virtual machine.

Verify:

Get-NetIPAddress -InterfaceAlias "vEthernet (NATSwitch)"

3. Create the NAT

New-NetNat -Name "NATNetwork" -InternalIPInterfaceAddressPrefix 192.168.100.0/24

This tells Windows to translate all traffic from the 192.168.100.0/24 subnet out through the host's active internet connection.

Verify:

Get-NetNat

4. Attach the virtual machine to the switch

Via the GUI: Settings → Network Adapter → Virtual switch → NATSwitch.

Or via PowerShell:

Connect-VMNetworkAdapter -VMName "MyVM" -SwitchName "NATSwitch"

5. Configure networking inside the virtual machine

There is no DHCP server running on a custom NAT switch. The virtual machine will not obtain an address by itself — you must configure a static setup inside the guest operating system.

Setting

Value

IP address

192.168.100.10

Subnet mask / prefix

255.255.255.0 (/24)

Default gateway

192.168.100.1

DNS

1.1.1.1 and/or 8.8.8.8

The gateway 192.168.100.1 does not provide DNS, so it cannot be used as a DNS server. Always specify a public or corporate DNS server.

Linux (Ubuntu, netplan)

File /etc/netplan/01-static.yaml:

network:
  version: 2
  ethernets:
    eth0:
      addresses: [192.168.100.10/24]
      routes:
        - to: default
          via: 192.168.100.1
      nameservers:
        addresses: [1.1.1.1, 8.8.8.8]

Apply the configuration with sudo netplan apply. Verify the interface name (eth0) with ip a — it is often ens33 or similar.

Windows (PowerShell inside the VM)
New-NetIPAddress -InterfaceAlias "Ethernet" -IPAddress 192.168.100.10 -PrefixLength 24 -DefaultGateway 192.168.100.1
Set-DnsClientServerAddress -InterfaceAlias "Ethernet" -ServerAddresses 1.1.1.1,8.8.8.8

Sanity checks from inside the VM
ping 192.168.100.1     # gateway is reachable
ping 1.1.1.1          # internet via NAT works
nslookup example.com   # DNS works

At this point the host can already reach the virtual machine directly — for example at http://192.168.100.10:80 — with no port forwarding at all. The remaining two steps are only needed for access from other computers.

6. Add the port forwarding rule

Forward host port 8080 to port 80 inside the virtual machine:

Add-NetNatStaticMapping -NatName "NATNetwork" -Protocol TCP -ExternalIPAddress 0.0.0.0 -ExternalPort 8080 -InternalIPAddress 192.168.100.10 -InternalPort 80

  • -ExternalIPAddress 0.0.0.0 means listening on all host interfaces. If the service should only be available on one of them (for example on the wired connection but not on Wi-Fi), enter that interface's specific IP address instead of the zeros.
  • Create a separate rule with different ports for each additional service — for example 2222 → 22 for SSH.
  • Only TCP and UDP are supported. If a service needs both, create two rules.

Managing existing rules:

Get-NetNatStaticMapping                    # list all rules
Remove-NetNatStaticMapping -StaticMappingID 0   # remove one (ID taken from the list above)

7. Open the host firewall

The forwarding rule alone is not enough — Windows Firewall still drops inbound connections from other computers. You need to allow the external port:

New-NetFirewallRule -DisplayName "Forward 8080 to VM web" -Direction Inbound -Protocol TCP -LocalPort 8080 -Action Allow

Optionally, the rule can be restricted to your own LAN, which is preferable from a security standpoint:

New-NetFirewallRule -DisplayName "Forward 8080 to VM web (LAN only)" -Direction Inbound -Protocol TCP -LocalPort 8080 -Action Allow -RemoteAddress 192.168.1.0/24

Adjust the 192.168.1.0/24 range to match your actual subnet.

Testing

  1. Find the host's LAN IP address with ipconfig — for example 192.168.1.50.
  2. From the host, open http://192.168.100.10:80 — direct access must work.
  3. From another computer on the network, open http://192.168.1.50:8080 — the service running inside the virtual machine must appear.

For a quick test without deploying a real service, start a throwaway web server inside the virtual machine: python3 -m http.server 80 (Linux). The server runs until you stop it with Ctrl+C.

Troubleshooting

The virtual machine has no internet access

  • Run Get-NetNat — does the NAT exist and does its subnet match your configuration?
  • The gateway inside the virtual machine must be 192.168.100.1, and that address must exist on the vEthernet (NATSwitch) adapter. Re-check step 2 — the address can disappear if the switch was recreated in the meantime.
  • If ping 1.1.1.1 works but names do not resolve, the DNS servers inside the virtual machine are configured incorrectly.

The host cannot reach the VM directly

  • The firewall inside the virtual machine — the guest system must allow the service port. This is by far the most common cause.
  • Verify that the VM's network adapter is connected to NATSwitch and that it has the correct IP address.

Other computers cannot connect, but direct access from the host works

  • The host firewall rule is missing, or is configured for a different port (step 7).
  • Typo in the forwarding rule — check the internal IP address and both ports with Get-NetNatStaticMapping.
  • Some VPN clients on the host intercept inbound traffic. Try again with the VPN disconnected.

The New-NetNat command fails

Typically with "The parameter is incorrect" or a similar message.

  • Another NetNat instance already exists on the host — verify with Get-NetNat. Remove it, or reuse its subnet.
  • On some machines WSL2 or Docker Desktop conflicts here, as they create their own NAT automatically.

Everything stops working after a host reboot

The switch, IP address, NAT, forwarding rules and firewall rules are all persistent and survive a reboot. If the host-side IP address disappears after a major Windows update, simply repeat step 2.

Removing the configuration

Remove everything in the reverse order of creation:

Get-NetNatStaticMapping | Remove-NetNatStaticMapping -Confirm:$false
Remove-NetFirewallRule -DisplayName "Forward 8080 to VM web"
Remove-NetNat -Name "NATNetwork" -Confirm:$false
Remove-NetIPAddress -InterfaceAlias "vEthernet (NATSwitch)" -IPAddress 192.168.100.1 -Confirm:$false
Remove-VMSwitch -Name "NATSwitch" -Force

The first command removes all forwarding rules on the host, not just the ones from this guide. If other rules exist on the machine, remove them individually by their StaticMappingID.

Quick reference

The entire setup in one block

Run on the host in PowerShell as Administrator:

New-VMSwitch -SwitchName "NATSwitch" -SwitchType Internal
New-NetIPAddress -IPAddress 192.168.100.1 -PrefixLength 24 -InterfaceAlias "vEthernet (NATSwitch)"
New-NetNat -Name "NATNetwork" -InternalIPInterfaceAddressPrefix 192.168.100.0/24
Connect-VMNetworkAdapter -VMName "MyVM" -SwitchName "NATSwitch"

Inside the virtual machine, set the static IP 192.168.100.10/24, gateway 192.168.100.1 and DNS 1.1.1.1.

Expose port 80 from the VM as port 8080 on the host:

Add-NetNatStaticMapping -NatName "NATNetwork" -Protocol TCP -ExternalIPAddress 0.0.0.0 -ExternalPort 8080 -InternalIPAddress 192.168.100.10 -InternalPort 80
New-NetFirewallRule -DisplayName "Forward 8080 to VM web" -Direction Inbound -Protocol TCP -LocalPort 8080 -Action Allow

Frantisek Brych Updated by Frantisek Brych

Diagnosing services

Contact

Syca (opens in a new tab)

Powered by HelpDocs (opens in a new tab)