Skip to main content
Add note to indicate that Google's DNS servers may not be reachable on corporate networks.
Source Link
Ben Johnson
  • 1.3k
  • 13
  • 12

NOTE: If on a corporate network, be sure to use the company's DNS servers, as Google's (shown in these examples) may not be reachable.

NOTE: If on a corporate network, be sure to use the company's DNS servers, as Google's (shown in these examples) may not be reachable.

Replace my previous Answer with a much more comprehensive and automated solution.
Source Link
Ben Johnson
  • 1.3k
  • 13
  • 12

Background

The Asker, and anyone with a similar use-case, is likely operating on a workstation (not Windows Server edition), for local development purposes, in which caseand prefers not to run a relatively simple solution existsDHCP server merely to prevent Hyper-V from changing IP address assignments on every host machine reboot.

Create the Switch

In HyperThe need to hard-V Manager, createcode a new Virtual Switchstatic IP address within the VM's network configuration "manually", under Actions panel -> Virtual Switch Manager... -> Create Virtual Switchafter provisioning, is cumbersome and stymies automation. Assuming the VM shouldWouldn't it be able to connectfar more preferable to the Internet, choose the External switch type.

Onautomate the next screenentire process, givein keeping with the switchspirit of "disposable" development VMs and a name, such as internet-enabledhands-free provisioning workflow? Why, and choose the physical network interface that is connected to the Internet.yes it would!

The resultant switch should look something likeAll of this hoop-jumping is necessary because Vagrant cannot (yet) set a static IP address for Hyper-V machines. See:

enter image description here

Hard-Code the Switch's IP Address (Gateway for the VM)Overview

Locate the network adapter that is associated with the new switch, i.e., under Control Panel -> Network and Internet -> Network Connections; its name will reflect the name given in the previous step, e.g., vEthernet (internet-enabled). Right-click the adapter and choose Properties.

Next, click Internet Protocol Version 4 (TCP/IPv4) and click Properties. Enter 192.168.10.1 for the IP addressIn short, and 255.255.255.0 for the Subnet mask. The settings should look likesequence of events to make this work is as follows:

enter image description here

  1. Create NAT switch for Hyper-V. (This is an Internal-only switch behind which any number of VMs with static IP addresses can sit and talk to each other, as well as the Hyper-V host. Guests behind this switch have outbound access to any network resources to which the host has access, such as the Internet or a LAN.)
  2. Configure a Vagrant Trigger that leverages the vagrant-reload plugin within the before-reload event to change a given VM's network switch on-demand.
  3. vagrant up, but choose Default Switch (not the new NATSwitch) on initial provision.
  4. At the beginning of the provisioning process, configure a static IP within the VM's operating system that is within the NATSwitch's range (this step is OS-specific).
  5. Call config.vm.provision :reload, which will a) fire the trigger defined in step 2, thereby changing the VM's network switch to the new NATSwitch; and b) issue vagrant reload and continue the provisioning process after the VM reboots.
  6. When the VM reboots, it will acquire the static IP address from the NATSwitch and use it indefinitely.

Assign a Static IP Address in Guest VM1. Create NAT Switch

The finalWhile this step is to assign a static IP address in the guest VM.

Unfortunatelycan certainly be done once, Vagrant does not (as of v2.2.1) support static IP configuration (see: https://github.com/hashicorp/vagrant/issues/8384 )manually, so this static IP cannot be assigned priorit's even more powerful to provisioningbake the VM.

Until Vagrant supports this capability, onecommands into a script that can simply provision the VM normally and editbe called from the network configuration subsequentlyVagrantfile during provisioning. Such a script might look like this:

The process for setting a static IP varies per guest OS, but in Ubuntu 18.04 LTS, for example, it's as simple as editing /etc./netplanscripts/01create-netcfgnat-hyperv-switch.yamlps1 to include values that match the virtual switch configuration from above (the spaces must be exact!):

network# See: https://www.petri.com/using-nat-virtual-switch-hyper-v

If ("NATSwitch" version:-in 2(Get-VMSwitch | Select-Object -ExpandProperty Name) -eq $FALSE) {
  ethernets:  'Creating Internal-only switch named "NATSwitch" on Windows Hyper-V host...'

    eth0:New-VMSwitch -SwitchName "NATSwitch" -SwitchType Internal

    New-NetIPAddress -IPAddress dhcp4:192.168.0.1 no-PrefixLength 24 -InterfaceAlias "vEthernet (NATSwitch)"

    New-NetNAT -Name addresses:"NATNetwork" [192-InternalIPInterfaceAddressPrefix 192.168.100.100/24]24
}
else {
    '"NATSwitch" gateway4:for static IP configuration already exists; skipping'
}

If ("192.168.0.1" -in (Get-NetIPAddress | Select-Object -ExpandProperty IPAddress) -eq $FALSE) {
    'Registering new IP address 192.168.100.1 on Windows Hyper-V host...'

    New-NetIPAddress -IPAddress nameservers:192.168.0.1 -PrefixLength 24 -InterfaceAlias "vEthernet (NATSwitch)"
}
else {
    '"192.168.0.1" for static IP addresses:configuration [8already registered; skipping'
}

If ("192.8168.80.8,80/24" -in (Get-NetNAT | Select-Object -ExpandProperty InternalIPInterfaceAddressPrefix) -eq $FALSE) {
    'Registering new NAT adapter for 192.8168.40.4]0/24 on Windows Hyper-V host...'

    New-NetNAT -Name "NATNetwork" -InternalIPInterfaceAddressPrefix 192.168.0.0/24
}
else {
    '"192.168.0.0/24" for static IP configuration already registered; skipping'
}

After savingThen, add an appropriate trigger to the filetop of the Vagrantfile config section, applywhich will ensure that the changes withconfiguration is always correct upon vagrant up:

config.trigger.before :up do |trigger|
    trigger.info = "Creating 'NATSwitch' Hyper-V switch if it does not exist..."

    trigger.run = {privileged: "true", powershell_elevated_interactive: "true", path: "./scripts/create-nat-hyperv-switch.ps1"}
end

2. Configure Vagrant Reload Trigger

Rebooting (reloading) the VM in the middle of provisioning, in order to change over to a static IP address, requires the https://github.com/aidanns/vagrant-reload plugin, so install that first:

$vagrant sudoplugin netplaninstall applyvagrant-reload

The VM should reflectscript that the trigger will call is very simply:

./scripts/set-hyperv-switch.ps1:

# See: https://www.thomasmaurer.ch/2016/01/change-hyper-v-vm-switch-of-virtual-machines-using-powershell/

Get-VM "homestead" | Get-VMNetworkAdapter | Connect-VMNetworkAdapter -SwitchName "NATSwitch"

Next, add an appropriate trigger to the Vagrantfile config section (i.e., just below the trigger added in the previous step):

config.trigger.before :reload do |trigger|
    trigger.info = "Setting Hyper-V switch to 'NATSwitch' to allow for static IP..."

    trigger.run = {privileged: "true", powershell_elevated_interactive: "true", path: "./scripts/set-hyperv-switch.ps1"}
end

3. Configure Static IP Within Guest VM

Configuring a static IP immediatelyis an OS-specific task, which canso this procedure should be confirmed withadjusted to suit the specific guest OS. Two examples follow.

Ubuntu 18.04 LTS Example

On Ubuntu 18.04 LTS, this works well:

./scripts/configure-static-ip.sh:

#!/bin/sh

echo 'Setting static IP address for Hyper-V...'

cat << EOF > /etc/netplan/01-netcfg.yaml
network:
  version: 2
  ethernets:
    eth0:
      dhcp4: no
      addresses: [192.168.0.2/24]
      gateway4: 192.168.0.1
      nameservers:
        addresses: [8.8.8.8,8.8.4.4]
EOF

# Be sure NOT to execute "netplan apply" here, so the changes take effect on
# reboot instead of immediately, which would disconnect the provisioner.

RedHat, CentOS, and Oracle Linux Example

./scripts/configure-static-ip.sh:

#!/bin/sh

echo 'Setting static IP address for Hyper-V...'

cat << EOF > /etc/sysconfig/network-scripts/ifcfg-eth0
DEVICE=eth0
BOOTPROTO=none
ONBOOT=yes
PREFIX=24
IPADDR=192.168.0.2
GATEWAY=192.168.0.1
DNS1=8.8.8.8
EOF

# Be sure NOT to execute "systemctl restart network" here, so the changes take
# effect on reboot instead of immediately, which would disconnect the provisioner.

With the above script in place, add something like this just below the trigger definitions that we added earlier:

config.vm.provision "shell", path: "./scripts/configure-static-ip.sh"

config.vm.provision :reload

4. Provision the VM

vagrant up and choose ifconfigDefault Switch when prompted; this causes the VM to obtain a dynamic IPv4 address that is sufficient for Vagrant to connect to the VM via SSH, mount Shared Folders, and begin provisioning.

Now, the static IP address will be set and the VM reloaded before provisioning continues.

Sample output:

$ sudo ifconfig
eth0  homestead: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>Setting static mtuIP 1500address for Hyper-V...
==> homestead: Running provisioner: reload...
==> homestead: Running action inettriggers 192before reload .168.10.10
==> homestead: netmaskRunning 255trigger.255.255.0
==> homestead: broadcastSetting 192Hyper-V switch to 'NATSwitch' to allow for static IP.168.10.255
    homestead: Running local script: inet6./scripts/set-hyperv-switch.ps1
==> fe80::215homestead:5dff Attempting graceful shutdown of VM...
==> homestead:fe38 Stopping the machine...
    homestead:12a Configuring prefixlenthe 64VM...
==> homestead: scopeidStarting 0x20<link>the machine...
==> homestead: Waiting for the machine to report etherits 00:15IP address...
    homestead:5d Timeout:38 120 seconds
    homestead:01 IP:2a 192.168.0.2
==> txqueuelenhomestead: 1000Waiting for (Ethernet)
machine to boot. This may take a few minutes...
==> homestead: Machine booted and ready!

The host can now ping the guest at 192.168.10.10, and the guest can ping the host at 192.168.10.1.

References:

5. Other Thoughts

  1. Manual input is required to choose the Default Switch after the initial vagrant up; it would be ideal to find a way around this.
  2. The vagrant-reload provisioner cannot shutdown the machine gracefully and must halt it forcibly; not a significant concern, given that it happens only once (during initial provisioning). This happens due to the fact that changing the VM's Hyper-V switch from Default Switch to NATSwitch must be done during the before-reload event, which is, in effect, akin to pulling the Ethernet cord out of a physical jack and connecting it to a different switch.

The Asker, and anyone with a similar use-case, is likely operating on a workstation (not Windows Server edition), for local development purposes, in which case a relatively simple solution exists.

Create the Switch

In Hyper-V Manager, create a new Virtual Switch, under Actions panel -> Virtual Switch Manager... -> Create Virtual Switch. Assuming the VM should be able to connect to the Internet, choose the External switch type.

On the next screen, give the switch a name, such as internet-enabled, and choose the physical network interface that is connected to the Internet.

The resultant switch should look something like this:

enter image description here

Hard-Code the Switch's IP Address (Gateway for the VM)

Locate the network adapter that is associated with the new switch, i.e., under Control Panel -> Network and Internet -> Network Connections; its name will reflect the name given in the previous step, e.g., vEthernet (internet-enabled). Right-click the adapter and choose Properties.

Next, click Internet Protocol Version 4 (TCP/IPv4) and click Properties. Enter 192.168.10.1 for the IP address, and 255.255.255.0 for the Subnet mask. The settings should look like this:

enter image description here

Assign a Static IP Address in Guest VM

The final step is to assign a static IP address in the guest VM.

Unfortunately, Vagrant does not (as of v2.2.1) support static IP configuration (see: https://github.com/hashicorp/vagrant/issues/8384 ), so this static IP cannot be assigned prior to provisioning the VM.

Until Vagrant supports this capability, one can simply provision the VM normally and edit the network configuration subsequently.

The process for setting a static IP varies per guest OS, but in Ubuntu 18.04 LTS, for example, it's as simple as editing /etc/netplan/01-netcfg.yaml to include values that match the virtual switch configuration from above (the spaces must be exact!):

network:
  version: 2
  ethernets:
    eth0:
      dhcp4: no
      addresses: [192.168.10.10/24]
      gateway4: 192.168.10.1
      nameservers:
        addresses: [8.8.8.8,8.8.4.4]

After saving the file, apply the changes with:

$ sudo netplan apply

The VM should reflect the static IP immediately, which can be confirmed with ifconfig:

$ sudo ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.10.10  netmask 255.255.255.0  broadcast 192.168.10.255
        inet6 fe80::215:5dff:fe38:12a  prefixlen 64  scopeid 0x20<link>
        ether 00:15:5d:38:01:2a  txqueuelen 1000  (Ethernet)
        ...

The host can now ping the guest at 192.168.10.10, and the guest can ping the host at 192.168.10.1.

References:

Background

The Asker, and anyone with a similar use-case, is likely operating on a workstation (not Windows Server edition), for local development purposes, and prefers not to run a DHCP server merely to prevent Hyper-V from changing IP address assignments on every host machine reboot.

The need to hard-code a static IP address within the VM's network configuration "manually", after provisioning, is cumbersome and stymies automation. Wouldn't it be far more preferable to automate the entire process, in keeping with the spirit of "disposable" development VMs and a hands-free provisioning workflow? Why, yes it would!

All of this hoop-jumping is necessary because Vagrant cannot (yet) set a static IP address for Hyper-V machines. See:

Overview

In short, the sequence of events to make this work is as follows:

  1. Create NAT switch for Hyper-V. (This is an Internal-only switch behind which any number of VMs with static IP addresses can sit and talk to each other, as well as the Hyper-V host. Guests behind this switch have outbound access to any network resources to which the host has access, such as the Internet or a LAN.)
  2. Configure a Vagrant Trigger that leverages the vagrant-reload plugin within the before-reload event to change a given VM's network switch on-demand.
  3. vagrant up, but choose Default Switch (not the new NATSwitch) on initial provision.
  4. At the beginning of the provisioning process, configure a static IP within the VM's operating system that is within the NATSwitch's range (this step is OS-specific).
  5. Call config.vm.provision :reload, which will a) fire the trigger defined in step 2, thereby changing the VM's network switch to the new NATSwitch; and b) issue vagrant reload and continue the provisioning process after the VM reboots.
  6. When the VM reboots, it will acquire the static IP address from the NATSwitch and use it indefinitely.

1. Create NAT Switch

While this step can certainly be done once, manually, it's even more powerful to bake the commands into a script that can be called from the Vagrantfile during provisioning. Such a script might look like this:

./scripts/create-nat-hyperv-switch.ps1:

# See: https://www.petri.com/using-nat-virtual-switch-hyper-v

If ("NATSwitch" -in (Get-VMSwitch | Select-Object -ExpandProperty Name) -eq $FALSE) {
    'Creating Internal-only switch named "NATSwitch" on Windows Hyper-V host...'

    New-VMSwitch -SwitchName "NATSwitch" -SwitchType Internal

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

    New-NetNAT -Name "NATNetwork" -InternalIPInterfaceAddressPrefix 192.168.0.0/24
}
else {
    '"NATSwitch" for static IP configuration already exists; skipping'
}

If ("192.168.0.1" -in (Get-NetIPAddress | Select-Object -ExpandProperty IPAddress) -eq $FALSE) {
    'Registering new IP address 192.168.0.1 on Windows Hyper-V host...'

    New-NetIPAddress -IPAddress 192.168.0.1 -PrefixLength 24 -InterfaceAlias "vEthernet (NATSwitch)"
}
else {
    '"192.168.0.1" for static IP configuration already registered; skipping'
}

If ("192.168.0.0/24" -in (Get-NetNAT | Select-Object -ExpandProperty InternalIPInterfaceAddressPrefix) -eq $FALSE) {
    'Registering new NAT adapter for 192.168.0.0/24 on Windows Hyper-V host...'

    New-NetNAT -Name "NATNetwork" -InternalIPInterfaceAddressPrefix 192.168.0.0/24
}
else {
    '"192.168.0.0/24" for static IP configuration already registered; skipping'
}

Then, add an appropriate trigger to the top of the Vagrantfile config section, which will ensure that the configuration is always correct upon vagrant up:

config.trigger.before :up do |trigger|
    trigger.info = "Creating 'NATSwitch' Hyper-V switch if it does not exist..."

    trigger.run = {privileged: "true", powershell_elevated_interactive: "true", path: "./scripts/create-nat-hyperv-switch.ps1"}
end

2. Configure Vagrant Reload Trigger

Rebooting (reloading) the VM in the middle of provisioning, in order to change over to a static IP address, requires the https://github.com/aidanns/vagrant-reload plugin, so install that first:

vagrant plugin install vagrant-reload

The script that the trigger will call is very simply:

./scripts/set-hyperv-switch.ps1:

# See: https://www.thomasmaurer.ch/2016/01/change-hyper-v-vm-switch-of-virtual-machines-using-powershell/

Get-VM "homestead" | Get-VMNetworkAdapter | Connect-VMNetworkAdapter -SwitchName "NATSwitch"

Next, add an appropriate trigger to the Vagrantfile config section (i.e., just below the trigger added in the previous step):

config.trigger.before :reload do |trigger|
    trigger.info = "Setting Hyper-V switch to 'NATSwitch' to allow for static IP..."

    trigger.run = {privileged: "true", powershell_elevated_interactive: "true", path: "./scripts/set-hyperv-switch.ps1"}
end

3. Configure Static IP Within Guest VM

Configuring a static IP is an OS-specific task, so this procedure should be adjusted to suit the specific guest OS. Two examples follow.

Ubuntu 18.04 LTS Example

On Ubuntu 18.04 LTS, this works well:

./scripts/configure-static-ip.sh:

#!/bin/sh

echo 'Setting static IP address for Hyper-V...'

cat << EOF > /etc/netplan/01-netcfg.yaml
network:
  version: 2
  ethernets:
    eth0:
      dhcp4: no
      addresses: [192.168.0.2/24]
      gateway4: 192.168.0.1
      nameservers:
        addresses: [8.8.8.8,8.8.4.4]
EOF

# Be sure NOT to execute "netplan apply" here, so the changes take effect on
# reboot instead of immediately, which would disconnect the provisioner.

RedHat, CentOS, and Oracle Linux Example

./scripts/configure-static-ip.sh:

#!/bin/sh

echo 'Setting static IP address for Hyper-V...'

cat << EOF > /etc/sysconfig/network-scripts/ifcfg-eth0
DEVICE=eth0
BOOTPROTO=none
ONBOOT=yes
PREFIX=24
IPADDR=192.168.0.2
GATEWAY=192.168.0.1
DNS1=8.8.8.8
EOF

# Be sure NOT to execute "systemctl restart network" here, so the changes take
# effect on reboot instead of immediately, which would disconnect the provisioner.

With the above script in place, add something like this just below the trigger definitions that we added earlier:

config.vm.provision "shell", path: "./scripts/configure-static-ip.sh"

config.vm.provision :reload

4. Provision the VM

vagrant up and choose Default Switch when prompted; this causes the VM to obtain a dynamic IPv4 address that is sufficient for Vagrant to connect to the VM via SSH, mount Shared Folders, and begin provisioning.

Now, the static IP address will be set and the VM reloaded before provisioning continues.

Sample output:

    homestead: Setting static IP address for Hyper-V...
==> homestead: Running provisioner: reload...
==> homestead: Running action triggers before reload ...
==> homestead: Running trigger...
==> homestead: Setting Hyper-V switch to 'NATSwitch' to allow for static IP...
    homestead: Running local script: ./scripts/set-hyperv-switch.ps1
==> homestead: Attempting graceful shutdown of VM...
==> homestead: Stopping the machine...
    homestead: Configuring the VM...
==> homestead: Starting the machine...
==> homestead: Waiting for the machine to report its IP address...
    homestead: Timeout: 120 seconds
    homestead: IP: 192.168.0.2
==> homestead: Waiting for machine to boot. This may take a few minutes...
==> homestead: Machine booted and ready!

5. Other Thoughts

  1. Manual input is required to choose the Default Switch after the initial vagrant up; it would be ideal to find a way around this.
  2. The vagrant-reload provisioner cannot shutdown the machine gracefully and must halt it forcibly; not a significant concern, given that it happens only once (during initial provisioning). This happens due to the fact that changing the VM's Hyper-V switch from Default Switch to NATSwitch must be done during the before-reload event, which is, in effect, akin to pulling the Ethernet cord out of a physical jack and connecting it to a different switch.
Source Link
Ben Johnson
  • 1.3k
  • 13
  • 12

The Asker, and anyone with a similar use-case, is likely operating on a workstation (not Windows Server edition), for local development purposes, in which case a relatively simple solution exists.

Create the Switch

In Hyper-V Manager, create a new Virtual Switch, under Actions panel -> Virtual Switch Manager... -> Create Virtual Switch. Assuming the VM should be able to connect to the Internet, choose the External switch type.

On the next screen, give the switch a name, such as internet-enabled, and choose the physical network interface that is connected to the Internet.

The resultant switch should look something like this:

enter image description here

Hard-Code the Switch's IP Address (Gateway for the VM)

Locate the network adapter that is associated with the new switch, i.e., under Control Panel -> Network and Internet -> Network Connections; its name will reflect the name given in the previous step, e.g., vEthernet (internet-enabled). Right-click the adapter and choose Properties.

Next, click Internet Protocol Version 4 (TCP/IPv4) and click Properties. Enter 192.168.10.1 for the IP address, and 255.255.255.0 for the Subnet mask. The settings should look like this:

enter image description here

Assign a Static IP Address in Guest VM

The final step is to assign a static IP address in the guest VM.

Unfortunately, Vagrant does not (as of v2.2.1) support static IP configuration (see: https://github.com/hashicorp/vagrant/issues/8384 ), so this static IP cannot be assigned prior to provisioning the VM.

Until Vagrant supports this capability, one can simply provision the VM normally and edit the network configuration subsequently.

The process for setting a static IP varies per guest OS, but in Ubuntu 18.04 LTS, for example, it's as simple as editing /etc/netplan/01-netcfg.yaml to include values that match the virtual switch configuration from above (the spaces must be exact!):

network:
  version: 2
  ethernets:
    eth0:
      dhcp4: no
      addresses: [192.168.10.10/24]
      gateway4: 192.168.10.1
      nameservers:
        addresses: [8.8.8.8,8.8.4.4]

After saving the file, apply the changes with:

$ sudo netplan apply

The VM should reflect the static IP immediately, which can be confirmed with ifconfig:

$ sudo ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.10.10  netmask 255.255.255.0  broadcast 192.168.10.255
        inet6 fe80::215:5dff:fe38:12a  prefixlen 64  scopeid 0x20<link>
        ether 00:15:5d:38:01:2a  txqueuelen 1000  (Ethernet)
        ...

The host can now ping the guest at 192.168.10.10, and the guest can ping the host at 192.168.10.1.

References: