Getting started with LXD 2.0 container hypervisor

4 min read

For the past few years I have been migrating between different OpenVZ VPS providers and each time it has been a hassle to migrate and upgrade my virtual machines between them. Then I stumbled upon LXD which in combination with a KVM VPS seems like a perfect fit for running multiple containers on a single KVM VPS and migrating them to and from others LXD hosts with a single command! Notice that using OpenVZ VPS’es is not possible since the kernel is too old. For this post I used VirtualBox, but plan on migrating the whole setup to a KVM VPS at RamNode which I highly recommend.

Check out my post here for installing the latest stable version of LXD on Ubuntu 16.04

Installation of LXD host

Start by installing a copy of the newest Ubuntu server on VirtualBox, I used Ubuntu 16.04.1 LTS. This already comes with LXD which just need to be configured. I configured LXD with the default values except saying yes to making LXD available over the network. Replace somepassword with your own password.

$sudo lxd init
Name of the storage backend to use (dir or zfs) [default=dir]: dir
Would you like LXD to be available over the network (yes/no) [default=no]? yes
Address to bind LXD to (not including port) [default=all]: all
Port to bind LXD to [default=8443]: 8443
Trust password for new clients: somepassword
Again: somepassword
Do you want to configure the LXD bridge (yes/no) [default=yes]? yes

This will open the bridge configurator. I used the default values.

01: LXD bridge configuration
02: Bridge name
03: IPv4 subnet
04: IPv4 address
05: IPv4 CIDR mask
06: First DHCP address
07: Last DHCP address
08: Max number of DHCP clients
09: NAT IPv4 traffic
10: IPv6 subnet

This should end with a LXD has been successfully configured message.

Setup a container

Lets create an Ubuntu container

$lxc launch ubuntu: test-container

After it is done we confirm that the container is running

$lxc list
    |      NAME       |  STATE  |          IPV4          | IPV6 |    TYPE    | SNAPSHOTS |
    | test-container  | RUNNING | (eth0)     |      | PERSISTENT | 0         |

That’s it! We can now enter the container

$lxc exec test-container bash

Which will enter the container as root


Here we can as an example setup NGINX

root@test-container:~#apt-get install nginx

Then exit the container


Which drops us back to the host. Here we can now access the webserver we just installed on the container

--2016-10-22 23:20:15--
Connecting to connected.
HTTP request sent, awaiting response... 200 OK
Length: 632 [text/html]
Saving to: ◼index.html◼

index.html           100%[==============================>]      632   --.-KB/s

2016-10-22 23:20:16 (41.0 MB/s) - ◼index.html◼ saved [632/632]

Lastly I wanted a static ip address for my containers

$sudo nano /etc/default/lxd-bridge

Find the line LXD_CONFILE and change it to LXD_CONFILE="/etc/default/lxd_dnsmasq.conf" and save the file. Next we create the lxd_dnsmasq.conf file which will contain our static ip mapping

$sudo nano /etc/default/lxd_dnsmasq.conf

For each container add a line dhcp-host=container_name,ip_address, for our container we add the following in the beginning of the file dhcp-host=test-container, and save the file. Now stop the container

$lxc stop test-container

Restart the LXD bridge

$sudo service lxd-bridge stop && sudo service lxd-bridge start

And start the container again

$lxc start test-container

Now this container will always use ip

$lxc list
    |      NAME       |  STATE  |          IPV4          | IPV6 |    TYPE    | SNAPSHOTS |
    | test-container  | RUNNING |  (eth0)     |      | PERSISTENT | 0         |

Migrate containers between LXD hosts

Lets assume that this LXD host we have created has the ip of And lets assume we have another LXD host at ip (if you used VirtualBox for this guide you can just clone the whole setup and change the ip). We want to migrate the test-container from to

Both LXD hosts

First we install criu on both LXD hosts.

$sudo apt-get install criu host

Then we add a reference to from Replace somepassword with your own password from the beginning of this post.

$lxc remote add host1
Certificate fingerprint:
ok (y/n)? y
Admin password for host1: # somepassword
Client certificate stored at server:  host1

We can now move or copy test-container to

$lxc copy host1:test-container test-container

This can take a long time if the container is large or the connection is slow. For me it takes less than a minute, but there is no progress indicator at the moment. Lastly we check if the new container is transferred.

$lxc list
    |      NAME       |  STATE  |          IPV4          | IPV6 |    TYPE    | SNAPSHOTS |
    | test-container  | RUNNING |   (eth0)    |      | PERSISTENT | 0         |

Since we cloned this host from, it also remembers our configuration that a container named test-container will get the ip Notice that a copy will stop the original container. To prevent this we can take a snapshot first and then transfer the snapshot.

$lxc snapshot host1:test-container current
$lxc copy host1:test-container/current test-container
$lxc start test-container

Lastly one can play around with live migration, but I choose not to do that yet since it is an experimental feature in LXD 2.0, but take a look at this post for more information.

Explore more:


↑ back to top