Skip to main content
  1. Posts/

Remote access to your LXD server through Tailscale

·844 words·4 mins

I recently started playing around with LXD, a next-generation system container and virtual machine manager.

Now I thought it was time to get more serious about it, so I wanted to deploy it on one of my servers at Hetzner.

Initial Setup #

Although LXD can be used on various Linux distributions, I think it works best with Ubuntu, since the development of LXD is also supported by Canonical. Therefore, I used a fresh install of Ubuntu 22.04 LTS as the base system for my setup.

The only change I made after installation was to enable the built-in firewall UFW and allow only ssh connections:

$ sudo ufw allow ssh
$ sudo ufw enable

Install LXD #

On Ubuntu, LXD is best installed as package from Snapcraft:

$ sudo snap install lxd

Once LXD is installed, you can initialize LXD on your server with the suggested default settings:

$ sudo lxd init
Would you like to use LXD clustering? (yes/no) [default=no]:
Do you want to configure a new storage pool? (yes/no) [default=yes]:
Name of the new storage pool [default=default]:
Name of the storage backend to use (lvm, zfs, ceph, btrfs, dir) [default=zfs]:
Create a new ZFS pool? (yes/no) [default=yes]:
Would you like to use an existing empty block device (e.g. a disk or partition)? (yes/no) [default=no]:
Size in GB of the new loop device (1GB minimum) [default=5GB]: 10GB
Would you like to connect to a MAAS server? (yes/no) [default=no]:
Would you like to create a new local network bridge? (yes/no) [default=yes]:
What should the new bridge be called? [default=lxdbr0]:
What IPv4 address should be used? (CIDR subnet notation, “auto” or “none”) [default=auto]:
What IPv6 address should be used? (CIDR subnet notation, “auto” or “none”) [default=auto]:
Would you like the LXD server to be available over the network? (yes/no) [default=no]:
Would you like stale cached images to be updated automatically? (yes/no) [default=yes]:
Would you like a YAML "lxd init" preseed to be printed? (yes/no) [default=no]:

If you have UFW enabled, as mentioned earlier, you must allow traffic from interface lxdbr0 to the LXD host and forward traffic from lxdbr0 to the external network without allowing all incoming external traffic, as described here:

$ sudo ufw allow in on lxdbr0
$ sudo ufw route allow in on lxdbr0

Launch a container #

Let’s start our first container by using the command line client for LXD:

$ lxc launch ubuntu:22.04
Creating the instance
Instance name is: right-stingray
Starting right-stingray

$  lxc ls
+----------------+---------+-----------------------+------------------------------------------------+-----------+-----------+
|      NAME      |  STATE  |         IPV4          |                      IPV6                      |   TYPE    | SNAPSHOTS |
+----------------+---------+-----------------------+------------------------------------------------+-----------+-----------+
| right-stingray | RUNNING | 10.152.219.164 (eth0) | fd42:d433:1d15:da1a:4c2e:4bff:fe51:938a (eth0) | CONTAINER | 0         |
+----------------+---------+-----------------------+------------------------------------------------+-----------+-----------+

Remote access with Tailscale #

Open your LXD server to your Tailscale network #

Now you have completed the basic setup of LXD to start new system containers and virtual machines on the server. Up to this point, you were logged into the server via SSH to use the lxc CLI. Although this works well, lxc can be used from a remote machine to manage LXD. However, it would not be a good idea to put the API openly on the Internet.

Let’s configure Tailscale to do this in a much safer way. Please read these instructions on how to install Tailscale.

Once you have installed Tailscale, you must obtain the assigned IP address of your Tailscale network interface:

$ tailscale ip
100.12.123.100

And use this IP address to share your LXD server with your Tailscale network:

$ sudo lxc config set core.https_address 100.12.123.100:8443

If you have enabled UFW, as mentioned earlier, you must allow any traffic from the tailscale0 interface to port 8443:

$ sudo ufw allow in on tailscale0 proto tcp to any port 8443

Add your LXD server as a new remote to your machine #

To proceed, you must have Tailscale and the command line for LXD installed on your computer. Please read the following instructions to install:

Note: If you have installed Homebrew on your computer, then you can install the command line for LXD with brew install lxc


In a first step you have to trust a new client on the LXD server to get the token to add our machine as a valid remote later:

$ sudo lxc config trust add
Please provide client name: macbook-air
Client macbook-air certificate add token:
eyJjbGllbnRfbmFtZSI6Im1hY2Jvb2stYWlyIiwiZmluZ2VycHJpbnQiOiI1ZGJkYzkzN2U0ODQ1NjY0NDY2NWQ0Zj...

Now you can add your LXD server as a new remote station on your machine by using the token as admin password:

$ lxc remote add lxd-server 100.12.123.100
Certificate fingerprint: 5dbdc937e48456644665d4f0d535bb0f5f3dc8d822ad8fda3a6db54be6220fac
ok (y/n/[fingerprint])? y
Admin password for lxd-server:
Client certificate now trusted by server: lxd-server

Since the command line of LXD allows more than one remote connection to an LXD server, you can switch between the different remotes with the following command:

$ lxc remote switch lxd-server

Congratulations, you can now securely manage your LXD server within your Tailscale network from your personal machine:

$ lxc list
+----------------+---------+-----------------------+------------------------------------------------+-----------+-----------+
|      NAME      |  STATE  |         IPV4          |                      IPV6                      |   TYPE    | SNAPSHOTS |
+----------------+---------+-----------------------+------------------------------------------------+-----------+-----------+
| right-stingray | RUNNING | 10.152.219.164 (eth0) | fd42:d433:1d15:da1a:4c2e:4bff:fe51:938a (eth0) | CONTAINER | 0         |
+----------------+---------+-----------------------+------------------------------------------------+-----------+-----------+