How to find the size of a lxc container

In order to determine the size of a LXC container, first run lxc storage list to list your storage pools:

uli@myserver:~$ lxc storage list
|  NAME   | DESCRIPTION | DRIVER |               SOURCE               | USED BY |
| default |             | dir    | /var/lib/lxd/storage-pools/default | 2       |

If the driver is not dir, you are using a COW-type storage backend. Using this technology it is not possible to easily determine the storage size of a container. The following instructions apply only for the dir driver.

Now open a root shell and cd to the directory listed in the SOURCE column and cd to its containers subdirectory:

root@myserver ~ # cd /var/lib/lxd/storage-pools/default
root@myserver /var/lib/lxd/storage-pools/default # cd containers/
root@myserver /var/lib/lxd/storage-pools/default/containers # 

This directory contains the storage directory for all containers. Run du -sh * in order to find the size of each container:

root@myserver /var/lib/lxd/storage-pools/default/containers # du -sh *
2.0G    my-container

In this example, the container my-container occupies 2.0 Gibibytes of disk space.

Routing public IPv6 addresses to your lxc/lxd containers

The enormous amount of IPv6 addresses available to most commercially hosted VPS / root servers with a public IPv6 prefix allows you to route a public IPv6 address to every container that is running on your server. This tutorial shows you how to do that, even if you have no prior experience with routing,

Step 0: Create your LXC container

We assume you have already done this – just for reference, here’s how you can create a container:

lxc launch ubuntu:18.04 my-container

Step 1: Which IP address do you want to assign to your container?

First you need to find out what prefix is routed to your host. Usually you can do that by checking in your provider’s control panel. You’re looking for something like 2a01:4f9:c010:278::1/64. Another option would be to run sudo ifconfig

and look for a inet6 line in the section of your primary network interface (this only works if you have configured your server to have an IPv6 address). Note that addresses that start with fe80:: and addresses starting with fd, among others, are not public IPv6 addresses.

Then you can define a new IPv6 address to your container. Which one you choose – as long as it’s within the prefix – is entirely your decision.

Often, <prefix>::1 is used for the host itself, therefore you could, for example, choose <prefix>::2. Note that some providers use some IP addresses for other purposes. Check your provider’s documentation for details.

If you don’t want to make it easy to find your container’s public IPv6, don’t choose <prefix>::1<prefix>::2<prefix>::3 etc but something more random like <prefix>:af15:99b1:0b05:1, for example2a01:4f9:c010:278:af15:99b1:0b05:0001. Ensure your IPv6 address has 8 groups of 4 hex digits each!

For this example, we choose the IPv6 address 2a01:4f9:c010:278::8.

Step 2: Find out the ULA of your container

We need to find the ULA (unique local address – similar to a private IPv4 address which is not routed on the internet) of the container. Using lxc, this is quite easy:

uli@myserver:~$ lxc list
|     NAME     |  STATE  |         IPV4          |                     IPV6                      |
| my-container | RUNNING | (eth0) | fd42:830b:36dc:3691:216:3eff:fed1:9058 (eth0) |

You need to look in the IPv6 column and copy the address listed there. In this example, the address is fd42:830b:36dc:3691:216:3eff:fed1:9058.

Step 3: Setup IPv6 routing

Now we can tell the host Linux to route your chosen public IPv6 to the container’s private IPv6. This is quite easy:

sudo ip6tables -t nat -A PREROUTING -d <public IPv6> -j DNAT --to-destination <container private IPv6>

In our example, this would be

sudo ip6tables -t nat -A PREROUTING -d 2a01:4f9:c010:278::8 -j DNAT --to-destination fd42:830b:36dc:3691:216:3eff:fed1:9058

First, test the command by running it in a shell. If it works (i.e. if it doesn’t print any error message), you can permanently store it e.g. by adding it to /etc/rc.local (after #!/bin/bash, before exit 0). Advanced users should prefer to add it to /etc/network/interfaces.

Step 4: Connect to your container using SSH on your public IPv6 (optional)

Note: This step requires that you have working IPv6 connectivity at your local computer. If you are unsure, check at

First, open a shell on your container:

lxc exec my-container bash

After running this, you should see a root shell prompt inside your container:


The following commands should be entered in the container shell, not the host!

Now we can create a user to login to (in this example, we create the uli user):

root@my-container:~# adduser uli
Adding user `uli' ...
Adding new group `uli' (1001) ...
Adding new user `uli' (1001) with group `uli' ...
Creating home directory `/home/uli' ...
Copying files from `/etc/skel' ...
Enter new UNIX password: 
Retype new UNIX password: 
passwd: password updated successfully
Changing the user information for uli
Enter the new value, or press ENTER for the default
        Full Name []: 
        Room Number []: 
        Work Phone []: 
        Home Phone []: 
        Other []: 
Is the information correct? [Y/n]

You only need to enter a password (you won’t see anything on screen when entering it) twice, for all other lines you can just press enter.

The ubuntu:18.04 lxc image used in this example does not allow SSH password authentication in its default configuration. In order to fix this, change PasswordAuthentication no to PasswordAuthentication yes in /etc/ssh/sshd_config and restart the SSH server by running service sshd restart. Be sure you understand the security implications before you do that!

Now, logout of your container shell by pressing Ctrl+D. The following commands can be entered on your desktop or any other server with IPv6 connectivity.

Now login to your server:

ssh <username>@<public IPv6 address>

in this example:

ssh uli@2a01:4f9:c010:278::8

If you configured everything correctly, you’ll see the shell prompt for your container:


Note: Don’t forget to configure a firewall for your container, e.g. ufw! Your container’s IPv6 is exposed to the internet and just assuming noone will guess it is not good security practice.

Solving Docker permission denied while trying to connect to the Docker daemon socket


You are trying to run a docker container or do the docker tutorial, but you only get an error message like this:

docker: Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Post http://%2Fvar%2Frun%2Fdocker.sock/v1.26/containers/create: dial unix /var/run/docker.sock: connect: permission denied.
See 'docker run --help'.


The error message tells you that your current user can’t access the docker engine, because you’re lacking permissions to access the unix socket to communicate with the engine.

As a temporary solution, you can use sudo to run the failed command as root.
However it is recommended to fix the issue by adding the current user to the docker group:

Run this command in your favourite shell and then completely log out of your account and log back in (if in doubt, reboot!):

sudo usermod -a -G docker $USER

After doing that, you should be able to run the command without any issues. Run docker run hello-world as a normal user in order to check if it works. Reboot if the issue still persists.

Logging out and logging back in is required because the group change will not have an effect unless your session is closed.

User Mode Linux for Beginners – Setup and first VM

Why another UML tutorial?

This is not the first tutorial on UML — there are hundreds of them publicly available on the internet. However, none of them seems to fulfill my requirements:

  • All my computers and servers (= UML hosts) run on x86_64, not on i386.
  • Use an up-to date (self-compiled) UML version, so you can use the latest features
  • One simple set of scripts. Execute them in the correct order to get it up and running – no config file editing etc.
  • Root should not be required (disregarding debootstrap) —> No /mnt mounts or similar
  • No nasty filesystem image that eats up space on the host and limits resources on the UML VM. HostFS eliminates all those disadvantages – if you want to limit VM space, use quotas.
  • No global state (e.g. mounting sth into /mnt), you should get another VM up and running concurrently by executing the setup scripts in another directory.
  • Step-by-step instructions, as automated and portable as possible, but still made to be read by humans.
  • No expansive techtalk. There are reference documentations out there for techtalk. A tutorial should tell you how to get it working, not why it works.

Read more