
Incus and Docker do not do the same job. Docker runs application containers (one process, one image, disposable) to package and distribute an application. Incus runs system containers (a complete, persistent Linux distribution) and virtual machines, in the manner of a lightweight machine. This guide explains the fundamental difference, lays it out in a clear table, and says which tool to choose for which need. For anyone hesitating between the two, or coming from Docker.
What you will learn
- The fundamental difference: application container against system container.
- A comparison table, Incus against Docker.
- Which tool to choose for your use case.
- That Incus also runs Docker images (OCI).
The fundamental difference
Everything hinges on what a container holds.
A Docker container runs a single process: your application (a web server, an API, a database). The image is built in layers, the container is ephemeral (you throw it away and recreate it), and it holds only what that process strictly needs. No init, no system services, no SSH.
An Incus container runs a complete system: a Linux distribution with its init (systemd, openrc), its services, its users, its logs. It is persistent: you connect to it, administer it, snapshot it, like a small machine. That is the difference between "packaging an application" and "provisioning a machine".
Comparison table
| Criterion | Docker | Incus |
|---|---|---|
| Container type | application (1 process) | system (complete distribution) |
| Virtual machines | no | yes (QEMU/KVM) |
| Lifetime | ephemeral | persistent |
| Image | layered (Dockerfile) | distribution (the images: remote) |
| Interactive access | docker exec, logs | incus shell, like a machine |
| Init and services | no (1 process) | yes (systemd, openrc) |
| Typical use | deploy an app | provision a Linux server |
This first table compares the natures. To choose, you also have to compare the application workflow, because "Incus runs OCI images" does not mean it replaces the Docker toolchain. The four capabilities below are often lumped together, whereas each is decided on its own.
| Capability | Docker | Incus |
|---|---|---|
| Run an OCI image | yes, it is its job | yes, since 6.3 |
| Build an image | yes, Dockerfile and BuildKit | no, no equivalent |
| Describe a multi-service set | yes, Compose | no, profiles and projects do not cover this need |
| Integrate with CI or Kubernetes | complete ecosystem | native Incus clustering, outside the Kubernetes ecosystem |
Which tool to choose
The right reflex: start from the need, not from the tool.
Choose Docker (or another application engine) when you want to package and distribute an application: a microservice, a reproducible web stack, a CI/CD build. The ecosystem around it, from Docker Hub to Compose, is cut out for that.
Choose Incus when you want a Linux machine: a test server, a complete development environment, a homelab, a virtual machine for another kernel or for Windows. You manage the instance as a system, with snapshots and an API, without the weight of a full hypervisor such as Proxmox (in French).
Incus also runs Docker images
The boundary is not sealed: since version 6.3, Incus can run OCI images (Docker's format) alongside its system containers. No OCI remote is preconfigured, so you add one first:
incus remote add docker https://docker.io --protocol=ociincus launch docker:nginx webThe image starts as an application container, marked CONTAINER (APP) in incus list, with its own IP address on incusbr0. An incus exec web -- nginx -v answers there as in any other Incus instance.
One check is needed before trying: OCI support dates from 6.3, so from the feature branch. Debian 13 ships Incus 6.0.4, the LTS branch, which predates it. On a standard Debian install, incus --version answers 6.0.4 and the command above cannot work: you have to move to the upstream repository.
Once that condition is met, you run application workloads without installing Docker, on the same platform as your system containers and your virtual machines. Details in running OCI containers with Incus.
Docker and Incus on the same host: does the network really break?
This is the most quoted trap, and it is conditional, not automatic. The Docker daemon can set the policy of the FORWARD chain to DROP, which stops the host from routing: Incus containers then get an IP on incusbr0 with no way out. But Docker only does so in a precise case, and Incus now protects itself against it.
Docker only sets this policy when it turns on IP forwarding itself. If it finds net.ipv4.ip_forward already at 1, it leaves it alone. Incus turns that setting on at initialisation: on a machine where Incus is installed before Docker, the chain stays at ACCEPT and the problem never shows up. This behaviour also concerns the iptables backend, still the default; the nftables backend introduced in Docker 29.0.0, experimental and to be enabled explicitly, does not turn on IP forwarding by itself.
And even under policy DROP, a recent Incus container keeps its network. Incus writes its own ACCEPT rules for incusbr0 into the FORWARD chain, and they survive a restart of the Docker daemon. The historical fix through DOCKER-USER then becomes useless. It remains useful on older versions of Incus or LXD, which did not set these rules: that is where the advice comes from.
The diagnosis, before any fix
Three commands are enough to know whether you are in the case described, and they avoid changing a firewall for nothing:
iptables -L FORWARD -n | head -1 # la politique : ACCEPT ou DROPdocker info --format '{{.FirewallBackend}}' # iptables ou nftablessysctl net.ipv4.ip_forward # 1 si quelqu'un l'a déjà activéIf the policy is ACCEPT, there is nothing to fix. If it is DROP, first check that your containers really lose the network with an incus exec <name> -- ping -c 2 9.9.9.9: the presence of the DROP is not enough to conclude, since Incus's rules can let the traffic through.
The fixes, from the cleanest to the most radical
If the blocking is confirmed, the Docker configuration is the cleanest lever: "ip-forward-no-drop": true in /etc/docker/daemon.json asks it not to touch the policy. The rule-based fix, on Incus versions that set none, explicitly allows the bridge:
iptables -I DOCKER-USER -i incusbr0 -j ACCEPTiptables -I DOCKER-USER -o incusbr0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPTSeparation remains the most durable answer: running one inside an instance of the other removes the question of the shared firewall.
Can Incus replace Docker
Partly. For a homelab or a development workstation, running your few application services as OCI images inside Incus avoids installing Docker as well, and everything is managed in one place. For intensive application work, though (building images from a Dockerfile, multi-service Compose, Kubernetes integration), the Docker ecosystem stays more complete and better tooled. Incus complements Docker more than it fully replaces it.
Key points
- Docker means application containers (one process, ephemeral) to package an application.
- Incus means system containers (a complete, persistent distribution) and virtual machines, to provision machines.
- You choose on the need: package an app (Docker) or provision a machine (Incus).
- Since 6.3, Incus also launches OCI images (
docker:), markedCONTAINER (APP); the LTS 6.0 branch of Debian 13 does not support them. - The two are often complementary, not competitors.
FAQ: common questions about Incus vs Docker
Application container against system container
- Docker: an application container, meaning one process (your app), a layered image, ephemeral;
- Incus: a system container, meaning a complete distribution (init, services), persistent, administered like a machine.
Start from the need
- Docker: to package and distribute an application (microservice, web stack, CI/CD). Its ecosystem (Docker Hub, Compose, Kubernetes) is built for that.
- Incus: for a Linux machine (test server, full development environment, homelab) or a virtual machine.
Only partly
For a homelab or a development workstation, running your few services as OCI images inside Incus avoids installing Docker, and everything is managed in one place.But for intensive application use (building images from a Dockerfile, Docker Compose, Kubernetes integration), the Docker ecosystem stays more complete. Incus complements Docker more than it fully replaces it.Yes, through the OCI remote
Since 6.3:incus remote add docker https://docker.io --protocol oci
incus launch docker:nginx web
The container shows with the CONTAINER (APP) type. Incus consumes OCI images (Docker Hub and other registries) but does not build them from a Dockerfile. Details in the dedicated OCI container guide.A conditional trap, not an automatic one
The Docker daemon can set theFORWARD chain policy to DROP, but only when it turns on IP forwarding itself. On a machine where Incus was installed first, forwarding is already on and the chain stays at ACCEPT. Recent Incus versions also write their own ACCEPT rules for incusbr0, so even a DROP policy does not necessarily cut the network.Diagnose before fixing:iptables -L FORWARD -n | head -1
incus exec <name> -- ping -c 2 9.9.9.9
If the blocking is confirmed, set "ip-forward-no-drop": true in /etc/docker/daemon.json, or allow the bridge in the DOCKER-USER chain on older Incus versions.