First steps with LXD

This tutorial guides you through your first steps with LXD. You’ll begin by installing and initializing LXD. Then you’ll use its CLI or graphical web UI to work with instances, including both containers and virtual machines. You’ll learn how to create and configure instances, create snapshots, and more.

Requirements

  • At least 20 GiB free disk space

  • A Linux distribution installed

Install LXD using snap

This section of the tutorial assumes that you have the snap packaging system available on your system, which is the recommended way to use LXD.

If you use a Linux distribution that does not support snap, see Other Linux installation options and skip to the next section of this tutorial.

LXD snap installation requirements

The snapd daemon that manages snap packages comes pre-installed on many distributions by default. To confirm whether it is available on your system, run:

snap version

If you see an error message indicating that snap is not installed, visit the Snap installation documentation and follow the instructions there to install it.

Once you have confirmed that snap is available on your system, use it to install LXD:

sudo snap install lxd

If the LXD snap is already installed

This tutorial is designed for LXD version 5.21 and higher. If you see an error message that the LXD snap is already installed, run the following command to find the channel the snap is tracking:

snap list lxd

The Tracking column lists the installed snap channel. If the number shown is 5.21 or higher, run the following command to update the snap to the most recent release in its channel:

sudo snap refresh lxd

Otherwise, if the number shown is lower, an older version is installed. In this case, upgrade to the 5.21/stable channel by following the instructions in this guide: Change the snap channel.

Add the current user to the lxd group

Important security notice

Local access to LXD through the Unix socket always grants full access to LXD. This includes the ability to attach file system paths or devices to any instance as well as tweak the security features on any instance.

Therefore, you should only give such access to users who you’d trust with root access to your system.

For more information, see Access to the LXD daemon.

Installing LXD through its snap should automatically create an lxd group on your system. The user you are logged in as must be in this group to interact with LXD.

Check to see if the current user is already in that group:

getent group lxd | grep "$USER"

If this command returns a result, you’re set up correctly and can continue with the next section.

If there is no result, enter the following commands. The first command adds your user to the lxd group. The second command starts a new shell where the group membership takes effect immediately.

sudo usermod -aG lxd "$USER"
newgrp lxd

Initialize LXD

Next, initialize LXD using a minimal setup with default options.

Run:

lxd init --minimal

If this command results in an error, your group membership might not have taken effect. In this case, close and re-open your terminal, then try again.

The lxd init command can be run again later to update the options. Once you have learned more about LXD, you might want to tune the initialization options according to your own preferences, or learn how to use a preseed file to initialize LXD. For now, the minimal configuration is sufficient.

Containers and virtual machines

LXD supports two instance types: containers and virtual machines. LXD containers are faster and more lightweight than virtual machines, but share the host system’s OS kernel. Virtual machines use their own kernel. For more information about these instance types, see Containers and VMs.

Confirm virtualization support

For LXD virtual machines, your host system must be capable of KVM virtualization. To test for this, run:

lxc info | grep -FA2 'instance_types'

If your host system is capable of KVM virtualization, you should see virtual-machine in the list of instance_types:

~$ lxc info | grep -FA2 'instance_types'
instance_types:       - container       - virtual-machine

If virtual-machine fails to appear in the output, this indicates that the host system is not capable of virtualization. In this case, LXD can only be used for containers. You can proceed with this tutorial to learn about using containers, but disregard the steps that refer to virtual machines.

Optional: Enable the LXD UI

While the installation and initialization steps must be performed via the command line interface, a graphical interface (the LXD UI) is available for use after these setup steps. The LXD UI is accessed through your web browser.

If you prefer to use the LXD UI, expand and follow the steps below.

View steps to enable the LXD UI
  1. By default, LXD is exposed through a Unix socket only and is not accessible over HTTPS. To access and manage LXD through a web browser using HTTPS, we must set the core.https_address server configuration option. Run:

lxc config set core.https_address :8443
  1. Access the UI in your browser by entering the server address (for example, https://127.0.0.1:8443 for a local server, or an address like https://192.0.2.10:8443 for a server running on 192.0.2.10).

    If you have not set up a secure TLS server certificate, LXD uses a self-signed certificate, which will cause a security warning in your browser. Use your browser’s mechanism to continue despite the security warning.

    Example for a security warning in Chrome
  2. Set up the certificates that are required for the UI client to authenticate with the LXD server by following the steps presented in the UI.

    You have two options, depending on whether you already have a client certificate selected in your browser:

    • If you don’t have a certificate yet, click Create a new certificate to get instructions for creating a set of certificates, adding the public key to the server’s trust store, and adding the private key to your browser.

      Instructions for setting up certificates for the UI
    • If you already have a client certificate in your browser, select “use an existing certificate” to authorize the certificate with the server and re-use it.

      Instructions for re-using an existing certificate for the UI

    See Remote API authentication for more information.

Most of the following sections include sets of tabs. When the UI tab is available, use the instructions in that tab.

Create instances

LXD uses images to create instances from either local or remote image servers. We will fetch our container images from the remote ubuntu: server, which hosts official Ubuntu images.

Create and start containers

For managing instances, we use the lxc command instead of lxd.

The lxc launch command creates an instance, then immediately starts it. By default, it creates a container instead of a virtual machine. Use this command to launch a container named first, based on the Ubuntu 24.04 LTS image:

lxc launch ubuntu:24.04 first

This downloads and unpacks the image, then uses it to create and start a container. Since this command does not specify a remote server, the default ubuntu: server is used. Once downloaded, this image is cached temporarily in the local image server.

We can also create an instance without starting it, using the lxc init command. Note that this differs from the lxd init command you used to initialize LXD.

Create a container called second but do not start it, using the same image as the first:

lxc init ubuntu:24.04 second

Since the image is now cached locally, this container is created much more quickly than the first.

To confirm that the containers have been created, run:

lxc list

You should see both containers you created in the output, with the first container in a RUNNING state and the second container in a STOPPED state.

Create and start a VM

Next, let’s launch a VM using the Ubuntu 24.04 LTS image.

Although we will use the same image name as we used when creating a container, LXD will download a variant of the image built specifically for VMs. This image is not yet cached, and it is larger than the container VM, so it will take longer to download.

We will use the same lxc launch command, this time to create an instance named ubuntu-vm. To create it as a VM instead of a container, we must add the --vm flag. Run:

lxc launch ubuntu:24.04 ubuntu-vm --vm

Configure, create, and start a desktop VM

A desktop Ubuntu VM is available from the remote images: server. This server is provided by Canonical for unofficial images of not only Ubuntu variants but other Linux distributions, for testing and development purposes.

The limits.memory option defaults to 1 GiB for VMs. For the desktop VM to run smoothly, we must allocate a higher memory limit.

You can configure instance options during creation or afterward. We will configure the desktop VM during creation, using the --config flag to set limits.memory to 4GiB.

Run:

lxc launch images:ubuntu/24.04/desktop ubuntu-desktop --vm --config limits.memory=4GiB

Tip

This is a large image and can take a while to download. If you like, you can open a separate terminal and continue with the next sections of the tutorial while you wait for the download to finish.

Once the VM has launched, confirm that its memory limit is set to 4 GiB:

lxc config get ubuntu-desktop limits.memory

Inspect instances

List all the instances that you created:

lxc list

The output tells you the name, state, IP addresses, instance type, and number of snapshots for each instance.

You can retrieve further information about each instance with lxc info, including its architecture, process ID, usage data, and more. Run:

lxc info first

Start a stopped instance

When you ran lxc list, you saw that the second container’s state is STOPPED, because we used lxc init to create the container instead of lxc launch.

Start the second container:

lxc start second

Run lxc list again to confirm that it is now in a RUNNING state.

See How to create instances and How to manage instances for more information.

Configure instances

Each instance created inherits a default set of configuration options. You can customize these options for each instance. See Instance options for a list of available options.

Earlier, we set the limits.memory option for the ubuntu-desktop VM during its creation. We can also update an instance’s configuration after creation.

As an example, let’s reduce the second container’s resource limits. Follow the instructions below to update its limits.cpu to 1, and its limits.memory to 192MiB.

Run:

lxc config set second limits.cpu=1 limits.memory=192MiB

To confirm that the options have been set, use the lxc config get command for each option:

lxc config get second limits.cpu
lxc config get second limits.memory

You can also use the lxc config show command to view values for all the options. Run:

lxc config show second

Open an interactive shell into instances

Thus far, we have only acted upon instances from outside of them, from the host system. It’s time to see what we can do inside an instance.

First, let’s run a couple of standard Linux commands on your host system. The first command below displays memory information in megabytes, and the second displays the number of available CPUs.

In a terminal, run:

free -m
nproc

Take note of the outputs. We will compare them to the outputs from the same commands run within your instances.

Use lxc shell to open an interactive shell into the first container:

lxc shell first

Notice that your command prompt has changed. You are now logged in as root inside the first instance.

In this shell session, run the same commands as you did on the host:

free -m
nproc

Note that the total memory returned by free -m and the value returned by nproc are identical for the host system and the first container. This is because by default, containers inherit the resources from their host environment.

Next, exit the first container:

exit

Enter an interactive shell into the second container:

lxc shell second

Then in the second container, run the same commands:

free -m
nproc

For the second container, notice that only 192 MiB total memory and 1 CPU is available. These are the options that we configured for this container earlier.

You can try other commands to interact with your instance. For example, enter the following command to display information about the operating system:

cat /etc/*release

Or have some fun:

apt update
apt install fortune -y
/usr/games/fortune

When you’re done, exit the shell:

exit

Your command prompt should return to that of the host system. From here, try out one other way to run commands inside an instance: the lxc exec command. This command is used to execute a single command inside an instance from the host system, without opening a shell. Run:

lxc exec second -- free -m

Notice that the output is the same as if you had run lxc shell second then the free -m command from inside the second container.

See How to run commands in an instance for more information.

Access files

To access files inside an instance from your host system, use the CLI.

As an example, let’s create a file in the first container, pull it out to the host system, modify it, then push it back to the container.

From the host system, use lxc exec to create an empty helloworld file in the first container:

lxc exec first -- touch helloworld.txt

Confirm that the file is empty:

lxc exec first -- cat helloworld.txt

Since the touch command creates an empty file, the cat command should display no output.

Pull this file from the first container to the current directory of your host system:

lxc file pull first/root/helloworld.txt .

Add content to the file:

echo "Hello world" > helloworld.txt

Push the file back to the container:

lxc file push helloworld.txt first/root/helloworld.txt

Now again view the content of the file on the container:

lxc exec first -- cat helloworld.txt

You should see the line that you added:

your-user@host-system:~$ lxc exec first -- cat helloworld.txt
Hello world!

See How to access files in an instance for more information.

Back up and restore instances by creating snapshots

You can back up your instance by creating a snapshot, then use it later to restore the instance to a saved state.

The following command creates a snapshot called “clean” that saves the current state of your instance. Run:

lxc snapshot first clean

Let’s see how many snapshots are available for the first container:

lxc list first

The SNAPSHOTS column shows the number of available snapshots.

Let’s find out more information about the available snapshots for the first container:

lxc info first

At the bottom of the output, a Snapshots table displays details about available snapshots.

If you accidentally do something to break an instance, or wish to revert recent changes to it, you can restore a previous state through a snapshot. To see how this works, let’s deliberately break the first container by deleting the bash command from it:

lxc exec first -- rm /usr/bin/bash

Confirm that you can no longer use the bash command on first:

lxc exec first -- bash

This results in an error because the bash command no longer exists. Luckily, we have a snapshot we can use to restore the container to a previous state. Run:

lxc restore first clean

Confirm that you can now enter the bash shell:

lxc exec first -- bash

Then exit the shell:

exit

When you no longer need a snapshot, you can delete it. Go ahead and delete the clean snapshot:

lxc delete first/clean

Optional: Stop and delete all instances

Congratulations! You have reached the end of this tutorial and acquired a greater understanding of LXD’s usage and capabilities along the way.

If you wish, you can clean up the instances you created.

Take caution when deleting instances

Deleting an instance is irreversible. All snapshots and other information associated with the instance will be lost.

You must first stop an instance before you can delete it:

lxc stop ubuntu-vm
lxc delete ubuntu-vm

You can also use the --force flag to delete an instance without stopping it:

lxc delete ubuntu-desktop --force

In the same way, you can delete the other instances that you created in this tutorial (first and second).

Optional: Hold snap updates

By default, snaps update automatically when a new release is published to their channel. In production environments, we strongly recommend that you disable automatic updates for the LXD snap and apply them manually. This approach allows you to schedule maintenance windows and avoid unplanned downtime.

To hold updates for the LXD snap indefinitely, run on your host machine:

sudo snap refresh --hold lxd

Once updates are on hold, manually update LXD regularly to benefit from security and bug fixes.

If you do not intend to run a production deployment of LXD, you might not need this. To remove the hold and restore automatic updates, run:

sudo snap refresh --unhold lxd

For more information on managing the LXD snap and its updates, see: How to manage the LXD snap.

Next steps

Now that you’ve completed your first steps with LXD, you have a general idea of how LXD works. Next, read up on important concepts in the Explanation section and check out more advanced use cases in our How-to guides. You can also find a wealth of information in the Reference section, including the Main API specification.