Incus on Ubuntu 24.04 on Azure User Guide
Overview
This image runs Incus 7.2 on Ubuntu 24.04 LTS. Incus is a system container and virtual machine manager from the LinuxContainers project, the community fork of LXD. It gives you full Linux systems rather than single process application containers: each instance boots its own init, runs its own services and behaves like a small independent machine, while sharing the host kernel so it starts in about a second and costs a fraction of a VM.
The image ships the Incus web UI, so you can create and manage instances from a browser, and the incus command line client for everything you would rather script.
No credential ships in this image, and it is locked until first boot. No password, certificate or token of any kind is baked into it. A unique password is generated on your VM specifically by incus-firstboot.service during first boot, and the Incus API's trust store is empty until that runs. There is no default login to find, and no window during which a known credential is live.
What is included:
- Incus 7.2, pinned, from the Zabbly package channel published by the Incus maintainer
- The Incus web UI, served through nginx over HTTPS on port 443
- A ready to use
defaultstorage pool and anincusbr0NAT bridge, so you can launch an instance immediately - A unique web UI password generated on this VM at first boot, in a root only file
- The
incuscommand line client, working out of the box over the local socket - A recorded licence notice and dependency CVE audit on the image itself
Before you start
You need an Azure subscription, and the Azure CLI if you deploy from the command line. Everything below uses azureuser, the default administrator name this image expects.
Sizing. System containers run comfortably on the recommended Standard_B2s (2 vCPU, 4 GiB). Scale up for more instances.
Containers and virtual machines. Incus can run both. System containers work on any VM size, including the recommended B2s, and are what this guide covers. Incus can also run full virtual machines (
incus launch ... --vm), but that needs nested virtualisation, which Azure exposes only on Dv3/Ev3 series and later and not on the B series. If you want Incus VMs as well as containers, choose a nested virtualisation capable size such asStandard_D4s_v3. On a B series VM/dev/kvmis absent and--vmwill not work; containers are unaffected.
Deploy from the Azure Marketplace
- In the Azure portal, search the Marketplace for Incus on Ubuntu 24.04 LTS by cloudimg and select Create.
- Choose your subscription, resource group and region.
- Set the VM name and size (
Standard_B2sor larger). - Set the administrator username to azureuser and upload your SSH public key.
- Under Inbound port rules, allow SSH (22) and HTTPS (443).
- Select Review + create, then Create.
Do not open port 8443. The Incus API is bound to
127.0.0.1and is not reachable from outside the VM by design. nginx on 443 is the only door it needs.
Deploy from the Azure CLI
az group create --name incus-rg --location eastus
az vm create \
--resource-group incus-rg \
--name incus-vm \
--image cloudimg:incus-ubuntu-24-04:incus-ubuntu-24-04:latest \
--size Standard_B2s \
--admin-username azureuser \
--ssh-key-values ~/.ssh/id_rsa.pub \
--public-ip-sku Standard
az vm open-port --resource-group incus-rg --name incus-vm --port 443 --priority 1001
Get the public IP:
az vm show -d --resource-group incus-rg --name incus-vm --query publicIps -o tsv
Retrieve your unique password
The password is generated on your VM at first boot and written to a root only file. SSH in and read it:
ssh azureuser@<your-vm-public-ip>
sudo cat /root/incus-credentials.txt
You will see the URL, the username admin, and the password generated for this VM. Confirm the three services are running at the same time:
systemctl is-active incus incus-firstboot nginx

If the web UI does not answer, first boot has not finished. nginx is deliberately configured so it cannot start until
incus-firstboot.servicehas successfully generated this VM's password and certificate. That is intentional: the appliance fails closed rather than ever serving without authentication. Give it a moment after first boot and checksystemctl status incus-firstboot.
Sign in to the web UI
Open https://\<your-vm-public-ip>/ in a browser and sign in as admin with the password from the file above.
Your browser will warn about the certificate. The image generates a self signed certificate for your VM's own IP at first boot, because it cannot know your domain name in advance. The warning is expected. Add your own domain and a trusted certificate when you are ready, as shown at the end of this guide.
The Incus UI opens on Instances. A fresh VM starts with none, so the list is empty until you launch one.

Launch your first container
From the VM, launch a system container. Incus pulls the image from the LinuxContainers image server the first time and caches it:
sudo incus launch images:debian/12 app-01
Why
sudo. Incus grants full control to members of theincus-admingroup. This image does not add your administrator account to that group, because doing so would hand anyone who reaches that account complete control of every instance without a further step. Runincuswithsudo, or add your own account deliberately withsudo usermod -aG incus-admin $USER(log out and back in) if you prefer.
Check it:
sudo incus list
sudo incus storage list

The container appears in the web UI immediately, with its image, status and address:

Get a shell inside it, from the command line:
sudo incus exec app-01 -- bash
or from the Terminal tab in the web UI:

A note on Alpine images. The web UI's Terminal tab opens a
bashlogin shell. Alpine ships BusyBoxashand has nobashat all, so the Terminal tab will fail to attach on an Alpine container. Use the Console tab for those, orsudo incus exec <name> -- shfrom the command line, or installbashinside the container.
Useful lifecycle commands:
sudo incus stop app-01
sudo incus start app-01
sudo incus restart app-01
sudo incus info app-01
When you are finished with an instance, remove it (-f stops it first). Leave app-01 running for now if you intend to follow the networking section below:
sudo incus delete -f <instance-name>
Storage
The image ships a default storage pool using the dir backend, which stores instances as plain directories on your VM's own OS disk. It works on every VM size, needs no kernel module, and grows with whatever disk you attach.

The dir backend does not support pool level snapshots or quotas. If you want those, add a second pool on a dedicated data disk. For example, after attaching a data disk as /dev/sdc:
sudo apt-get install -y zfsutils-linux
sudo incus storage create fast zfs source=/dev/sdc
sudo incus launch images:debian/12 db-01 --storage fast
Both pools coexist; default stays as it is and you choose per instance.
Networking
Instances attach to the managed incusbr0 bridge and get a private address with NAT egress, so they can reach the internet while remaining unreachable from outside the VM.
To publish a service from a container, forward a port from the VM to the instance:
sudo incus config device add app-01 http proxy \
listen=tcp:0.0.0.0:8080 connect=tcp:127.0.0.1:80
Then open that port in your network security group:
az vm open-port --resource-group incus-rg --name incus-vm --port 8080 --priority 1002
Open only the ports you intend to publish, and never open 8443.
How this image is secured
Worth understanding, because it is deliberately different from a stock Incus install.
Incus authenticates its remote API with TLS client certificates, not passwords. Exposing that API to a browser means meeting a certificate prompt with no certificate to offer. So this image does not expose it at all:
- The Incus API listens on
127.0.0.1:8443only and is never reachable from the network. - nginx on 443 is the only door. It terminates TLS and gates on HTTP Basic Auth with your VM's unique password.
- nginx authenticates to the API with a TLS client certificate that first boot generated on your VM and added to the trust store. It is the only entry in it.
- Your SSH key is the root of trust. The password is readable only via
sudoon a VM only your key opens.
You can verify all of this on your own VM:
sudo ss -tlnp | grep -E '8443|:443|:80 '
curl -sk -o /dev/null -w 'unauthenticated: HTTP %{http_code}\n' https://localhost/ui/

To change the web UI password at any time:
sudo htpasswd -B /etc/cloudimg-incus/htpasswd admin
sudo systemctl reload nginx
Licence and dependency audit
The image records what it ships and under which licence, verified at build time against the real upstream artifacts:
head -18 /usr/share/doc/incus-cloudimg/LICENCE-NOTICE.txt
head -8 /usr/share/doc/incus-cloudimg/cve-audit.txt

Incus core is Apache-2.0. The Incus web UI is GPL-3.0, conveyed verbatim and unmodified; the notice on the image names the exact upstream tag its corresponding source is published at, together with a written offer to supply it. Nothing in this image or cloudimg's support terms restricts the rights those licences grant you.
Add your own domain and certificate
For production, put a real name and a trusted certificate in front:
- Point a DNS
Arecord at your VM's public IP. - Install a certificate with Certbot:
sudo apt-get update
sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d incus.example.com
Certbot edits the nginx site in place and sets up renewal. Your password and the API binding are unchanged.
Keeping the image up to date
The OS receives security updates automatically through unattended-upgrades, and no package is held back, so security fixes are never blocked, including for Incus itself.
Incus is installed from the Zabbly package channel, which is a third party origin that unattended-upgrades does not auto-install from. So your appliance stays on the release this image shipped until you upgrade it deliberately:
sudo apt-get update && sudo apt-get install -y incus incus-ui-canonical
Review the Incus release notes first, and snapshot the VM before a major jump.
Troubleshooting
The web UI does not load. Check systemctl is-active incus incus-firstboot nginx. If nginx is inactive or failed, first boot has not completed successfully; nginx will not start without this VM's generated password and certificate. Check journalctl -u incus-firstboot.
I get a 401 and my password is correct. Confirm you are signing in as admin, and re read the password with sudo cat /root/incus-credentials.txt.
The Terminal tab will not attach. On Alpine containers this is expected, as they have no bash. Use the Console tab or sudo incus exec <name> -- sh.
incus launch says the image cannot be found. The LinuxContainers image server retires old releases. Run sudo incus image list images: | grep <distro> to see what is currently published and use a current alias.
incus launch --vm fails. Full VMs need nested virtualisation. Check with ls /dev/kvm; if it is absent, your VM size does not support it. Use a Dv3/Ev3 or later size, or use system containers.
Support
Covered by cloudimg support: email support@cloudimg.co.uk.