Network switch

Root server with IPv6-only KVM guests (II): NAT64, DNS64, and KVM 4

Root ser­ver with IPv6-only KVM guests

In the first part of this arti­cle series, I’ve descri­bed how to set up a root ser­ver which can ser­ve KVM guests which only have IPv6 con­nec­tivi­ty. I use the Ger­man hos­ting pro­vi­der Hetz­ner as an examp­le and descri­be a brid­ged set­up which fits into that provider’s IPv6 infra­st­ruc­tu­re.

Network switch

Net­work switch

After the basic set­up, we need some more ser­vices on the host to be able to install the first guest sys­tems.

Create a non-root user on the system.

Hetzner’s instal­la­ti­on pro­cess gene­ra­tes a sys­tem with only the root user. To make it more com­pli­ant with usu­al Ubun­tu beha­viour, add a non-root user:

  • Crea­te user with adduser.
  • Put your ssh public key into .ssh/authorized_keys of that user.

You can now eit­her per­form the fol­lo­wing steps as that user with sudo -s or con­ti­nue as direc­t­ly log­ged in root via ssh.

NAT64 with Tayga

As I wro­te, our guest sys­tems shall have IPv6-only inter­net. That implies that they can­not access sys­tems which are IPv4-only. Unfor­tu­n­a­te­ly, even in 2018, the­re are qui­te popu­lar sites like which do not have any IPv6 con­nec­tivi­ty at all. To make such sys­tems acces­si­ble from the guest sys­tems, we set up a NAT64 ser­vice which per­forms a net­work address trans­la­ti­on for exac­t­ly this case.

I deci­ded to go with the „Tay­ga” ser­ver. Its scope is limi­ted to exac­t­ly per­form NAT64. This makes it necessa­ry to add fur­ther ser­vices to make all this real­ly use­ab­le but it also mini­mi­zes con­fi­gu­ra­ti­on com­ple­xi­ty. This is what I did:

  • Install the tay­ga ser­vice by the usu­al
  • In /etc/tayga.conf, enab­le the dis­ab­led ipv6-addr direc­tive as this is nee­ded for working with the well-known pre­fix. You should set the IPv6 address to some­thing ran­dom in your IPv6 sub­net:

    Addi­tio­nal­ly, switch the prefix direc­tive from the activa­ted 2001... one to the 64:ff9b::/96 one::

  • The who­le Tay­ga con­fi­gu­ra­ti­on reads like this:
  • Test the new set­up by star­ting tayga once in fore­ground:

    This should give some­thing like this:

  • Stop the manu­al­ly star­ted instan­ce and edit /etc/default/tayga. Set RUN to yes:
  • Launch the ser­vice

    systemctl status tayga should say the Active sta­te is active (running), the log should end with

  • If the Active sta­te is active (exited) and the pro­to­col says some­thing about „set RUN to yes”, you have for­got­ten to enab­le the RUN opti­on in /etc/default/tayga. If you cor­rect that, you have to per­form a stop and a start com­mand after­wards to launch tay­ga:

DNS64 with bind

NAT64 is usual­ly used tog­e­ther with a so-cal­led „DNS64” name ser­ver. This is a spe­ci­al­ly con­fi­gu­red name ser­ver. If a cli­ent asks it for an IPv6 name reso­lu­ti­on, i.e. an AAAA name ser­vice record and the­re is only an IPv4 A record for the requested name, the DNS64 name ser­ver „mocks up” an AAAA record mun­ging the IPv4 address and a „well-known pre­fix” to a syn­the­ti­cal IPv6 address. This address – sur­pri­se, sur­pri­se – points direc­t­ly to a nice­ly pre­pa­red NAT64 ser­ver so that the IPv6 sys­tem talks to an IPv4 sys­tem trans­par­ent­ly hid­den behind the NAT64 pro­xy.

DNS64 and NAT64 translate betwwen IP protocols

DNS64 and NAT64 trans­la­te bet­ween IP pro­to­cols

Go on like this:

  • Install bind9 on the host:
  • Our bind is a for­war­ding only-ser­ver only for our own vir­tu­al machi­nes. On Debi­an-deri­ved sys­tems, the bind opti­ons nee­ded for this set­up are loca­ted in /etc/bind/named.conf.options. Edit that file and enter the fol­lo­wing ent­ries:
  • The actu­al important defi­ni­ti­on is the dns64 sec­tion at the bot­tom of the options defi­ni­ti­ons. It enab­les the DNS64 mode of bind and defi­nes the IPv6 address ran­ge into which the addres­ses should be con­ver­ted.
  • It also important to defi­ne listen-on {}; to dis­able lis­ten­ing on the IPv4 port altog­e­ther – we do not need it. Restric­ting allow-query to the localnets is also important to pre­vent the ser­ver from beco­m­ing an open DNS relay. We only need it for our inter­nal net­work.
  • Check the net­work in listen-on-v6 and also check the forwarders. You who­le IP address reso­lu­ti­on will not work if one of the­se is wrong.
  • Restart the dae­mon and check that it is enab­led and run­ning:

After the­se steps, you have a working DNS64 ser­ver which you can use for all your vir­tu­al machi­nes on the sys­tem.

Using an exter­nal DNS64 ser­ver
So far, the name ser­ver is only used for DNS64. You can also use the Goog­le ser­vers 2001:4860:4860::6464 and 2001:4860:4860::64 offe­ring this ser­vice. Their replies are com­pa­ti­ble with our NAT64 set­up. Howe­ver, having an own ser­ver redu­ces exter­nal depen­den­ci­es and allows for addi­tio­nal ser­vices late­ron.

Include NAT64/DNS64 into radvd advertisements

We now have the NAT64/DNS64 ser­vice pair up and run­ning. We will inform the vir­tu­al machi­nes by the rou­ter adver­ti­se­ment dae­mon we have alrea­dy set up. This sim­pli­fies instal­la­ti­on and admi­nis­tra­ti­on tre­men­dous­ly:

  • Extend /etc/radvd.conf:
  • The RDNSS defi­ni­ti­on descri­bes which DNS ser­ver to access. Use the host’s IP address. If you opted for the Goog­le ser­vers to do the job, wri­te ins­tead
  • The route sec­tion adver­ti­ses that this sys­tem rou­tes the 64:ff9b:: net­work. Only with this defi­ni­ti­on the vir­tu­al ser­vers know whe­re to send the packets for the emu­la­ted IPv6 addres­ses for the IPv4-only ser­vers to.
  • Restart radvd and check its out­put with radvdump. It should con­tain both the DNS ser­ver and the NAT64 rou­te.
The nas­ty Hetz­ner pit­fall
In their own docu­men­ta­ti­on, Hetz­ner also descri­bes how to set­up radvd. For the DNS ser­vers, howe­ver, they use IPv6 examp­le addres­ses from the 2001:db8 realm. It took me three days and seve­re doubts about Hetzner’s IPv6 set­up to find out, that my only mista­ke was to copy the­se wrong IP addres­ses for the DNS ser­ver into the con­fi­gu­ra­ti­on. Don’t make the same mista­ke…

You have now pre­pa­red ever­ything for the IPv6-only vir­tu­al machi­nes to come: They get their net­work con­fi­gu­ra­ti­on through the cen­tral­ly admi­nis­tra­ted radvd. The adver­ti­sed set­up inclu­des a name ser­ver with DNS64 and a NAT64 rou­te to access IPv4-only sys­tems.

About non-vir­tu­al net­work set­ups
In my series, I descri­be how to set up a root ser­ver with vir­tu­al machi­nes. Espe­ci­al­ly NAT64/DNS64 is com­ple­te­ly inde­pen­dent of that. If you admi­nis­tra­te a (real) com­pu­ter net­work and want to lay the ground for IPv6-only machi­nes in that, do exac­t­ly the same with your phy­si­cal machi­nes: Install Tay­ga and the DNS64-capa­ble Bind9 on the rou­ter behind which the IPv6-only sys­tems resi­de. This might be the „fire­wall” of clas­si­cal set­ups. Then, your actu­al com­pu­ters play the role of the vir­tu­al machi­nes in this gui­de.

Install KVM

We’­re now rea­dy for the final steps! Our net­work is con­fi­gu­red far enough so that we real­ly can start instal­ling vir­tu­al machi­nes on our sys­tem. For this, we, of cour­se, need KVM. For Ubun­tu 18.04 I fol­lo­wed the first steps of this gui­de::

  • Check that the sys­tem sup­ports vir­tua­li­za­ti­on at all. Issue

    and veri­fy that the result is grea­ter than 0.

  • Then, app­ly

    and check that the result is

    If not, the BIOS set­tings of the sys­tem must be cor­rec­ted. Con­tact the hos­ting pro­vi­der to sort that out.

  • Install KVM and the requi­red hel­per packa­ges:

    This will install a rather lar­ge num­ber of new packa­ges on your host. Final­ly, it will be capa­ble to ser­ver vir­tu­al machi­nes.

  • The libvirtd dae­mon should alrea­dy be up and run­ning at this point. If this is, for any rea­son, not the case, start and enab­le it with the usu­al systemctl com­mands or wha­te­ver the init sys­tem of your host ser­ver requi­res to do this.
  • To sim­pli­fy instal­la­ti­on and admi­nis­tra­ti­on of your vir­tu­al machi­nes, add the „nor­mal” user you crea­ted above to the libvirt user group. I pre­fer doing this by sim­ply adding the user name to the defi­ni­ti­on in /etc/group:

Well, that’s it! Our sys­tem can get its first vir­tu­al machi­ne!

The first virtual machine

Instal­ling a vir­tu­al machi­ne might sound dif­fi­cult to you if you have never done this befo­re. In fact, it is not. After all, it is even simp­ler than the remo­te instal­la­ti­on on a hosted sys­tem once you get used to it. On the phy­si­cal machi­ne, you are depen­dent on what the hos­ting pro­vi­der offers as instal­la­ti­on pro­ce­du­res. KVM offers you more or less a com­ple­te vir­tua­li­zed gra­phi­cal con­so­le which allows acting just as you were sit­ting in front of the (vir­tu­al) computer’s moni­tor. This way, you can install wha­te­ver you like.

Fur­ther­mo­re, if you make a con­fi­gu­ra­ti­on mista­ke on the phy­si­cal host, you might end with a bro­ken machi­ne. If this hap­pens in a vir­tu­al machi­ne, you have several ways to sol­ve the pro­blem: You can con­nect to the con­so­le and log in direc­t­ly wit­hout net­work access. If the machi­ne does not boot any­mo­re, you can even mount the vir­tu­al hard disk into the phy­si­cal machi­ne and try to fix. And if the machi­ne is for any rea­son bro­ken bey­ond repair, you can just throw it away and start over with a fresh instal­la­ti­on.

I sug­gest star­ting with a throw-away vir­tu­al machi­ne. It will not con­tain any „real” ser­vices but only show any remai­ning pro­blems in the set­up. Fur­ther, it allows to test and learn the who­le pro­cess of instal­ling a vir­tu­al machi­ne in the set­up. Pre­pa­re the set­up with the fol­lo­wing steps:

  • Copy the instal­la­ti­on ISO image for the sys­tem to install onto the host.
  • Con­nect to the KVM sys­tem using virt-manager. Of cour­se, you might also use ano­t­her cli­ent, but I find this rather easy.
  • Use the ssh con­nec­tion of the nor­mal user crea­ted on the host.
  • Start the host crea­ti­on.

From here on, things beco­me rather stan­dard. We’­re now in the pro­cess of instal­ling a guest sys­tem in a KVM guest. My best prac­tices are the­se:

  • Assign as many CPUs to the vir­tu­al machi­ne as the hard­ware has. Only if you suspect the vir­tu­al machi­ne to grab too many resour­ces, redu­ce the CPU num­ber.
  • Use cow2 image file for the vir­tu­al hard disk. It is the most fle­xi­ble way once it comes to migra­ting the vir­tu­al machi­ne and today’s file sys­tems can cope with the dou­ble indi­rec­tion qui­te well.
  • Give the vir­tu­al machi­ne defi­ni­ti­on the same name the sys­tem will later have.

The one inte­res­ting point is the net­work con­fi­gu­ra­ti­on at the very end of the defi­ni­ti­on pro­cess. Here, enter the „Net­work selec­tion” befo­re crea­ting the machi­ne. Select „Name of com­mon device” and give the name of bridge expli­citly. Here it is br0.

Network setup for virtual machine in virt-manager

Net­work set­up for vir­tu­al machi­ne in virt-mana­ger

If you are rea­dy, press „Crea­te” and sum­mon your first vir­tu­al sys­tem.

Ubuntu 18.04 as guest system

We’­re now at a sta­ge whe­re you can install any ope­ra­ting sys­tem which is install­ab­le in KVM vir­tu­al machi­nes. I give some advi­ses for the Ubun­tu 18.04 net­work instal­ler:

  • Install by sim­ply pres­sing the „Install” but­ton. I never nee­ded any addi­tio­nal ker­nel para­me­ters.
  • Select cor­rect key­board or it will dri­ve you nuts.
  • Net­work auto­de­tec­tion will idle around when loo­king for the non-exis­ting DHCP ser­ver. Keep calm. Apart from that, it will sim­ply set­up ever­ything cor­rec­t­ly.
  • Enter the host­na­me, pre­fer­ra­b­ly the same as the name of the vir­tu­al machi­ne to keep it simp­le…
  • Check whe­ther you pro­vi­der has their own mir­ror for the instal­la­ti­on ser­ver. Hetz­ner has, the­re­fo­re you can save down­load time:
    • Go to top of mir­ror list and press enter information manually
    • For Hetz­ner: This ser­ver also works also with IPv6. But even IPv4 ser­vers would be pos­si­ble due to our NAT64/DNS64 set­up.
    • Set direc­to­ry for the Hetz­ner ser­ver to /ubuntu/packages/
  • You do not need a HTTP pro­xy.
  • Install should start.
  • I sug­gest to not par­ti­ti­on the vir­tu­al hard disk in any way. It is not nee­ded.
  • Ever­ything else is as usu­al. In the soft­ware selec­tion, you should at least select the „OpenSSH ser­ver” so that you can log into the sys­tem after instal­la­ti­on.
Ubuntu 18.04 within KVM virt-manager

Ubun­tu 18.04 wit­hin KVM virt-mana­ger

As this is Ubun­tu 18.04, this machi­ne uses net­plan for net­work con­fi­gu­ra­ti­on. It has a very simp­le defi­ni­ti­on file in /etc/netplan/01-netcfg.yaml:

Net­plan sum­ma­ri­zes rou­ter adver­ti­se­ment in the „dhcp6” state­ment.

Note that after (re-)booting the vir­tu­al machi­ne, it may take some seconds until it has con­fi­gu­red its net­work inter­face. Once it has done so, ever­ything should work wit­hout pro­blems.

Entering the virtual machine in DNS

To work with the long IPv6 addres­ses con­ve­ni­ent­ly, DNS is almost man­dato­ry. You should enter the vir­tu­al machi­ne now into the domain.

  • Find the vir­tu­al machine’s IP address, e.g. through „ip a”.
  • Crea­te an ent­ry in the DNS zone of the sys­tem. Note that you only enter a AAAA record, not an old-fashio­ned A record for an IPv4 address. The sys­tem just has no IPv4 address…
  • In my opi­ni­on, it makes also sen­se to always crea­te a rever­se IP ent­ry for IPv6 hosts. If for any rea­son your DNS AAAA ent­ry vanis­hes, you still have the rever­se IP ent­ry which assigns name and IP address. Rever­se IP ent­ries are always mana­ged in the DNS realm of the IP net­work owner. In my case, they are edi­ted in Hetzner’s robot inter­face.
Reverse IP entries in Hetzner's robot interface

Rever­se IP ent­ries in Hetzner’s robot inter­face

The SLAAC mecha­nism deri­ves the IP address from the MAC address of the vir­tu­al machi­ne. So, it will be sta­tic even though it has nowhe­re been con­fi­gu­red expli­citly. This who­le mecha­nism works smooth­ly with any modern ope­ra­ting sys­tem. I even made a test instal­la­ti­on of Win­dows 10 which went per­fec­t­ly wit­hout any IPv4 address.

IPv6-only network settings in Windows 10

IPv6-only net­work set­tings in Win­dows 10

We can now install any num­ber of vir­tu­al machi­nes on our ser­ver. In the next arti­cles of this series, I descri­be how I set up some ser­vices on this infra­st­ruc­tu­re. The most important ones are, of cour­se, e‑mail and web ser­vers.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

4 Gedanken zu “Root server with IPv6-only KVM guests (II): NAT64, DNS64, and KVM

  • Sebastian

    Hal­lo Dirk,

    vie­len Dank für die­se sehr aus­führ­li­che und unglaub­lich hilf­rei­che Anlei­tung.
    Ich hat­te es schon fast auf­ge­ge­ben so ein set­up bei Hetz­ner mög­lich zu machen aber dei­ne Anlei­tung hat gera­de alle Stei­ne aus dem Weg geräumt. DANKE!

    Son­ni­ge Grü­ße

    • Dirk Hillbrecht Autor des Beitrags

      Hal­lo Sebas­ti­an,

      das freut mich! Ich weiß nicht, wann du der Anlei­tung gefolgt bist: Ich habe erst kürz­lich im ers­ten Teil den Abschnitt mit der Mas­kie­rung der inter­nen MAC-Adres­sen hin­zu­ge­fügt. Ohne das macht Hetz­ner irgend­wann Stress…

      Vie­le Grü­ße und viel Erfolg beim wei­te­ren Admi­nis­trie­ren,

      • Sebastian

        Hal­lo Dirk,

        dan­ke für den Tipp, ich habe es mit umge­setzt. Nun muss ich nur noch einen sinn­vol­len Weg fin­den Ser­ver­diens­te in den Gäs­ten per IP4 anzu­bin­den. Hast du da einen Tipp? Ich schwan­ke zwi­schen Nginx rever­se pro­xy und socat.

        Dir eine son­ni­ge Zeit und bes­te Grü­ße

        • Dirk Hillbrecht Autor des Beitrags

          Hal­lo Sebas­ti­an,

          ich habe das mit einem Rever­se Pro­xy mit Apa­che gemacht. socat hat bei mir nicht zuver­läs­sig funk­tio­niert und so habe ich nur eine Tech­nik zu war­ten. Außer­dem wirk­te socat auf mich arg gebas­telt…

          Ciao, Dirk