
The incusbr0 NAT bridge is enough for a single isolated host, not for a private cloud. With OVN (Open Virtual Network), Incus creates distributed virtual networks, the equivalent of VPCs, isolated from one another, and puts load balancers with health checks in front of your services. This guide covers the prerequisite (a central OVN database), how to connect Incus to it, how to create an uplink network and an OVN VPC, then how to expose a distributed service behind a load balancer. Tested on an Incus OS cluster. For people building cloud-grade network infrastructure.
What you will learn
- Why OVN goes beyond the NAT bridge (VPCs, isolation, load balancers).
- Provide the central OVN database that Incus requires.
- Create an uplink network and an OVN VPC.
- Set up a network load balancer with health checks and verify failover.
Prerequisites
- A working Incus cluster (or a single Incus server).
- Familiarity with basic Incus networking, meaning the managed bridge and its NAT.
- A dedicated network interface for the uplink, with no IP address on the host side.
Why OVN, and not just a bridge
A NAT bridge connects the instances of a single host. As soon as you want networks isolated per project (VPCs), connectivity that follows instances across nodes, or a native load balancer, you need OVN. OVN builds logical virtual networks on top of the physical infrastructure, with routing, ACLs (the equivalent of Security Groups) and load balancers.
The trade-off: OVN needs a central database (northbound and southbound) that Incus drives. That is the real prerequisite, and the point where most setups stall.
The central OVN database (the prerequisite)
Incus does not ship OVN central: it connects to it. So you need an OVN cluster exposing its northbound (port 6641) and southbound (port 6642) databases. Two routes exist, and the official Incus documentation describes the second one.
- MicroOVN: a snap that brings up an OVN cluster in a handful of commands, with TLS. This is my own preference for production, not an Incus project recommendation.
ovn-centralinstalled by hand (packagesovn-centralandovn-host): the route the Incus documentation walks through, and the simplest one in a lab.
For a lab, the manual install over plain TCP is enough:
sudo apt install -y ovn-central ovn-hostsudo ovn-nbctl set-connection ptcp:6641:0.0.0.0 # northboundsudo ovn-sbctl set-connection ptcp:6642:0.0.0.0 # southboundOn the chassis side, every Incus node runs ovn-controller and connects to the southbound database. On an Incus OS node, which has no shell, you enable it through the system API rather than a manual install:
curl --cert client.crt --key client.key -X PUT \ https://<node>:8443/os/1.0/services/ovn \ -d '{"config":{"enabled":true,"database":"tcp:<central>:6642","tunnel_address":"<node-ip>","tunnel_protocol":"geneve"}}'The node then registers as an OVN chassis, ready to carry virtual networks.
Connecting Incus to OVN
You point Incus at the address of the northbound database:
incus config set network.ovn.northbound_connection tcp:<central>:6641Creating the uplink network
An OVN network needs an uplink: the exit point towards the physical world, and the range of external addresses that load balancers and OVN routers can use. The uplink relies on a dedicated interface (here ens19), with no IP on the host side.
On a cluster, the uplink is created in two steps: the parent is specific to each member, the rest is global.
# 1. the parent, per member (member-specific config)incus network create UPLINK --type=physical parent=ens19 --target node1
# 2. the global configurationincus network create UPLINK --type=physical \ ipv4.gateway=192.168.10.1/24 \ ipv4.ovn.ranges=192.168.10.220-192.168.10.230 \ dns.nameservers=192.168.10.1The ipv4.ovn.ranges key reserves a slice of the physical network (here .220 to .230) for OVN routers and load balancers. Those addresses will be routable from your LAN.
Creating an OVN VPC
The virtual network is created with a single command, pointing at the uplink:
incus network create vpc0 --type=ovn network=UPLINKIncus automatically allocates an internal subnet (for example 10.151.218.0/24) and sets up NAT towards the uplink. Instances attached to vpc0 get a private IP and reach the internet, while staying isolated from other OVN networks.
incus launch images:debian/13 web1 --network vpc0incus launch images:debian/13 web2 --network vpc0incus list -c ns4| web1 | RUNNING | 10.151.218.2 (eth0) || web2 | RUNNING | 10.151.218.3 (eth0) |An outbound ping from web1 confirms connectivity through the OVN NAT.
Setting up a load balancer with health checks
The OVN network load balancer spreads one external IP (taken from ipv4.ovn.ranges) across several internal backends, with health checking. It is the equivalent of an ELB or NLB.
-
Create the load balancer on an address from the uplink range:
Fenêtre de terminal incus network load-balancer create vpc0 192.168.10.220 -
Declare the backends (the instances that serve traffic):
Fenêtre de terminal incus network load-balancer backend add vpc0 192.168.10.220 web1 10.151.218.2 80incus network load-balancer backend add vpc0 192.168.10.220 web2 10.151.218.3 80 -
Publish the port, spreading it across the backends:
Fenêtre de terminal incus network load-balancer port add vpc0 192.168.10.220 tcp 80 web1,web2 -
Enable health checks: a backend that goes down leaves the pool.
Fenêtre de terminal incus network load-balancer set vpc0 192.168.10.220 \healthcheck=true healthcheck.interval=10 healthcheck.failure_count=3
Health checking is off by default, so that fourth step is what turns a plain round-robin into a load balancer that reacts to failure. Two more keys round out the behaviour if you need them: healthcheck.success_count decides how many successful probes bring a backend back, and healthcheck.timeout bounds each probe.
From the LAN, 192.168.10.220 answers and alternates between backends. If web1 goes down, traffic fails over automatically to web2:
for i in $(seq 1 6); do curl -s http://192.168.10.220/; doneweb2web1web2web1web1web2Key points
- OVN gives Incus distributed virtual networks (VPCs), per-network isolation and native load balancers.
- Incus does not provide OVN central: it connects to it (
network.ovn.northbound_connection). - On Incus OS, the OVN chassis is enabled through the API (
/os/1.0/services/ovn), with no shell. - An OVN network requires an uplink (a dedicated interface plus
ipv4.ovn.rangesfor external IPs). - The OVN load balancer spreads one external IP over several backends, with health checks and failover.