Libvirt Hostname Resolution

22 Dec 2019

I use Vagrant when testing new machines and experimenting locally with clusters, and since moving (mostly) to Linux, I have been using the LibVirt Plugin to create the virtual machines. Not only is it significantly faster than Hyper-V was on windows, but it also means I don’t need to use Oracle products, so it’s win-win really.

The only configuration challenge I have had with it is setting up VM hostname resolution, and as I forget how to do it each time, I figured I should write about it.


First I install the plugin so Vagrant can talk to Libvirt.

vagrant plugin install vagrant-libvirt

I also created a single vagrantfile with two virtual machines defined in it, so that I can check that the machines can resolve each other, as well as the host being able to resolve the guests.

Vagrant.configure("2") do |config| = "elastic/ubuntu-16.04-x86_64"

 config.vm.define "one" do |n1|
 n1.vm.hostname = "one"

 config.vm.define "two" do |n1|
 n1.vm.hostname = "two"

Once running vagrant up has finished (either with --provider libvirt or setting ` VAGRANT_DEFAULT_PROVIDER=libvirt`), connect to one of the machines, and try to ping the other:

[email protected]$ vagrant ssh one
[email protected]$ ping two
ping: unknown host two
[email protected]$ exit

Now that we can see they can’t resolve each other let’s move on to fixing it.

Custom Domain

The solution is to configure the libvirt network to have a domain name, and then to set the host machine to send requests for that domain to the virtual network.

First, I picked a domain. It doesn’t matter what it is, but I gather using .local will cause problems with other services, so instead, I picked $, which is in this case.

Vagrant-libvirt by default creates a network called vagrant-libvirt, so we can edit it to include the domain name configuration by running the following command:

virsh net-edit --network vagrant-libvirt

And adding the ` line to the xml which is displayed:

<network ipv6='yes'>
 <forward mode='nat'/>
 <bridge name='virbr1' stp='on' delay='0'/>
 <mac address='52:54:00:a0:ae:fd'/>
+ <domain name='' localOnly='yes'/>
 <ip address='' netmask=''>
 <range start='' end=''/>

To make the changes take effect, we need to destroy and re-create the network, so first I destroy the vagrant machines, then destroy and restart the network:

vagrant destroy -f
virsh net-destroy --network vagrant-libvirt
virsh net-start --network vagrant-libvirt

Finally, we can re-create the machines, and log in to one to check that they can resolve each other:

[email protected]$ vagrant up
[email protected]$ vagrant ssh one
[email protected]$ ping two
PING ( 56(84) bytes of data.
[email protected]$ exit

You can also check that the host can resolve the machine names when querying the virtual network’s DNS server:

[email protected]$ dig @ +short one

Host DNS Forwarding

The host cant talk to the machines by name still, so we need to tweak the host’s DNS, which means fighting with SystemD. Luckily, we only need to forward requests to a DNS server running on port 53 - if it was on another port then replacing systemd-resolved like my post on Consul DNS forwarding would be necessary.

Edit /etc/systemd/resolved.conf on the host, to add two lines which instruct it to send DNS requests for the domain picked earlier to the DNS server run by libvirt (dnsmasq):


Lastly, restart systemd-resolved for the changes to take effect:

systemctl restart systemd-resolved

Now we can resolve the guest machines by hostname at the domain we picked earlier:

[email protected]$ ping
PING ( 56(84) bytes of data.


libvirt, vagrant, dns

« Nomad Good, Kubernetes Bad Consul DNS Fowarding in Alpine, revisited »