1. List your lxc images
lxc image list
2. Delete image
lxc image delete [image alias]
1. List your lxc images
lxc image list
2. Delete image
lxc image delete [image alias]
1. Create a snapshot
lxc snapshot [mycontainer] [snapshot name]
2. Create local image from snapshot
lxc publish [mycontainer]/[snapshot name] --alias [image alias]
3. List your images
lxc image list
4. Create container from iamge
lxc launch [image alias] [mynewcontainer]
You can copy a running lxc container like this
lxc copy [name of container to be copied] [new container]
for example
lxc copy mycontainer mycontainerCopy
You can run a shell in your LXC container using
lxc exec [name of container] /bin/bash
for example
lxc exec mycontainer /bin/bash
You are trying to launch a LXC container using a command like
lxc launch mycontainer ubuntu:18.04
but you see this error message:
Your command line arguments are in the wrong order. You need to run lxc launch [image] [name of container]
, not lxc launch [name of container] [image]
! The correct command looks like this:
lxc launch ubuntu:18.04 mycontainer
You are trying to copy a file to a LXC container using lxc file push
, but you see this error message:
Error: Path already exists as a directory: File too large
Add a slash (/
) at the end of your path, for example:
mycontainer/root
=> mycontainer/root/
Working example:
lxc file push myfile.zip mycontainer/root/
Also see our previous post How to copy files to a LXC container
Once you’ve created a LXC container using a command like
lxc launch ubuntu:18.04 mycontainer
you can push files to the container using
lxc file push myfile.zip mycontainer/root/
This will copy the local file myfile.zip
to /root/myfile.zip
on the container. Ensure that your path ends with /
, since lxc file push myfile.zip mycontainer/root
will show this error message:
Error: Path already exists as a directory: File too large
In that case, add a slash (/
) to the end of your destination path (e.g. mycontainer/root
=> mycontainer/root/
).
Run this:
lxc launch ubuntu:22.04 mycontainer
In case you see this error message
Error: Failed container creation: No storage pool found. Please create a new storage pool
see How to fix lxd ‘Failed container creation: No storage pool found. Please create a new storage pool.’
Now you can connect to your container using
lxc exec mycontainer /bin/bash
To download files, use
lxc file pull <container name>/<path>/<filename> <target directory>
To download directories, use
lxc file pull --recursive <container name>/<path>/<filename> <target directory>
Download /root/myfile.txt
from mycontainer
to the current directory (.
):
lxc file pull mycontainer/root/myfile.txt .
Download /root/mydirectory
from mycontainer
to the current directory (.
):
lxc file pull -r mycontainer/root/mydirectory .
You know you can launch an Ubuntu LXC container using
lxc launch ubuntu:18.04 myvm
Now you want to launch a Debian VM using
lxc launch debian:jessie myvm
but you only get this error message:
Error: The remote "debian" doesn't exist
The debian images are (by default) available from the images remote, not the debian remote, so you need to use this:
lxc launch images:debian/jessie myvm
In order to determine the size of a LXC container, first run lxc storage list
to list your storage pools:
[email protected]:~$ 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:
[email protected] ~ # cd /var/lib/lxd/storage-pools/default [email protected] /var/lib/lxd/storage-pools/default # cd containers/ [email protected] /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:
[email protected] /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.
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,
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
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
.
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:
[email protected]:~$ lxc list +--------------+---------+-----------------------+-----------------------------------------------+ | NAME | STATE | IPV4 | IPV6 | +--------------+---------+-----------------------+-----------------------------------------------+ | my-container | RUNNING | 10.144.118.232 (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
.
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
.
Note: This step requires that you have working IPv6 connectivity at your local computer. If you are unsure, check at ipv6-test.com
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:
[email protected]:~#
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):
[email protected]:~# 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 [email protected]:4f9:c010:278::8
If you configured everything correctly, you’ll see the shell prompt for your container:
[email protected]:~$
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.
You want to launch a lxc container using lxc launch, but you get this error message instead:
Error: The remote isn't a private LXD server
You are using a command like this:
lxc launch mycontainer ubuntu:18.04
You’ve swapped the container name and image arguments! The correct command looks like this:
lxc launch ubuntu:18.04 mycontainer
You want to launch some lxd container using lxc launch […] but instead you get the following error message:
Failed container creation: No storage pool found. Please create a new storage pool.
You need to initialize lxd before using it:
lxd init
When it asks you about the backend
Name of the storage backend to use (btrfs, dir, lvm) [default=btrfs]:
choosing the default option (btrfs
) means that you’ll have to use a dedicated block device (or a dedicated preallocated file image) for storage. While this is more efficient if you run many containers at a time, I recommend to choose the dir
backend for the default storage pool, because that option will be easiest to configure and will not occupy as much space on your hard drive.
See Storage management in lxd for more more details, including different options for storage pools in case you need a more advanced setup.