Incus is a next-generation system container and virtual machine manager. It manages LXC containers and QEMU virtual machines through a unified command-line interface and REST API. Instances are persistent, full-system environments with their own init system, networking, and storage, distinct from the application containers that Docker and Podman manage.
Incus originates from a community fork of LXD. In 2023, Canonical transferred LXD development exclusively to its own commercial organisation and removed the project from Linux Containers governance. The Linux Containers community forked the codebase as Incus under the LXC Project umbrella. Incus is FOSS, independently governed, and carries no commercial licensing terms. It represents the correct choice for operators who require system container infrastructure without dependency on Canonical's commercial roadmap.
🔗1. Installation
🔗Arch Linux
Incus is available in the AUR. Install with an AUR helper:
yay -S incus
Or build manually:
git clone [https://aur.archlinux.org/incus.git](https://aur.archlinux.org/incus.git)
cd incus
makepkg -si
Enable and start the service:
sudo systemctl enable --now incus
sudo systemctl enable --now incus-user
Add your user to the incus-admin group:
sudo usermod -aG incus-admin $USER
Log out and back in for group membership to take effect.
🔗Alpine Linux
apk add incus incus-client
rc-update add incusd
rc-service incusd start🔗Ubuntu / Debian
Canonical's repositories ship LXD, the proprietary fork. Incus requires the Zabbly repository:
curl -fsSL [https://pkgs.zabbly.com/key.asc](https://pkgs.zabbly.com/key.asc) | sudo gpg --dearmor -o /etc/apt/keyrings/zabbly.gpg
echo "deb [signed-by=/etc/apt/keyrings/zabbly.gpg] [https://pkgs.zabbly.com/incus/stable](https://pkgs.zabbly.com/incus/stable) $(lsb_release -cs) main" \
| sudo tee /etc/apt/sources.list.d/zabbly-incus-stable.list
sudo apt update
sudo apt install incus
sudo adduser $USER incus-admin🔗Verify Installation
incus --version
incus info
🔗2. Initial Configuration
Run the interactive initialisation on first use:
sudo incus admin init
The wizard configures storage pools, networking, clustering, and remote access. For a minimal single-node setup, the following answers produce a functional environment:
| Question | Recommended Answer |
|---|---|
| Clustering | no |
| Existing storage pool | no |
| Storage backend | dir (safe default) or zfs (recommended) |
| Remote access over network | no (unless required) |
| Automatic image updates | yes |
| YAML output of config | optional |
For production use, ZFS provides snapshots, clones, and copy-on-write storage that the dir backend does not. Install ZFS before running incus admin init:
# Arch Linux
sudo pacman -S zfs-utils
sudo modprobe zfs
🔗3. Core Architecture
| Component | Definition |
|---|---|
| Instance | A running container or virtual machine managed by Incus. |
| Image | A compressed file-system used as the base for new instances. |
| Profile | A named set of configuration options applied to instances. Multiple profiles stack. |
| Storage pool | A named storage backend (zfs, btrfs, lvm, dir) hosting instance disks and images. |
| Network | A managed bridge, VLAN, OVN overlay, or physical interface attached to instances. |
| Project | A namespace isolating instances, images, profiles, and storage. Useful for multi-tenant environments. |
| Remote | A reference to another Incus server or a public image registry. |
🔗4. Images
Incus instances launch from images. Images are distributed via remotes. The default remotes point to Linux Containers image servers.
🔗Default Remotes
incus remote list| Default Remote | Content |
|---|---|
images: | Community images (Alpine, Arch, Ubuntu, Rocky, Debian, and many others) |
ubuntu: | Official Ubuntu images |
ubuntu-daily: | Ubuntu daily builds |
🔗Searching for Images
incus image list images:
incus image list images: alpine
incus image list images: arch
incus image list images: | grep -i rocky🔗Image Properties
| Field | Meaning |
|---|---|
ALIAS | Friendly name for the image |
FINGERPRINT | SHA-256 hash identifying the image uniquely |
PUBLIC | Whether the image is publicly accessible |
DESCRIPTION | Distribution, version, and architecture |
TYPE | CONTAINER or VIRTUAL-MACHINE |
SIZE | Compressed image size |
UPLOAD DATE | When the image was cached locally |
🔗Managing Local Images
| Command | Action |
|---|---|
incus image list | List locally cached images |
incus image info {alias} | Show image metadata |
incus image delete {fingerprint} | Remove local image |
incus image export {alias} {path} | Export image to file |
incus image import {path} --alias {name} | Import image from file |
incus image copy images:{alias} local: --alias {name} | Copy remote image to local cache |
incus image refresh | Update cached images |
🔗Publishing Instances as Images
Use incus publish to save a stopped container or virtual machine as a reusable image in your local image list. You can also publish from a snapshot.
| Command | Action |
|---|---|
incus publish {instance} --alias {alias} | Create image from instance, assign alias |
incus publish {instance}/{snapshot} --alias {alias} | Create image from a snapshot |
incus publish {instance} --public --alias {alias} | Publish as a public image (visible to others) |
incus publish {instance} --expiry 30d | Set image to expire after 30 days |
incus publish {instance} --reuse | Replace existing image with same alias |
# Publish a stopped container called "web-backup" as "my-website:1.0"
incus publish web-backup --alias my-website:1.0
# Publish from a snapshot
incus publish web-backup/snap0 --alias my-website:snap0
# List your published images
incus image list
Note: The source instance should be stopped unless you use --force, but forcing may produce inconsistent file-systems.
🔗Managing Image Aliases
Aliases give human-friendly names to image fingerprints. Use them to reference images in incus launch, incus copy, etc. without typing the full hash.
| Command | Action |
|---|---|
incus image alias list | List all aliases on the local server |
incus image alias list images: | List aliases on a remote (e.g., images:) |
incus image alias create {alias} {fingerprint} | Assign an alias to an existing image |
incus image alias delete {alias} | Remove an alias |
incus image alias rename {old} {new} | Rename an existing alias |
# List aliases you have defined locally
incus image alias list
# Create an alias "ubuntu-jammy" for image with fingerprint abc123...
incus image alias create ubuntu-jammy abc123...
# Delete an alias
incus image alias delete my-old-alias
# Rename an alias
incus image alias rename my-website my-website:stable
You can also assign aliases during incus publish, incus copy, or incus image import using the --alias flag:
incus publish my-container --alias my-container:v1
incus image copy local:my-container:v1 images: --alias public-container🔗Building Custom Images
Incus accepts tarballs in its image format. The minimal structure requires a metadata.yaml and a root file-system tarball.
# BUILD A MINIMAL ALPINE IMAGE FOR IMPORT
mkdir -p rootfs
# populate rootfs with a base alpine system, then archive it
tar -czf rootfs.tar.gz -C rootfs .
# create metadata file
cat > metadata.yaml <<EOF
architecture: x86_64
creation_date: $(date +%s)
properties:
description: Custom Alpine minimal
os: Alpine
release: edge
EOF
# bundle metadata and rootfs into an incus image tarball
tar -czf custom-alpine.tar.gz metadata.yaml rootfs.tar.gz
# import image into local cache with alias
incus image import custom-alpine.tar.gz --alias custom-alpine