Incus: Next-Gen Container and VM Management
LXD fork backed by Linux Containers. Unified management for system containers and VMs with modern features.
LXD was the gold standard for system containers—lightweight, fast, and efficient. Then Canonical’s licensing changes created uncertainty. The community needed a true open-source alternative without corporate control.
Incus emerged as the answer—a community-driven fork maintaining LXD’s excellence.
Backed by the Linux Containers project and led by LXD’s original creator, Incus preserves everything that made LXD great while ensuring long-term open-source commitment. It’s not just a container runtime—it’s a complete infrastructure platform combining containers and VMs in a unified experience.
Why This Guide Matters
Most container guides focus on Docker. This guide explores Incus:
- Complete installation and configuration
- System containers vs. application containers (Docker)
- VM support alongside containers
- Profile-based configuration management
- Advanced networking (bridges, VLANs, OVN)
- Storage pool optimization
- Migration from LXD
- Production-ready deployments
Whether you’re new to system containers or migrating from LXD, this guide provides comprehensive coverage.
What You’ll Master
By the end of this guide, you will:
- Understand Incus architecture and use cases
- Install Incus on Ubuntu, Debian, and other distributions
- Create and manage system containers and VMs
- Configure profiles for consistent deployments
- Implement advanced networking (bridges, NAT, routed)
- Optimize storage pools (ZFS, btrfs, LVM)
- Migrate from LXD to Incus
- Automate deployments with cloud-init
- Integrate with existing infrastructure
Prerequisites
Required Knowledge:
- Linux command line proficiency
- Basic networking concepts
- Understanding of containers vs. VMs
- Storage concepts (filesystems, volumes)
System Requirements:
Minimum:
- Linux system (Ubuntu 22.04+, Debian 12+, or compatible)
- 2GB RAM
- 20GB available storage
- Kernel 5.4+ with namespace support
Recommended:
- 8GB+ RAM
- 100GB+ storage (SSD preferred)
- ZFS-compatible storage for advanced features
- Dedicated network interface (for advanced networking)
Section 1: Understanding Incus
What is Incus?
Incus is a modern infrastructure platform providing:
System Containers (Primary Use Case):
Unlike Docker containers that run single applications, Incus containers are complete Linux systems:
Docker Container:
- Single process (nginx, postgres, etc.)
- Minimal OS (often Alpine Linux)
- Stateless, ephemeral
- Application isolation
- No init system
Incus Container:
- Full Linux distribution (Ubuntu, Debian, Alpine, etc.)
- Complete init system (systemd)
- Multiple processes and services
- Can run Docker inside container
- SSH access
- Persistent state
- System isolation Virtual Machines (Since Incus 0.1):
Full VMs using QEMU/KVM, managed the same way as containers:
Unified Management:
incus launch ubuntu:22.04 my-container # Container
incus launch ubuntu:22.04 my-vm --vm # VM
Same commands, same management interface
Different isolation levels for different needs Key Features:
- Unified API for containers and VMs
- Live migration (containers and VMs)
- Snapshot and backup management
- Profile-based configuration
- Advanced networking (OVN, bridging, routing)
- Storage pools (ZFS, btrfs, LVM, dir)
- Resource limits (CPU, memory, disk I/O)
- Image server (public and private)
- REST API for automation
- Cluster support (multiple hosts)
Incus vs. LXD vs. Docker
When to Use Each:
Docker:
✓ Microservices architectures
✓ Application deployment
✓ CI/CD pipelines
✓ Kubernetes workloads
✗ Full system requirements
✗ Multiple services in one container
✗ Traditional server workloads
Incus:
✓ Development environments
✓ Testing different Linux distributions
✓ Running complete services (mail server, web stack)
✓ Multi-service applications
✓ Docker host (run Docker inside Incus)
✓ VM needs alongside containers
✗ Orchestration at scale (use Kubernetes)
✗ Minimal overhead requirements
LXD:
⚠️ Consider Incus instead (fork for open-source future)
Same features, community-driven development Architecture Comparison:
Incus/LXD Architecture:
Host OS (Ubuntu/Debian/etc.)
├── Incus Daemon (REST API server)
│ ├── Container Runtime (LXC)
│ │ ├── Namespaces (PID, Network, Mount, UTS, IPC)
│ │ ├── Cgroups (resource limits)
│ │ └── AppArmor/SELinux (security)
│ ├── VM Runtime (QEMU/KVM)
│ ├── Storage Backend (ZFS/btrfs/LVM)
│ ├── Network Manager
│ └── Image Server
└── Containers and VMs
Docker Architecture:
Host OS
├── Docker Daemon
│ ├── containerd (container runtime)
│ ├── runc (OCI runtime)
│ └── Image management
└── Containers (single process each) Why Incus Over LXD?
Incus Advantages:
- True Open Source: Community-driven, no corporate control
- Original Creator: Led by Stéphane Graber (LXD creator)
- Active Development: Rapid feature additions
- Compatibility: Nearly 100% compatible with LXD
- Long-term Commitment: Linux Containers project backing
Migration Path: LXD users can migrate seamlessly (covered later in guide)
Section 2: Installing Incus
Installation on Ubuntu 22.04+
Method 1: From Official Repository (Recommended)
# Update system
sudo apt update && sudo apt upgrade -y
# Install Incus from Zabbly repository (official)
sudo mkdir -p /etc/apt/keyrings/
sudo wget -O /etc/apt/keyrings/zabbly.asc https://pkgs.zabbly.com/key.asc
# Add repository
cat <<EOF | sudo tee /etc/apt/sources.list.d/zabbly-incus-stable.sources
Enabled: yes
Types: deb
URIs: https://pkgs.zabbly.com/incus/stable
Suites: $(. /etc/os-release && echo ${VERSION_CODENAME})
Components: main
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/zabbly.asc
EOF
# Update package list
sudo apt update
# Install Incus
sudo apt install incus -y
# Verify installation
incus --version
# Output: incus version 0.x Method 2: Build from Source
# Install build dependencies
sudo apt install -y acl autoconf dnsmasq-base git golang liblxc-dev libacl1-dev libcap-dev libuv1-dev make pkg-config rsync squashfs-tools tar tcl xz-utils ebtables
# Clone Incus repository
cd /opt
sudo git clone https://github.com/lxc/incus.git
cd incus
# Build Incus
make deps
make
# Install
sudo make install
# Verify
/usr/local/bin/incus --version Installation on Debian 12+
# Add backports if needed
echo "deb http://deb.debian.org/debian bookworm-backports main" | sudo tee /etc/apt/sources.list.d/backports.list
# Update
sudo apt update
# Install from Zabbly (same as Ubuntu)
sudo mkdir -p /etc/apt/keyrings/
sudo wget -O /etc/apt/keyrings/zabbly.asc https://pkgs.zabbly.com/key.asc
cat <<EOF | sudo tee /etc/apt/sources.list.d/zabbly-incus-stable.sources
Enabled: yes
Types: deb
URIs: https://pkgs.zabbly.com/incus/stable
Suites: bookworm
Components: main
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/zabbly.asc
EOF
sudo apt update
sudo apt install incus -y Post-Installation Configuration
Initialize Incus:
# Run initialization wizard
sudo incus admin init
# Wizard prompts (recommended answers):
# Would you like to use clustering? No
# (Unless building multi-host cluster)
# Do you want to configure a new storage pool? Yes
# Name: default
# Driver: zfs (recommended) or btrfs/dir
# Create new ZFS pool? Yes
# Use existing block device? /dev/sdb (or create file-backed)
# Size: 50GB (if file-backed)
# Would you like to connect to a MAAS server? No
# Create a new local network bridge? Yes
# Bridge name: incusbr0
# IPv4 address: auto
# IPv4 NAT: Yes
# IPv6 address: auto
# IPv6 NAT: Yes
# Would you like stale cached images to be updated automatically? Yes
# Would you like a YAML "incus admin init" preseed? No
# Configuration complete! Manual Configuration (Alternative):
# Create storage pool
sudo incus storage create default zfs size=50GB
# Create network bridge
sudo incus network create incusbr0 ipv4.address=10.0.10.1/24 ipv4.nat=true ipv6.address=fd42:1234:5678::/64 ipv6.nat=true
# Set default profile
sudo incus profile device add default root disk path=/ pool=default
sudo incus profile device add default eth0 nic network=incusbr0 Add User to incus-admin Group:
# Add your user
sudo usermod -aG incus-admin $USER
# Apply group membership
newgrp incus-admin
# Verify access (no sudo needed now)
incus list Section 3: Creating and Managing Containers
Launching Your First Container
List Available Images:
# List Ubuntu images
incus image list images:ubuntu
# Common aliases:
# ubuntu:22.04 - Ubuntu 22.04 LTS
# ubuntu:24.04 - Ubuntu 24.04 LTS
# debian:12 - Debian Bookworm
# alpine:3.19 - Alpine Linux
# rockylinux:9 - Rocky Linux 9
# List all available distributions
incus image list images: | less Launch Container:
# Launch Ubuntu 22.04 container
incus launch images:ubuntu/22.04 web-server
# Breakdown:
# images:ubuntu/22.04 - Image from images.linuxcontainers.org
# web-server - Container name
# Container downloads, creates, and starts
# Takes 10-30 seconds on first launch Interact with Container:
# Execute commands in container
incus exec web-server -- ls /
# Get shell in container
incus exec web-server -- bash
# Or shorthand
incus shell web-server
# Inside container:
root@web-server:~# apt update
root@web-server:~# apt install nginx -y
root@web-server:~# systemctl start nginx
root@web-server:~# exit
# Check container IP
incus list
# Output:
# +------------+---------+---------------------+------+
# | NAME | STATE | IPV4 | IPV6 |
# +------------+---------+---------------------+------+
# | web-server | RUNNING | 10.0.10.100 (eth0) | ... |
# +------------+---------+---------------------+------+
# Access nginx
curl http://10.0.10.100 Container Lifecycle Management
Container Operations:
# Stop container
incus stop web-server
# Start container
incus start web-server
# Restart container
incus restart web-server
# Pause container (freeze processes)
incus pause web-server
# Resume container
incus resume web-server
# Delete container
incus delete web-server
# Delete running container (force)
incus delete web-server --force Container Information:
# Show detailed info
incus info web-server
# Output shows:
# - State (running/stopped)
# - Resources (CPU, memory usage)
# - Network info
# - Storage usage
# - Snapshots
# Show configuration
incus config show web-server
# Show running processes
incus exec web-server -- ps aux
# Monitor container resources
incus monitor web-server File Transfer
Copy Files to/from Container:
# Copy file to container
echo "Hello from host" > test.txt
incus file push test.txt web-server/root/
# Copy file from container
incus file pull web-server/etc/nginx/nginx.conf ./
# Copy directory
incus file push -r /local/directory web-server/root/
# Create file in container
incus exec web-server -- bash -c "echo 'content' > /root/file.txt" Snapshots and Backups
Create Snapshot:
# Create snapshot
incus snapshot create web-server pre-update
# List snapshots
incus info web-server | grep Snapshots -A 10
# Restore snapshot
incus snapshot restore web-server pre-update
# Delete snapshot
incus snapshot delete web-server pre-update
# Create with description
incus snapshot create web-server backup-20251216 --reuse description="Before major update" Export/Import Containers:
# Export container to file
incus export web-server web-server-backup.tar.gz
# Import container from file
incus import web-server-backup.tar.gz new-web-server
# Publish container as image
incus publish web-server --alias my-web-server-image
# Launch from custom image
incus launch my-web-server-image web-server-02 Section 4: Creating and Managing VMs
Launching Virtual Machines
Enable VM Support:
# Verify VM support (requires KVM)
incus info | grep "kvm:"
# Should show:
# - kvm: true
# If false, enable virtualization in BIOS Launch VM:
# Launch Ubuntu 22.04 VM
incus launch images:ubuntu/22.04 test-vm --vm
# Specify resources
incus launch images:ubuntu/22.04 windows-vm --vm -c limits.cpu=4 -c limits.memory=8GiB
# VM launches and boots (slower than containers)
# Can take 30-60 seconds for first boot VM-Specific Operations:
# Access VM console
incus console test-vm
# Exit console: Ctrl+a q
# Get VM IP (after boot complete)
incus list
# SSH to VM (after SSH server installed)
# VMs require SSH server installation:
incus exec test-vm -- apt install openssh-server -y
# Access via VNC (if configured)
incus config set test-vm raw.qemu="-vnc 0.0.0.0:0" VM vs. Container Comparison:
Operation Container VM
Boot time 1-2 sec 30-60 sec
Memory overhead ~10 MB ~512 MB
Kernel Shared Dedicated
OS support Linux only Any OS
Isolation Strong Strongest
Performance Native Near-native
Windows support No Yes
Docker inside? Yes Yes Section 5: Profiles and Configuration
Understanding Profiles
Profiles are templates for container/VM configuration:
Default Profile Structure:
config:
- CPU limits
- Memory limits
- Security policies
devices:
- Network interfaces
- Disk mounts
- USB devices
- GPU passthrough
Multiple profiles can be applied to single container
Settings merge with later profiles overriding earlier View Default Profile:
# Show default profile
incus profile show default
# Output:
config: {}
description: Default Incus profile
devices:
eth0:
network: incusbr0
type: nic
root:
path: /
pool: default
type: disk
name: default Creating Custom Profiles
Example: Web Server Profile
# Create profile
incus profile create webserver
# Configure profile
incus profile edit webserver
# In editor, add:
config:
limits.cpu: "2"
limits.memory: 2GiB
security.nesting: "true"
description: Web server optimized profile
devices:
eth0:
network: incusbr0
type: nic
root:
path: /
pool: default
type: disk
shared-data:
path: /var/www/shared
source: /srv/www-shared
type: disk
name: webserver
# Save and exit Apply Profile to Container:
# Launch with custom profile
incus launch images:ubuntu/22.04 web1 -p webserver
# Add profile to existing container
incus profile add web-server webserver
# Remove profile
incus profile remove web-server default
# List container profiles
incus config show web-server | grep profiles -A 5 Example: Development Environment Profile
incus profile create devenv
incus profile edit devenv
# Configuration:
config:
limits.cpu: "4"
limits.memory: 8GiB
security.nesting: "true" # Allow Docker inside
security.syscalls.intercept.mknod: "true"
security.syscalls.intercept.setxattr: "true"
description: Development environment with Docker support
devices:
eth0:
network: incusbr0
type: nic
root:
path: /
pool: default
size: 50GiB
type: disk
projects:
path: /home/ubuntu/projects
source: /home/user/projects
type: disk Resource Limits
CPU Limits:
# Set CPU limit (number of cores)
incus config set web-server limits.cpu=2
# CPU priority (shares)
incus config set web-server limits.cpu.priority=10
# Pin to specific CPUs
incus config set web-server limits.cpu.allowance="0,1" Memory Limits:
# Set memory limit
incus config set web-server limits.memory=4GiB
# Memory with swap
incus config set web-server limits.memory.swap=true
incus config set web-server limits.memory.swap.priority=1
# Hard enforcement
incus config set web-server limits.memory.enforce=hard Disk I/O Limits:
# Limit read throughput
incus config device set web-server root limits.read=20MB
# Limit write throughput
incus config device set web-server root limits.write=10MB
# IOPS limits
incus config device set web-server root limits.read.iops=1000
incus config device set web-server root limits.write.iops=500 Section 6: Advanced Networking
Network Types
1. Bridge Network (Default):
# Create bridge network
incus network create br-production ipv4.address=10.0.20.1/24 ipv4.nat=true ipv4.dhcp=true ipv6.address=none
# Attach container to bridge
incus network attach br-production web-server eth1
# Or set in profile
incus profile device add production-profile eth0 nic network=br-production 2. Macvlan Network:
Containers get IPs from physical network:
# Create macvlan (parent: physical interface)
incus network create mvlan-external parent=enp1s0 type=macvlan
# Attach to container
incus config device add web-server eth0 nic network=mvlan-external name=eth0
# Container now has IP from physical network DHCP
# Accessible directly from LAN 3. Routed Network:
# Create routed network
incus network create routed-net ipv4.address=10.0.30.1/24 ipv4.routing=true ipv4.nat=false ipv6.address=none
# Requires static routes on gateway
# ip route add 10.0.30.0/24 via [incus-host-ip] VLANs
# Create VLAN network
incus network create vlan100 parent=enp1s0 vlan=100 type=macvlan
# Attach containers to VLAN
incus launch images:ubuntu/22.04 vlan-web -p default
incus network attach vlan100 vlan-web eth1 Port Forwarding
Forward Host Port to Container:
# Create proxy device
incus config device add web-server http-proxy proxy listen=tcp:0.0.0.0:80 connect=tcp:10.0.10.100:80
# Now host:80 forwards to container:80
# HTTPS forwarding
incus config device add web-server https-proxy proxy listen=tcp:0.0.0.0:443 connect=tcp:10.0.10.100:443
# Multiple ports
incus config device add db-server mysql-proxy proxy listen=tcp:0.0.0.0:3306 connect=tcp:10.0.10.101:3306 Section 7: Storage Pools
Storage Backends
ZFS (Recommended):
Advantages:
- Instant snapshots (copy-on-write)
- Efficient cloning
- Data integrity (checksums)
- Compression
- Deduplication
# Create ZFS pool
incus storage create zfs-pool zfs size=100GB
# Or use existing ZFS pool
incus storage create zfs-pool zfs source=tank/incus
# Configure compression
incus storage set zfs-pool zfs.compression=lz4
# Enable snapshots
incus storage set zfs-pool volume.zfs.use_refquota=true Btrfs:
Similar to ZFS but lighter weight:
# Create btrfs pool
incus storage create btrfs-pool btrfs size=50GB
# Enable snapshots
incus storage set btrfs-pool btrfs.mount_options=compress=zstd LVM:
Traditional block storage:
# Create LVM pool
incus storage create lvm-pool lvm source=/dev/sdb lvm.thinpool_name=IncusPool
# Set volume group
incus storage set lvm-pool lvm.vg_name=incus-vg Directory (Simple):
File-based, no special filesystem:
# Create dir pool
incus storage create dir-pool dir source=/var/lib/incus/storage
# Works on any filesystem
# No advanced features (snapshots via rsync) Storage Volumes
Create Custom Volumes:
# Create storage volume
incus storage volume create default data-volume size=20GiB
# Attach to container
incus storage volume attach default data-volume web-server /mnt/data
# Detach volume
incus storage volume detach default data-volume web-server
# Delete volume
incus storage volume delete default data-volume Shared Volumes:
# Create shared volume
incus storage volume create default shared-data
# Attach to multiple containers
incus storage volume attach default shared-data web1 /mnt/shared
incus storage volume attach default shared-data web2 /mnt/shared
incus storage volume attach default shared-data web3 /mnt/shared
# All containers see same data Section 8: Migrating from LXD
Migration Process
Prerequisites:
✓ LXD containers stopped or prepare for downtime
✓ Incus installed on target system
✓ Storage pools created in Incus
✓ Network configuration planned
✓ Backup of LXD data Method 1: Direct Migration (Same Host)
# Stop LXD
sudo systemctl stop lxd
# Migrate data
sudo incus admin migrate-lxd
# Wizard prompts:
# - Migrate all containers? Yes
# - Migrate storage pools? Yes
# - Migrate networks? Yes
# - Migrate profiles? Yes
# Migration completes
# Containers now managed by Incus
# Verify
incus list
# Start containers
incus start --all Method 2: Manual Export/Import
# On LXD system, export container
lxc export my-container my-container.tar.gz
# Transfer to Incus system
scp my-container.tar.gz incus-host:/tmp/
# On Incus system, import
incus import /tmp/my-container.tar.gz
# Container imported and ready Conclusion
Incus represents the future of system containers—combining LXD’s excellence with true open-source commitment. From lightweight containers to full VMs, unified management to advanced networking, it delivers professional infrastructure tools for homelabs and production.
Key Takeaways:
- Incus preserves LXD’s power with community governance
- System containers offer full Linux environments, not just apps
- VMs and containers managed identically
- Profiles enable consistent, repeatable deployments
- Advanced networking rivals enterprise platforms
- ZFS integration provides enterprise-grade storage
Next Steps:
- Explore clustering for multi-host setups
- Implement OVN for software-defined networking
- Integrate with Ansible/Terraform for IaC
- Join the Incus community forums
- Contribute to open-source development
Resources:
- Incus Documentation: https://linuxcontainers.org/incus/docs/
- GitHub Repository: https://github.com/lxc/incus
- Community Forum: https://discuss.linuxcontainers.org/
- r/linuxcontainers: Reddit community
Welcome to Incus. The future of containers is open.