Three weeks after 1.0, here’s the next release — no big theme this time, mostly hardening plus a handful of features that came out of running this in production myself.
Key Changes & Features
-
Event-Driven Architecture
ic-healthdnow reacts to Incus lifecycle events (start/stop/shutdown/delete) instead of polling.upno longer polls for health/dependency waits—uses project-scoped Incus event listeners.
-
Port Handling
ports:now uses userspace proxy (default:127.0.0.1) or kernel NAT mode (opt-in viax-incus-compose.nat: true).- Removed
x-incus-compose.nat-proxy(replaced by plainports:).
-
Build Improvements
- Cross-platform support: No longer depends on
umoci(Linux-only). - Builder detection: Uses binary name (supports
podman,docker,buildah). - Image caching: Built images now use the same cache path as pulled images.
- Cross-platform support: No longer depends on
-
New Features
configs:Mount config files from files, inline content, or environment variables.networks.{name}.aliases:Extra DNS names (CNAME) for services.- DNS settings:
dns,dns_search,domainnamenow map to Incus’s OCI DNS config. - Auto-added registries:
docker.io,ghcr.io,mcr.microsoft.com,quay.io,registry.gitlab.com,codeberg.org.
-
CLI & Behavior
--external-healthdcan now be set incompose.yamlviax-incus-compose.healthd.external: true.up --no-depsno longer skipshealthd(use--no-deps --no-healthdfor old behavior).- Multiple compose files (
-f a.yaml -f b.yaml) now each get their own.incus.yamloverride.
-
Bug Fixes
- Fixed event-driven conflicts between
ic-healthdandup. - Improved CI reliability (E2E tests now pass consistently).
- Fixed event-driven conflicts between
Next Steps
- Backup support (#45) in progress.
- OVN network support (#15) and network ACLs (#98) in design phase.
On moving both sides to events
ic-healthd got its event-driven rewrite first, and once the client’s up wait followed onto the same Incus lifecycle event stream, the two started fighting each other. One side was sure an instance was down, the other equally sure it was up — for a while there it genuinely felt like they’d each developed a mind of their own. Tamed that step by step: backoff-aware retries around Instance is busy, healthd learning not to start an instance it doesn’t own, no starting mid-backoff-wait. Slower to land than “swap poll for events” makes it sound, but idle API load is gone now and status propagates as fast as Incus reports it, not on the next poll tick.
Update
incus-compose self-update
First install:
curl -sSfL https://raw.githubusercontent.com/lxc/incus-compose/main/install.sh | sh -s -- -b ~/.local/bin
Arch users: an incus-compose-bin and incus-compose-git (maintained by @neitsab and @jochumdev) are available.
Debian users: zabbly/incus will soon have incus-compose via it’s incus-extra package.
Docs: docs.incus-compose.org · Full changelog: CHANGELOG.md
What’s next: backup (#45) @ishaan-jindal is working on it. Also scoping real OVN network support (#15) and network ACLs — firewall rules between compose networks (#98); more once the design settles.
Thanks to @ishaan-jindal for the NAT-proxy rework, configs support, and the well-known-registry expansion this cycle, and to @code-by-tanveer for pitching in on test coverage.
Still running this in production myself — Immich, Wiki.js, LeafWiki, Gitea, Caddy, Kimai, and a DNS stack. Real-world compose files remain the most useful bug reports.
René
Repo: GitHub - lxc/incus-compose: Bring the familiar Docker Compose workflow to Incus — run compose.yaml files natively on Incus · GitHub
Releases: Releases · lxc/incus-compose · GitHub
Changelog: incus-compose/CHANGELOG.md at main · lxc/incus-compose · GitHub
Previous threads: v1.0 annoucement