Incus 0.3 has been released

27th of November 2023


The Incus team is pleased to announce the release of Incus 0.3!

This isn't a very busy release as a good chunk of the Incus team has been traveling to the Linux Plumbers Conference in Richmond, VA.

The most exciting new feature is likely the addition of OpenFGA support as when combined with an OpenID connect provider, this now allows for a fully open source identity and authorization stack. This also removes the last blocker for some waiting to migrate to Incus from LXD (with Canonical RBAC).

On top of that, a lot of improvements have gone into the lxd-to-incus migration tool and we've also added support for hot-plug/hot-remove of shared paths in virtual machines!


You can try it for yourself online:


New features and highlights

OpenFGA support for authorization control

OpenFGA is an open source authorization solution which is designed to be very easy to integrate with while still offering extremely good performance.

It's basically an external daemon that you run on your network and which will get asked by Incus whether to allow a specific user to perform a specific action.

You can learn more about OpenFGA here:

On the Incus side of things, OpenFGA is enabled through a new set of server configuration keys:

  • openfga.api.token
  • openfga.api.url

You'll want to set those to point to your OpenFGA instance and then configure an OIDC provider for authentication. Once done, OpenFGA will be queried whenever a user request is received.


This feature was first introduced in LXD.

lxd-to-incus improvements

The lxd-to-incus migration tool has seen a lot of improvements:

  • Support for OpenRC target systems
  • Detection and handling of mounts on the daemon path
  • Support for migrating Ceph storage pools
  • Support for migrating OVN networks
  • Generation of a log file
  • Generation of backups (database, OVN data)

Note that as LXD is late in releasing LXD 5.20, the migration tool only supports up to LXD 5.19 as a source release. Packagers should update that to 5.20 once LXD releases and assuming no last minute changes that would break the migration.

Hot-plug/hot-remove of paths in virtual machines

Incus has had support for hot-plug and hot-remove of disks for a little while.
With those, you see a virtual disk appearing or disappearing inside the VM.

But Incus also supports sharing just a path from the host system or passing in a shared custom volume (filesystem) to the instance.

This is handled through virtio-fs or 9p and up until now, required the VM to be stopped, the device added and then the VM started.

But that's now a thing of the past and Incus now supports hot-plug and hot-remove of those paths through a combination of PCI hotplug in QEMU and communication with the incus-agent in the guest to perform the actual mount as part of the hot-plug process.

Worth noting that the agent will not automatically unmount the filesystem prior to hot-remove. If the filesystem is mounted in the guest, you'll get an error during hot-remove.

Complete changelog

Here is a complete list of all changes in this release:

Full commit list
  • lxd-to-incus: query systemd instead of assuming service file path
  • doc/installing: Re-introduce direct download links
  • doc/howto/import-machines: Re-introduce direct download links
  • cmd/lxd-to-incus: Unmount target paths
  • cmd/lxd-to-incus: Add OpenRC target support
  • doc: Link to migration guide from getting started
  • cmd/network {forward,load-balancer}: fix typo port to ports
  • i18n: Update translation templates
  • lxd-to-incus: Split the targets
  • lxd-to-incus: Handle mountpoint on daemon path
  • [lxd-import] lxd/cluster/config: Adds OpenFGA config keys.
  • [lxd-import] incus-doc: Runs make update-metadata.
  • [lxd-import] lxd/db: Exports StoragePoolVolumeTypeToName function.
  • [lxd-import] lxd: Adds method to daemon to load the OpenFGA authorizer.
  • [lxd-import] lxd: Loads OpenFGA authorizer at startup if configured.
  • [lxd-import] lxd: Load OpenFGA authorizer on config change.
  • [lxd-import] test/lint: Adds linter for openfga model.
  • [lxd-import] test/includes: Adds util for getting certificate fingerprint.
  • [lxd-import] test/includes: Adds utils for running and interacting with an openfga server.
  • [lxd-import] test/suites: Adds OpenFGA test suite.
  • [lxd-import] test/suites: Adds OpenFGA clustering test.
  • [lxd-import] test: Runs OpenFGA tests in main.
  • [lxd-import] workflows: Installs openfga server and CLI in github action.
  • [lxd-import] doc: Adds OpenFGA to wordlist.
  • [lxd-import] lxd/patches: Ensure renaming is only done on cluster leader
  • [lxd-import] test/suites: Fixes wait_no_operations helper.
  • [lxd-import] lxd/auth: Adds OpenFGA model.
  • [lxd-import] Makefile: Adds make target for generating openfga model json.
  • [lxd-import] lxd/auth: Runs make-openfga.
  • Makefile: Pass --yes to npx
  • [lxd-import] lxd/auth: Adds constants for relations.
  • [lxd-import] lxd/auth: Adds Resources type and load option.
  • [lxd-import] gomod: Adds openfga dependency.
  • [lxd-import] lxd/auth: Adds OpenFGA authorization driver.
  • gomod: Use older OpenFGA for Go 1.20
  • [lxd-import] doc: Adds openfga server configuration options.
  • [lxd-import] doc: Adds authorization explanation page.
  • doc/authorization: Update for Incus
  • [lxd-import] doc: Updates authentication page to separate authorization.
  • [lxd-import] doc: Adds authorization page to security related links.
  • tests: Disable OpenFGA tests until we have a test OIDC provider
  • tests: Don't require OpenFGA
  • gomod: Update dependencies
  • client: Allow overriding web browser
  • client: Cleanup OIDC login
  • tests: Add mini-oidc
  • tests/link: Ignore test/mini-oidc
  • tests: Re-enable openfga tests
  • tests: Add oidc helpers
  • tests: Add OpenID Connect tests
  • internal/server/auth: Replace LXD with Incus
  • cmd/incus-agent: Remove LXD reference
  • tests: Update OpenFGA tests for Incus and OIDC
  • [lxd-import] zfs: Support zfs pools containing '/' in the patch
  • [lxd-import] test/deps: switch to ecdsa certificate
  • [lxd-import] github: shorten job names to improve the UI view
  • [lxd-import] test/clustering: remove unneeded shellcheck ignore and update others
  • [lxd-import] config: Ensure config key values are reset to their default
  • [lxd-import] test: Test unsetting config keys
  • [lxd-import] doc/configuration: review openfga.* documentation
  • [lxd-import] doc/openfga: small fixes to documentation
  • doc/installing: Remove LXD reference
  • incusd/auth: Fix handling of trusted certs in CA mode
  • tests: Properly test core.trust_ca_certificates
  • lxd-to-incus: Skip non-symlinks
  • lxd-to-incus: Detect mountpoint on target path
  • lxd-to-incus: Rewrite rbd stamp volume
  • lxd-to-incus: Split out validation code
  • lxd-to-incus: Add advanced option to bypass cluster evacuation
  • incusd/server/task: Code style
  • incusd/server/task: Handle nil group
  • internal/linux: Rename parseMountinfo
  • internal/linux: Add GetMountinfo
  • incusd/storage/drivers/btrfs: Skip nodatacow on compressed pools
  • incusd/storage/drivers/btrfs: Check for datacow mount option
  • [lxd-import] metrics: Fix label merging in metric sets
  • [lxd-import] test: Check instance type in filesystem metrics
  • [lxd-import] test/includes/certificates: add gen_cert_and_key()
  • [lxd-import] test/metrics: use gen_cert_and_key function instead of directly calling openssl
  • [lxd-import] test/remote: use gen_cert_and_key function instead of directly calling openssl
  • [lxd-import] test/tls_restrictions: add some double quotes
  • [lxd-import] test/tls_restrictions: fix some comments
  • [lxd-import] test/tls_restrictions: make sure expected failures get the expected 403
  • [lxd-import] test/tls_restrictions: use gen_cert_and_key function instead of directly calling openssl
  • [lxd-import] test/tls_restrictions: ensure type=metrics certificates cannot access anything besides /1.0/metrics.
  • [lxd-import] lxd/device/proxy: Consider routed NIC IPs for wildcard target check
  • [lxd-import] lxd/network/driver/bridge: Improve comments for accept_ra
  • [lxd-import] config: Restrict user.* keys
  • [lxd-import] test: Validate user.* keys
  • [lxd-import] github: Use Go 1.20 and check for compat with that in go mod tidy
  • [lxd-import] github: Removes whitespace
  • [lxd-import] lxd/incus-doc: Remove noisy log line
  • [lxd-import] test/lint: Removes openfga model linter.
  • [lxd-import] test/basic: always use -- with incus exec
  • [lxd-import] test/basic: test with and without "--" separator
  • [lxd-import] test/clustering: always use -- with incus exec
  • [lxd-import] test/config: always use -- with incus exec
  • [lxd-import] test/dev-incus: always use -- with incus exec
  • [lxd-import] test/image_acl: always use -- with incus exec
  • [lxd-import] test/storage_snapshots: always use -- with incus exec
  • [lxd-import] doc/howto/network_ovn_setup: always use -- with incus exec
  • [lxd-import] doc/howto/instances_troubleshoot: always use -- with lxc exec
  • [lxd-import] lxd/dev-incus: always use -- with incus exec
  • [lxd-import] doc/requirements: allow linking to Go requirements
  • [lxd-import] doc/installing: link to Go requirements and update Ubuntu instructions
  • [lxd-import] doc/howto/benchmark_performance: link to Go requirements
  • [lxd-import] doc/howto/migrate_from_lxc: link to Go requirements
  • [lxd-import] doc/requirements: Go 1.20 is now the minimum version
  • [lxd-import] shared/cert: Update code comments about CRL
  • [lxd-import] lxd/util/http: Check if the CRL was signed by the CA before using it
  • [lxd-import] lxc/delete: Include instance name in error message
  • [lxd-import] Update translations
  • incus: Fix first use missing on init/create
  • incus: Fix first use message on admin init
  • incus: Don't show first use on admin commands
  • incusd/device: The MTU can always be controlled
  • [lxd-import] lxc: Use volume copy when moving to target project
  • [lxd-import] shared/network: Only skip TLS verification if no remote certificate is available
  • [lxd-import] lxd/daemon_images: fix typo
  • [lxd-import] lxd: Enforce users to be authenticated before running the access handler.
  • [lxd-import] lxd/instance/exec: Only use keepalives on TCP sockets
  • [lxd-import] test: Restructure local volume handling
  • [lxd-import] test: Add storage volume move between projects
  • doc: Update for trust add-certificate
  • lxd-to-incus: Add support for OVN database mangling
  • doc: incus -> incusd in build instructions.
  • lxd-to-incus: Add target name
  • lxd-to-incus: Fix env variable name
  • lxd-to-incus: Fix bad exit code
  • lxd-to-incus: Add debug log
  • lxd-to-incus: Backup the database
  • lxd-to-incus: Backup the OVN database
  • lxd-to-incus: Detect problematic btrfs setup
  • tests: Workaround shellcheck
  • gomod: Update dependencies
  • lxd-to-incus: Allow evacuated servers when using CLUSTER_NO_STOP
  • lxd-to-incus: Fix ceph username
  • lxd-to-incus: Add missing line breaks in log
  • lxd-to-incus: Don't fail migration on a failed command
  • lxd-to-incus: Fix format string
  • lxd-to-incus: Split OVS commands from OVN
  • lxd-to-incus: Fix typo in OVS migration
  • doc: replace lxc with incus in cmdStorageVolumeSnapshotShow example
  • [lxd-import] client: Use io.Writer for Stdout/Stderr in InstanceExecArgs
  • [lxd-import] btrfs: Add function to check subvolumes in a given path
  • [lxd-import] btrfs: Use hasSubvolumes when creating a new pool
  • [lxd-import] test: Btrfs pool with a subvolume as its source
  • [lxd-import] client: Use io.Reader for Stdin in InstanceExecArgs
  • [lxd-import] Makefile: remove toolchain directive from go.mod for backward compat
  • Makefile: Use GO env variable everywhere
  • [lxd-import] github: remove Go tip tarball after extraction
  • [lxd-import] config: Fix acme.ca_url short description
  • [lxd-import] Update metadata
  • [lxd-import] lxd/instance/drivers/driver_qemu: factor out config volume mounting from setupNvram
  • [lxd-import] shared/instance: correct volatile.apply_nvram type
  • [lxd-import] client/lxd/instances: Close websocket as soon as channel mirror finishes in ExecInstance
  • [lxd-import] lxc/exec: No need to use io.ReadCloser anymore
  • [lxd-import] shared/ws/mirror: No need for defer in MirrorWrite and MirrorRead
  • [lxd-import] Revert "lxd/instance/exec: Only use keepalives on TCP sockets"
  • [lxd-import] client/lxd/instances: Consume ping messages from server for exec control and stdin channels
  • incusd/instance/qemu: Send device notifications
  • incus-agent: Properly forward device events
  • incusd/instance/qemu/qmp: Add CharDevice commands
  • incusd/device/disk: Allow virtiofs hotplug/hotremove
  • incusd/device/disk: Don't spawn 9p proxy for hotplug
  • incusd/instance/qemu: Add support for hotplug/hotremove of virtiofs
  • incus-agent: Add support for mounting hot-plugged paths
  • gomod: Update dependencies
  • doc: Add markdown table to containers vs vms
  • doc: Minor changes to containers vs vms
  • incusd/instances: Properly detect unfiltered
  • incusd/images: Properly detect unfiltered
  • internal/filter: Support string slices
  • incusd/storage_volumes: Allow filtering based on UsedBy


The Incus documentation can be found at:


There are no official Incus packages as Incus upstream only releases regular release tarballs. Below are some available options to get Incus up and running.

Zabbly packages for Debian and Ubuntu

Zabbly provides both daily and stable builds of Incus to Debian and Ubuntu users:

Homebrew package for the Incus client

The client tool is available through HomeBrew for both Linux and MacOS.

Chocolatey package for the Incus client

The client tool will soon be available through Chocolatey for Windows users.

Until then, binaries can be found here:


At this early stage, each Incus release will only be supported up until the next release comes out. This will change in a few months as we are planning an LTS release to coincide with the LTS releases of LXC and LXCFS.

Community support is provided at:
Bugs can be reported at:

Incus 0.2 has been released

28th of October 2023


The Incus team is pleased to announce the release of Incus 0.2!

This version incorporates most changes that went into LXD 5.19 as well as introduce a few additional features and improvements.

Screenshot from 2023-10-28 19-01-17|690x459

You can try it for yourself online:


New features and highlights

NVME storage support in virtual machines

A new io.bus configuration key was added to disk type devices of virtual-machines.

This defaults to virtio-scsi but can also now be set to nvme in order to have the disk appear as an NVME SSD inside the virtual machine.

Cluster support for migration from LXD

The lxd-to-incus migration tool now supports clustered environments.
Additionally, it's also been updated to support LXD 5.19 as a source release.

This means that anyone on LXD version 4.0 and higher (up until 5.19) can now easily move over to Incus by installing Incus and running lxd-to-incus!

New image requirement for unprivileged containers

When adding support for NixOS as a container image, it came out that this particular image cannot currently work inside of a privileged container.

Rather than just let it silently fail for those users, a new image requirement was added.
requirements.privileged can be set to false in order to prevent the image from being used with a privileged container.

stgraber@dakara:~$ incus launch images:nixos nixos-priv -c security.privileged=true
Creating nixos-priv
Starting nixos-priv
Error: The image used by this instance is incompatible with privileged containers. Please unset security.privileged on the instance
Try `incus info --show-log local:nixos-priv` for more info

Server-side custom volume copy

Incus now supports server-side copies of custom volumes. This significantly speeds up copies of custom volumes by eliminating the need for the client to act as a relay.

The command line tool automatically detects support for this and uses it when available.

This feature was first introduced in LXD.

Static binaries now available for 64-bit Arm

All static binaries provided as part of our releases and tests are now provided for both Intel 64-bit as well as Arm 64-bit.

Complete changelog

Here is a complete list of all changes in this release:

Full commit list
  • doc: change Incus_DIR to upper case INCUS_DIR
  • README: Fix link to getting started
  • doc: Add start-after to include from
  • Makefile: Build doc in production mode
  • doc: Fix logic to find incus
  • lxd-to-incus: Port to current Incus
  • gomod: Update dependencies
  • doc: Add "Then run the following command:"
  • incus-user: Fix bad path
  • doc: Remove direct from reference/network_external/
  • doc: Remove "Configure a network section" in howto/network_create
  • doc: Align output of IPAM table
  • doc: Make Incus_INSECURE_TLS uppercase
  • doc: Remove all mentions of trust passwords
  • doc: Update Grafana screenshots
  • build(deps): bump redhat-plumbers-in-action/differential-shellcheck
  • github: Build static binaries for x86_64 and aarch64
  • cmd/incus/admin_cluster: Fix re-exec logic
  • [lxd-import] client: Remove project from format string API path.
  • [lxd-import] client: Adds a flag to operations to skip event listener setup.
  • [lxd-import] client: Pass useEventListener flag into queryOperation.
  • [lxd-import] client/certificates: Update calls to queryOperation.
  • [lxd-import] client/cluster: Update calls to queryOperation.
  • [lxd-import] client/images: Update calls to queryOperation.
  • [lxd-import] client/instances: Update calls to queryOperation.
  • [lxd-import] client/projects: Update calls to queryOperation.
  • [lxd-import] client/storage_volumes: Update calls to queryOperation.
  • cmd/incusd: Properly forward rebuild requests
  • tests: Fix storage volume recovery test
  • tests: Fix syslog test
  • doc: Remove UI tabs
  • tests: Add incus-user test
  • gomod: Update dependencies
  • github: Prevent interactions with image server
  • internal/server/seccomp: Fix clang build
  • [lxd-import] scripts/bash: add missing incus config trust subcommands
  • [lxd-import] lxd/storage: Prevent duplicate usedBy profile device entries
  • [lxd-import] doc/projects: fix typo "profiles" instead of "projects"
  • instance/qemu: Tweak systemd/udev units of incus-agent
  • github: Re-try golang-tip for up to 10min
  • [lxd-import] doc/projects: point out that new projects don't have a profile
  • [lxd-import] lxd-agent: Adds an operation wait endpoint.
  • [lxd-import] lxd: Move certificate type to certificate package.
  • [lxd-import] lxd/certificate: Adds a thread-safe certificate cache.
  • [lxd-import] lxd: Use certificate.Cache in the daemon.
  • [lxd-import] lxd/resources: if SCSI_IDENT_SERIAL is available, use it as serial nr before ID_SERIAL_SHORT
  • [lxd-import] doc/doc-lint: fix the linting script for new version of mdl
  • internal/server/storage: Remove leftover LXD references
  • internal/server/config: Remove leftover LXD references
  • doc: Remove mention of containers/virtual-machines API
  • doc: Remove mention of LXD versions
  • lxd-to-incus: Report source name
  • lxd-to-incus: Add manual source
  • shared/osarch: Add loongarch64
  • [lxd-import] tests: Fix storage volume recovery test
  • [lxd-import] github: improve ceph test reliability
  • [lxd-import] github: reorder microceph setup steps to remove a sleep
  • [lxd-import] github: tune ext4 for speed and reclaim some space
  • [lxd-import] shared/version: Adds API extension.
  • [lxd-import] client: Check for operation wait extension and conditionally revert to events API.
  • [lxd-import] lxd/locking/lock: Return error if context got cancelled
  • [lxd-import] lxd/api: Handle error from lock
  • [lxd-import] lxd/daemon: Handle error from lock
  • [lxd-import] lxd/images: Handle error from lock
  • [lxd-import] lxd/instance: Handle error from lock
  • [lxd-import] lxd/instance/drivers: Handle error from lock
  • [lxd-import] lxd/storage/drivers: Handle error from lock
  • [lxd-import] lxd/network/driver/ovn: Handle error from lock
  • [lxd-import] lxd/storage/backend: Handle error from lock
  • [lxd-import] lxd/storage/s3/miniod: Handle error from lock
  • [lxd-import] shared/ws/mirror: Log as soon as io.Copy has finished in MirrorRead
  • [lxd-import] shared/ws/mirror: Removes unused context argument from Mirror*()
  • [lxd-import] client: ws.Mirror*() usage
  • [lxd-import] lxc-to-lxd: ws.Mirror*() usage
  • [lxd-import] lxd-agent: ws.Mirror*() usage
  • [lxd-import] lxd-migrate: ws.Mirror*() usage
  • [lxd-import] lxd: ws.Mirror*() usage
  • [lxd-import] shared/util/linux: Partially reverts 54e3da881103c42d6b4813e8930bde1b10edb236 and reintroduces GetPollRevents
  • [lxd-import] shared/util/linux: Adds execWrapper for use with ws.MirrorRead() and ws.Mirror()
  • [lxd-import] lxd/instance/exec: Use context.WithCancel rather than cancel
  • [lxd-import] lxd/instance/exec: Use shared.NewExecWrapper
  • [lxd-import] lxd-agent/exec: Use shared.NewExecWrapper and bring into line with container exec
  • [lxd-import] patches: Fix patch regarding unsetting zfs block settings
  • gomod: Update dependencies
  • cmd/lxd-to-incus: Handle backups/images volumes
  • Makefile: Generate vendor tree for lxd-to-incus
  • Makefile: Use tar.xz for smaller tarballs
  • gitignore: Update for .tar.xz
  • doc: Add packaging instructions
  • [lxd-import] lxd/storage/backend: Allow generating backup configuration w/o volume snapshots
  • [lxd-import] lxd/instance/drivers: Update func call
  • [lxd-import] client: Unset response header timeout when waiting for operations.
  • [lxd-import] test/suites/backup: Test instance export with instance-only flag
  • [lxd-import] test/main: Add invocation of instance export test
  • [lxd-import] github: use ppa:ubuntu-lxc/daily instead of ppa:ubuntu-lxc/lxc-git-master
  • [lxd-import] lxd-agent: Fixes vsock listener restart on boot due to vsock module not being fully initialised
  • [lxd-import] lxd/vsock/vsock: Removes unused ContextID function
  • [lxd-import] lxd-agent: Fixes intermittent exec EOF closure when vsock listener is restarted just after boot
  • [lxd-import] shared/api/url: Fix double path encoding issue
  • [lxd-import] lxc: avoid returning early when multiple ephemeral instances are to be deleted
  • [lxd-import] test: test multiple ephemeral delete
  • [lxd-import] lxc/storage/volume: Move volume if a destination cluster member name is set
  • [lxd-import] test: Rename storage volumes in a cluster
  • [lxd-import] lxd/network/driver/bridge: Don't consider an IP parse failure of a proxy listen address an error
  • [lxd-import] github: Run push actions on main and release branches only
  • [lxd-import] lxd/daemon: Initialise server name and global config before patches
  • [lxd-import] lxd/patches: Only update volumes that need updating in patchStorageZfsUnsetInvalidBlockSettingsV2
  • [lxd-import] lxd/patches: Only update volumes that need updating in patchStorageZfsUnsetInvalidBlockSettings
  • doc/images: Fix type of requirements.secureboot
  • api: Add image_restriction_privileged
  • doc/images: Introduce requirements.privileged
  • doc/images: Sort image requirements
  • internal/server/instance/lxc: Add support for image.requirements.privileged
  • shared/cliconfig: Nicer error on missing socket
  • instance/lxc: Fix swap limit handling
  • [lxd-import] doc: add a note about go-incus build issue when INC_DEVEL=1
  • [lxd-import] lxd/firewall: Fix nftables ACL template
  • [lxd-import] lxd/api: replace numeric literal 301 by http.StatusMovedPermanently
  • [lxd-import] lxd/auth/oidc: replace numeric literal 301 by http.StatusMovedPermanently
  • [lxd-import] lxd/dev_incus: replace numeric literal 401 by http.StatusUnauthorized
  • [lxd-import] lxd: Update certificate cache again after cluster join.
  • [lxd-import] lxd/patches: Add cluster check for patches fixing volumes
  • [lxd-import] lxd/storage_pools: Fix etag when retrieving storage pool
  • [lxd-import] Makefile: add staticcheck target
  • [lxd-import] Add staticcheck config
  • [lxd-import] golangci: sort linters list
  • [lxd-import] doc/instances: clarify initial volume configuration
  • [lxd-import] lxd/instance/drivers: Check running status with InitPID for cgroups
  • [lxd-import] lxd/instance/drivers: Extend error message in deviceAddCgroupRules
  • [lxd-import] doc/networking/firewall: add more restrictive UFW rules
  • [lxd-import] loki: enable TLS verification if a CA cert is provided
  • [lxd-import] test/container_devices_unix: Make unix device checks less flaky
  • [lxd-import] api: Add cluster_internal_custom_volume_copy
  • [lxd-import] shared/api: Add Location to StorageVolumeSource
  • [lxd-import] shared/api: Add Source to StorageVolumePost
  • [lxd-import] lxd/db: Add function to update storage volume node
  • [lxd-import] lxd: Handle copying storage volumes with a single API call
  • [lxd-import] lxd: Support single API custom volume rename
  • [lxd-import] client: Set Source.Location if supported
  • [lxd-import] doc: Update API
  • [lxd-import] lxd/instance/exec: Use linux.NewExecWrapper for MirrorRead in non-interactive exec
  • [lxd-import] shared/ws/mirror: Updare Mirror*() to return error channels
  • [lxd-import] client: shared.Mirror*() usage
  • [lxd-import] lxd/instance/exec: Log error from ws.Mirror*() in execWs
  • [lxd-import] lxc/copy: Require destination name to be provided
  • [lxd-import] po: Update translations
  • [lxd-import] shared/api: Add authentication method constants.
  • gitignore: Remove macaroon-identity
  • [lxd-import] client: Replaces 'oidc' string with constant.
  • [lxd-import] lxc/config: Replaces 'oidc' string with constant.
  • [lxd-import] lxc: Replaces 'oidc' string with constant.
  • [lxd-import] lxd: Replaces 'oidc' string with constant.
  • [lxd-import] client: Replaces 'tls' string with constant.
  • [lxd-import] lxc/config: Replaces 'tls' string with constant.
  • [lxd-import] lxc: Replaces 'tls' string with constant.
  • [lxd-import] lxd: Replaces 'tls' string with constant.
  • [lxd-import] lxd-agent: Replaces 'tls' string with constant.
  • [lxd-import] lxd-migrate: Replaces 'tls' string with constant.
  • [lxd-import] shared/network: remove unused args of GetTLSConfig()
  • [lxd-import] lxd/migration_connection: drop unused args for localtls.GetTLSConfig()
  • [lxd-import] lxd/storage_volumes: drop unused args for localtls.GetTLSConfig()
  • [lxd-import] lxd/util/http: drop unused args for localtls.GetTLSConfig()
  • [lxd-import] shared/cert: drop unused args for GetTLSConfig()
  • [lxd-import] lxd/instance/driver/qemu: replace sha1 by sha256 in blockNodeName()
  • [lxd-import] shared/api: Adds constant for default project name.
  • [lxd-import] lxd/cluster: Updates project.Default to api.ProjectDefaultName.
  • [lxd-import] lxd/db: Updates project.Default to api.ProjectDefaultName.
  • [lxd-import] lxd/device: Updates project.Default to api.ProjectDefaultName.
  • [lxd-import] lxd/instance/drivers: Updates project.Default to api.ProjectDefaultName.
  • [lxd-import] lxd/instance: Updates project.Default to api.ProjectDefaultName.
  • [lxd-import] lxd/network/acl: Updates project.Default to api.ProjectDefaultName.
  • [lxd-import] lxd/network: Updates project.Default to api.ProjectDefaultName.
  • [lxd-import] lxd/project: Updates project.Default to api.ProjectDefaultName.
  • [lxd-import] lxd/storage: Updates project.Default to api.ProjectDefaultName.
  • [lxd-import] lxd: Updates project.Default to api.ProjectDefaultName.
  • client: Use api.ProjectDefaultName
  • cmd/incus: Use api.ProjectDefaultName
  • cmd/incus-benchmark: Use api.ProjectDefaultName
  • cmd/incus-migrate: Use api.ProjectDefaultName
  • [lxd-import] lxd/project: Removes project.Default.
  • [lxd-import] lxd/request: Exports query parameter methods and moves to lxd/request.
  • [lxd-import] lxd: Updates calls to projectParam and queryParam.
  • [lxd-import] shared/util/linux: Update NewExecWrapper.Read to be time based when waiting for output from a process after it has exited
  • [lxd-import] lxd/auth: Adds entitlement, object, and permission types and constants.
  • [lxd-import] lxd/auth: Adds functions for creating auth objects.
  • [lxd-import] lxd/auth: Adds tests for authorization objects.
  • [lxd-import] lxd/auth: Extends the authorizer interface.
  • [lxd-import] lxd/auth: Update common authorizer for Authorizer interface extension.
  • [lxd-import] lxd/auth: Implement Authorizer for TLS driver.
  • [lxd-import] lxd: Do not set user access data in request context.
  • [lxd-import] lxd: Update calls to auth package.
  • [lxd-import] lxd: Only allow missing access handler when AllowUntrusted is true.
  • [lxd-import] lxd: Update allowPermission function.
  • [lxd-import] lxd: Updates allowAuthenticated function.
  • [lxd-import] lxd/db/operationtype: Updates Permission method.
  • [lxd-import] lxd/operations: Updates operation permissions.
  • [lxd-import] lxd/db/cluster: Renames constants.go file.
  • [lxd-import] lxd/db/cluster: Add storage bucket entity type.
  • [lxd-import] lxd/db/cluster: Adds URLToEntityType function.
  • [lxd-import] lxd/db/cluster: Adds a unit test for the URLToEntityType function.
  • [lxd-import] lxd/project: Updates permission handling for projects.
  • [lxd-import] lxd/project: Updates permissions tests.
  • [lxd-import] lxd/events: Pass an auth.PermissionChecker into the event listener.
  • [lxd-import] lxd-agent: Update call to AddListener for the Incus Agent.
  • [lxd-import] lxd: Update authorization for the /1.0 endpoint.
  • [lxd-import] lxd: Update authorization for cluster endpoints.
  • [lxd-import] lxd: Update authorization for internal endpoints.
  • [lxd-import] lxd/metrics: Adds method to filter metrics with a permission checker.
  • [lxd-import] lxd: Update authorization for metrics.
  • [lxd-import] lxd: Update authorization for projects API.
  • [lxd-import] lxd: Updates authorization for certificates API.
  • [lxd-import] lxd: Updates authorization for events API.
  • [lxd-import] lxd: Updates authorization for image API.
  • [lxd-import] lxd: Add/remove images and image aliases from authorizer.
  • [lxd-import] lxd: Update authorization for instances.
  • [lxd-import] lxd/instance/drivers: Add/remove/rename instances in authorizer.
  • [lxd-import] lxd: Update authorization for network ACL API.
  • [lxd-import] lxd: Update network ACLs in the authorizer.
  • [lxd-import] lxd: Update authorization for network allocations.
  • [lxd-import] lxd: Update authorization for network forwards.
  • [lxd-import] lxd: Update authorization for network load balancers.
  • [lxd-import] lxd: Update authorization for network peers.
  • [lxd-import] lxd: Update authorization for network zones.
  • [lxd-import] lxd: Update network zones in the authorizer.
  • [lxd-import] lxd: Update authorization for the networks API.
  • [lxd-import] lxd: Update networks in the authorizer.
  • [lxd-import] lxd: Update authorization for operations.
  • [lxd-import] lxd: Update authorization for profiles.
  • [lxd-import] lxd: Update profiles in authorizer.
  • [lxd-import] lxd: Update authorization for resources.
  • [lxd-import] lxd: Update authorization for storage buckets.
  • [lxd-import] lxd: Update storage buckets in authorizer.
  • [lxd-import] lxd: Update authorization for storage pools.
  • [lxd-import] lxd: Update storage pools in authorizer.
  • [lxd-import] lxd: Update authorization for storage volumes.
  • [lxd-import] lxd/storage: Add/Remove/Rename storage volumes in authorizer.
  • [lxd-import] lxd: Update authorization for warnings.
  • [lxd-import] lxd/cluster/config: Add missing bool default values
  • cmd/lxd-to-incus: Bump max version to 5.19
  • cmd/lxd-to-incus: Remove line break
  • cmd/lxd-to-incus: Validate storage tools are present
  • cmd/lxd-to-incus: Fix SQL update for multiple pools
  • cmd/lxd-to-incus: Initial cluster handling
  • api: disk_io_bus
  • doc: Add io.bus to disk devices
  • doc: Reformat disk option table
  • incusd/device/disk: Add io.bus
  • incusd/instance/qemu: Add NVME disk support
  • [lxd-import] gomod: Remove dependency
  • [lxd-import] lxd/storage/drivers: Generate and parse UUID using
  • [lxd-import] lxd/instance/drivers: Generate and parse UUID using
  • [lxd-import] lxd/instance: Generate UUID using
  • [lxd-import] lxc-to-lxd: Generate UUID using
  • [lxd-import] lxd-migrate: Generate UUID using
  • [lxd-import] lxd/apparmor: Generate UUID using
  • [lxd-import] lxd/bgp: Generate UUID using
  • [lxd-import] lxd/db: Generate UUID using
  • [lxd-import] lxd/device: Generate UUID using
  • [lxd-import] lxd/events: Generate UUID using
  • [lxd-import] lxd/firewall/drivers: Generate UUID using
  • [lxd-import] lxd/operations: Generate UUID using
  • [lxd-import] lxd/rsync: Generate UUID using
  • [lxd-import] lxd/storage/s3/miniod: Generate UUID using
  • [lxd-import] shared/validate: Parse UUID using
  • [lxd-import] lxd/auth/oidc: Generate UUID using
  • [lxd-import] lxd: Handler error from oidc.NewVerifier
  • incusd/apparmor: Generate UUID using
  • gomod: Update dependencies
  • incusd/seccomp: Switch to path/filepath
  • incusd/seccomp: Pass correct path and fstype to IdmappedStorage
  • incusd/forksyscall: Fix idmapped mount code path
  • lxd-to-incus: Fix bad check
  • doc: Add migration doc
  • README: Update for lxd-to-incus
  • incusd/devices/disk: Always apply the disk options
  • Release Incus 0.2


The Incus documentation can be found at:


There are no official Incus packages as Incus upstream only releases regular release tarballs. Below are some available options to get Incus up and running.

Zabbly packages for Debian and Ubuntu

Zabbly provides both daily and stable builds of Incus to Debian and Ubuntu users:

Homebrew package for the Incus client

The client tool is available through HomeBrew for both Linux and MacOS.

Chocolatey package for the Incus client

The client tool will soon be available through Chocolatey for Windows users.

Until then, binaries can be found here:


At this early stage, each Incus release will only be supported up until the next release comes out. This will change in a few months as we are planning an LTS release to coincide with the LTS releases of LXC and LXCFS.

Community support is provided at:
Bugs can be reported at:

Incus 0.1 has been released

7th of October 2023


The Linux Containers team is very excited to announce the initial release of Incus!

Incus is a community fork of Canonical LXD, created by @cyphar and now part of the Linux Containers project.

This initial release is roughly equivalent to LXD 5.18 but with a number of breaking changes on top of the obvious rename.

You can try it for yourself online:



With this initial release of Incus, we took the opportunity to remove a lot of unused or problematic features from LXD. Most of those changes are things we would have liked to do in LXD but couldn't due to having strong guarantees around backward compatibility.

Incus will be similarly strict with backward compatibility in the future, but as this is the first release of the fork, it was our one big opportunity to change things.

That said, the API and CLI are still extremely close to what LXD has, making it trivial if not completely seamless to port from LXD to Incus.


Removal of /1.0/containers and /1.0/virtual-machines

LXD started as a container-only project and therefore its REST API used /1.0/containers.

When virtual-machines were then introduced, a new /1.0/instances endpoint took over for all operations across both containers and virtual-machines, but /1.0/containers was kept around for legacy clients. On top of that, a convenience /1.0/virtual-machines endpoint was also added, though never used.

With Incus, those two legacy endpoints are now removed and the only supported way to interact with instances is through /1.0/instances.

Replacement of /dev/lxd with /dev/incus

As part of the renaming of everything from LXD to Incus, the guest API was also renamed from /dev/lxd to /dev/incus.

Convenience symlinks are currently provided so existing workloads will keep working after a migration from LXD.

Type change for the server configuration

The LXD server configuration has always been a bit oddly typed as map[string]any rather than our usual map[string]string. The reason for that one inconsistency was because of core.trust_password, the legacy authentication method used by LXD in the early days.

That's because LXD never stored the password in clear text but instead would hash it and store the hash instead. This made it impossible to return the full configuration to the user. Instead when a password would be set, a true boolean would be returned rather than a string.

Now as mentioned, core.trust_password is a legacy way to handle authentication and should be replaced by either token based authentication, TLS certificate trust or external authentication.

Incus has removed support for core.trust_password completely (see below) and so all server config keys can now fit in a standard map[string]string.

Removal of legacy Container functions from the Go API

Following the above change of removing /1.0/containers and /1.0/virtual-machines, the matching functions in the Go client package are also all gone now.

Instead the Instance equivalents of those Container functions should be used.
(e.g. CreateInstance instead of CreateContainer)


Introduction of incus snapshot sub-command

A long term annoyance and inconsistency in the LXD CLI has been around snapshot management. While most other operations get their own sub-command (file, config, ...), snapshots were kept at the top-level with snapshot and restore.

This was then forcing us to handle things like renaming or deleting snapshots through the lxc rename and lxc delete functions. Instead having an lxc snapshot sub-command with lxc snapshot create would have made a lot more sense but couldn't be done without breaking all scripts using lxc snapshot.

Now is time to fix this, so incus snapshot is now a sub-command, featuring:

  • incus snapshot create
  • incus snapshot delete
  • incus snapshot list
  • incus snapshot rename
  • incus snapshot restore

Handling of incus config trust add and incus cluster add

With Incus doing away with password based authentication and focusing a lot more on tokens, it was important to make the experience of issuing tokens be easy and consistent.

As a result, both incus config trust add and incus cluster add now simply take a name as argument and return a valid token.

The certificate handling aspect of incus config trust add has now been moved to incus config trust add-certificate instead.

Introduction of incus admin sub-command

Another long time annoyance in the LXD world was the fact that both lxc and lxd had to be used to set up a server. With incus, the incusd binary can be safely hidden away as nobody should ever have to directly interact with it.

Instead, we now have the incus admin sub-command:

  • incus admin cluster
  • incus admin init
  • incus admin recover
  • incus admin shutdown
  • incus admin waitready


Transition to Cowsql

Shortly after @cyphar forked LXD as Incus, @freeekanayaka, the original author of Dqlite, also decided to fork Dqlite as Cowsql. Given that @freeekanayaka is also a maintainer on Incus, it made sense to port incus over to Cowsql.

Similarly to Incus itself, Cowsql is a community fork of Canonical Dqlite, largely compatible with Dqlite, allowing Incus to easily import existing data during the migration stage.

Focus on Cowsql so far has been on dramatically improving performance testing and making a number of changes across the Raft and Cowsql layers to make it as performant as possible for Incus' usage pattern.

Minimum Go version

For those building Incus from source, the minimum Go version required is now Go 1.20.
In general, we'll attempt to keep supporting building on the current and previous Go version.

Feature removal

A number of LXD features have been removed from Incus.
Those primarily focus around features that were added because of ecosystem reasons and/or depend on now deprecated or poorly maintained software.

Removal of Ubuntu Fan bridges

The Ubuntu Fan bridges depend on custom Ubuntu-only kernel patches and user-space changes to iproute2. While this feature is still maintained in the Ubuntu kernel, it can't be found in the mainline kernel nor in any other distro's kernel.

While convenient in some environments, Ubuntu Fan bridges are dwarfed by what's possible through Incus' integration with OVN.

The following network config keys have therefore been removed:

  • bridge.mode
  • fan.overlay_subnet
  • fan.underlay_subnet
  • fan.type

Removal of Ubuntu shiftfs

Another feature that's unique to the Ubuntu kernel, shiftfs was an initial attempt at flexible uid/gid shifting at the kernel level.

While LXD supported shiftfs for years, it was never enabled by default due to a variety of kernel issues. Instead a cleaner in-kernel solution to this problem was developed, VFS idmap shifting. That's now available in recent Linux kernels and automatically used by Incus when present.

Removal of Canonical Candid authentication

Back in the days, Canonical developed its own authentication system based on the use of Macaroons. The central authentication server for this was Candid.

LXD got Candid support, allowing it to authenticate users through a variety of providers through it.

These days, Candid is mostly unmaintained and the focus has been on moving towards industry standards, namely Open ID Connect.

Therefore, the following server configuration keys have been removed:

  • candid.api.key
  • candid.api.url
  • candid.expiry

Incus already has OpenID Connect support for external authentication and there are widely available OIDC servers that match and often exceed what Candid supported.

Removal of Canonical RBAC authorization

Canonical RBAC was a proprietary Role Based Access Control solution built on top of Macaroons and Candid.

It was only ever supported by MAAS and LXD and has seen extremely little adoption, mostly due to it being proprietary and generally difficult to get access to.

It's mostly unmaintained and the focus these days is to transition to something more industry standard, namely OpenFGA.

Therefore the following server configuration keys have been removed:

  • rbac.agent.url
  • rbac.agent.username
  • rbac.agent.private_key
  • rbac.agent.public_key
  • rbac.api.expiry
  • rbac.api.key
  • rbac.api.url
  • rbac.expiry

Incus currently doesn't have OpenFGA support, so any existing user of Canonical RBAC should stick with LXD until such time as an OIDC + OpenFGA alternative is available.

Removal of Canonical MAAS integration

LXD supports integrating with the MAAS API to use MAAS as some kind of IPAM (IP Address Management) solution.

This allows mapping specific LXD networks to MAAS subnet and then having MAAS create records for each instance on that network, assigning it a static address and DNS record.

Unfortunately, this integration has seen very little adoption and MAAS itself has a number of constraints that makes this integration problematic:

  • MAC addresses in MAAS are globally unique whereas in LXD they have to be unique among running instances on the same network. This different makes some instance copy operations impossible.
  • Instance names are expected to be globally unique in MAAS, even if attached to completely different DNS zones. This effectively makes it impossible to use LXD projects as instances can now easily conflict.

Between those issues and the lack of adoption of this feature, we've made the decision to remove MAAS support from Incus, the following configuration keys have therefore been removed:

  • maas.api.key
  • maas.api.url
  • maas.subnet.ipv4
  • maas.subnet.ipv6

Removal of the concept of trust password

Back in the early LXD days, the only way to connect to a remote server was to use a trust password, basically a fixed secret that would then allow a client to add its TLS certificate to the server's trust store.

This effectively allowed anyone who knew or could find the trust password to add their client into the trust store after which the trust store was no longer required for further operations.

The trust password therefore had to be kept very safely, or unset immediately after adding a new client. This was unfortunately rarely the case, opening up the door for a brute force attack on the trust password and ultimately an attacker gaining full control over LXD and the server it runs on.

To address this, support for using one-time trust tokens has been added a little while back and all documentation updated to discourage users from using trust passwords.

In Incus, we went one step further and completely removed support for trust passwords. Adding new clients or new servers into a cluster should now be done through the use of one-time tokens or by using external authentication through OIDC.

Therefore, the following server configuration key has been removed:

  • core.trust_password


Change in DMI information

Inside of Incus virtual machines, the vendor is now set to Linux Containers and the product is set to Incus.

Change in virtio-serial marker

The virtio-serial device used for limited communication with Incus prior to establishing full agent access through vsock is now org.linuxcontainers.incus.

Migration from LXD

Incus comes with a convenient lxd-to-incus tool which can be used to transition a system from LXD to Incus.

The main restrictions at this stage are:

  • Minimum LXD version of 4.0
  • Maximum LXD version of 5.18
  • No support for migrating clusters at this stage (this is being worked on)


The Incus documentation can be found at:


There are no official Incus packages as Incus upstream only releases regular release tarballs. Below are some available options to get Incus up and running.

Zabbly packages for Debian and Ubuntu

Zabbly provides both daily and stable builds of Incus to Debian and Ubuntu users:

Homebrew package for the Incus client

The client tool is available through HomeBrew for both Linux and MacOS.

Chocolatey package for the Incus client

The client tool will soon be available through Chocolatey for Windows users.
Until then, binaries can be found here:


At this early stage, each Incus release will only be supported up until the next release comes out. This will change in a few months as we are planning an LTS release to coincide with the LTS releases of LXC and LXCFS.

Community support is provided at:
Bugs can be reported at: