LXD is a management daemon for system containers and virtual machines on Linux. It runs complete Linux distributions as lightweight containers built on LXC, and since version 4.0 it can also run full virtual machines through QEMU and KVM, all controlled through one REST API, one image catalog and one command-line client.
In Linux virtualization, LXD occupies the space between application containers such as Docker and full hypervisor stacks such as libvirt or Proxmox VE. It is developed by Canonical and distributed mainly as a snap package; the community fork Incus, created in 2023, continues the same design under the Linux Containers project.
How LXD manages containers and virtual machines
LXD runs as a privileged daemon that exposes a REST API, locally over a Unix socket and optionally over HTTPS with client certificates. The command-line tool, confusingly named lxc, is just one client of that API. For containers, LXD uses liblxc to create namespaces, cgroups and security profiles; for virtual machines, it starts QEMU with KVM acceleration and a small agent inside the guest for file transfer and command execution.
Every instance is created from an image, a root file system plus metadata, downloaded from a remote image server and cached locally. Configuration is layered: profiles hold reusable settings such as network interfaces, storage and limits, and each instance can add its own overrides. Projects separate instances, images and profiles for different teams or purposes on the same host.
The following table summarizes the main building blocks of an LXD installation.
| Building block | Purpose | Typical example |
|---|---|---|
| Instance | A container or virtual machine | Ubuntu 24.04 container named web1 |
| Image | Template for new instances | Distribution image from a remote server |
| Profile | Reusable configuration set | Default profile with bridge and root disk |
| Storage pool | Backend for root disks and volumes | ZFS, Btrfs, LVM, Ceph or a directory |
| Network | Connectivity for instances | Managed bridge such as lxdbr0 or OVN |
| Project | Isolated namespace for resources | Separate projects for test and production |
System containers compared with application containers and VMs
LXD’s containers are system containers: they boot a full init system such as systemd, run several services and behave like lightweight virtual machines. Application containers in Docker or Podman usually run one process per container from an immutable image.
| Technology | Unit of isolation | Kernel | Typical use |
|---|---|---|---|
| LXD container | Full Linux system | Shared host kernel | Long-lived servers and dev environments |
| LXD virtual machine | Full machine | Own guest kernel | Other kernels, Windows, stronger isolation |
| LXC alone | Full Linux system | Shared host kernel | Low-level tooling without a daemon API |
| Docker or Podman | Single application | Shared host kernel | Packaging and deploying applications |
| libvirt with KVM | Full machine | Own guest kernel | Traditional VM management |
| systemd-nspawn | Full Linux system | Shared host kernel | Simple containers on systemd hosts |
Because containers share the host kernel, they start in about a second and add very little memory overhead, but they can only run Linux and must be compatible with the host kernel features. LXD virtual machines boot more slowly and use more memory, but provide a separate kernel and a stronger isolation boundary.
Storage, networking and clustering
LXD’s practical strength lies in storage drivers with copy-on-write. On ZFS or Btrfs, creating an instance from a cached image or taking a snapshot is nearly instant and initially consumes almost no extra space. The plain directory driver works everywhere but copies files and lacks efficient snapshots.
| Driver | Snapshots and clones | Best suited to |
|---|---|---|
| ZFS | Fast, space-efficient, with quotas | Most single-host and production setups |
| Btrfs | Fast copy-on-write subvolumes | Hosts already using Btrfs |
| LVM thin | Block-level thin snapshots | Environments standardized on LVM |
| Ceph RBD | Shared, distributed storage | Clusters needing migration between hosts |
| Directory | Full copies, slow | Testing and simple laptops |
For networking, LXD can create a managed bridge with DHCP, DNS and NAT, attach instances directly to physical networks with macvlan or bridged interfaces, or use OVN for software-defined networks across hosts. Several LXD servers can form a cluster with a shared database, distributing instances and allowing migration between members.
Typical workflows and configuration
A typical workflow begins with lxd init, which configures a storage pool, a network and optional clustering. Instances are then created with commands such as lxc launch ubuntu:24.04 web1 for a container or the same command with --vm for a virtual machine. Resource limits are set with keys such as limits.cpu and limits.memory.
- Snapshots before changes:
lxc snapshotandlxc restoremake risky upgrades reversible in seconds. - Cloud-init integration: user data in a profile configures packages, users and SSH keys at first boot.
- Device passthrough: GPUs, USB devices and host directories can be attached to instances.
- Remote management: one client can control several LXD servers added as remotes.
- Export and migration: instances can be exported as backups or copied between hosts.
Security considerations and common pitfalls
LXD containers are unprivileged by default: root inside the container is mapped to an unprivileged user ID range on the host, so a process escaping the container has no host root privileges. Setting security.privileged=true removes this protection and should be reserved for exceptional cases.
- Membership in the lxd group equals root access on the host, because group members can create privileged instances and mount host paths.
- Nested containers such as Docker inside LXD need
security.nesting=trueand careful review. - Kernel-dependent workloads such as custom modules or a different kernel version belong in a virtual machine, not a container.
- Confusing the lxc client with classic LXC tools leads to wrong commands; they are separate interfaces.
- Image server changes after the Incus fork mean some community image sources may not be available to LXD, so image remotes should be checked.
A plain-language summary
LXD lets one Linux computer act like many separate small computers. Each one has its own name, its own network address and its own installed programs, as if it were a different machine.
Most of them are very light, because they share the main computer’s core. When stronger separation is needed, LXD can create a complete virtual machine instead. Both kinds are managed with the same simple commands.
An example from practice
A university computer science department needs isolated Linux servers for about sixty students in a networking course. Each student must have root access, install packages and break things without affecting others, and the department has only two physical servers.
The administrator installs LXD on both servers, forms a small cluster with a ZFS storage pool on each node and creates a project for the course. A profile sets limits of two CPUs and two gigabytes of memory per container, and cloud-init adds each student’s SSH key. Before every lab, a script takes snapshots of all instances.
Containers start in seconds, a broken system is restored from its snapshot almost instantly, and a few students who need a custom kernel get LXD virtual machines from the same tools. The two servers handle the whole course comfortably.