Installing Incus on Debian 13 with a Host Bridge (br0) for Container Networking
Generated with AI
Objective:
This guide will walk you through installing Incus on a fresh Debian 13 (“Trixie”) installation and configuring a host‐side bridge (named br0) so that:
- Your Debian server retains its original network connectivity (DHCP or static) via
br0. - All Incus containers attach directly to that same bridge (no NAT), allowing them to obtain IPs from your LAN’s DHCP or use static assignments.
- You can still access the Incus Web UI on
https://<br0-IP>:8443/(or whatever port you choose), since the host’s IP remains onbr0.
Along the way, we’ll highlight and correct the pitfalls you encountered (specifically, creating an Incus network object named br0 of the wrong type), explain each command in detail, and end with a consolidated “All Commands” section for quick reference.
Table of Contents
- Prerequisites & Overview
- Step 1: Update the OS & Install Prerequisites
- Step 2: Create a Host Bridge (br0) Without Losing Connectivity
- 2 .A Identify the Primary Interface
- 2 .B Backup & Edit
/etc/network/interfaces - 2 .C Restart Networking & Verify Bridge
- Step 3: Install Incus
- 3 .A Install
incusPackages - 3 .B (Optional) Install the Incus Web UI
- 3 .C Add Your User to the
incus-adminGroup - Step 4: Initialize Incus (Skip the Default Bridge)
- 4 .A Run
incus admin init - 4 .B When Prompted About a New Bridge, Answer “No”
- 4 .C Tell Incus You Already Have an Existing Bridge (
br0) - 4 .D Decline Incus Configuring IPv4/IPv6 on
br0 - 4 .E Verify
incus info& “networks: []” - Step 5: Attach Containers to the Host’s
br0Bridge - 5 .A Understand Why “Creating an Incus Network Named
br0” → Error - 5 .B Remove Any Erroneously Created Incus Network & Profile References
- 5 .C Re‐Add the
eth0Device in the Default Profile, Pointing to Hostbr0 - 5 .D Launch & Verify a Test Container on
br0 - 5 .E (Optional) Firewall / Sysctl Considerations
- Appendix: Complete List of Commands
Prerequisites & Overview
- Debian 13 “Trixie”: This guide assumes a fresh install of Debian 13, using the traditional
ifupdownnetworking (i.e., editing/etc/network/interfaces). - Root or Sudo Access: You must be able to run commands as
rootor viasudo. - Once finished:
- The host will have its primary IP on a Linux bridge named
br0. - Any container launched with the default profile will have its
eth0veth pair attached tobr0and thus receive an IP from your LAN’s DHCP or use a static you assign inside the container. - The Incus Web UI (HTTPS API) remains accessible at
https://<br0-IP>:8443(unless you bind to a different address or port).
- The host will have its primary IP on a Linux bridge named
Pitfall to Avoid:
If you create an Incus “network object” named br0 of type physical, and then leave your default profile pointing at parent: br0, Incus will think you mean that Incus network, and will refuse to attach a nictype: bridged device to a physical network object (error: Specified network must be of type bridge). In practice, you should treat br0 as the host’s actual Linux bridge, not as an Incus-managed network object. That means:
- Do not manually run
incus network create br0 --type=physical parent=br0unless you also remove or rename the Incus profile’s reference tobr0. - The recommended approach is to let Incus see the host’s
br0directly (Incus will auto-detect host bridges inincus network listasTYPE=bridge, MANAGED=NO) and attach containers to it.
This guide incorporates the corrections needed to avoid the “Specified network must be of type bridge” error.
Step 1: Update the OS & Install Prerequisites
- Log in as a sudo-enabled user & become root (if not already):
This ensures you have full administrative privileges for installing packages and editing network files.
- Update package lists and upgrade all installed packages:
apt update fetches the latest package lists. apt upgrade -y installs any available upgrades without prompting for “yes/no” on each package.
- Install bridge-utils (for managing Linux bridges) and dnsmasq-base (optional but prevents missing‐dependency errors):
bridge-utils provides the brctl command (used when creating or inspecting Linux bridges).
dnsmasq-base is not strictly required if you never enable Incus’s built-in managed bridge, but it avoids “missing package” errors in case Incus expects it later.
- (Optional) Verify bridge-utils is installed:
You should see a line with bridge-utils 1.7-1+deb13u1 (or similar), confirming installation.
At the end of Step 1, your Debian 13 host is fully updated and ready to create a Linux bridge for container networking.
Step 2: Create a Host Bridge (br0) Without Losing Connectivity
If your Debian server’s NIC (e.g. enp0s3, ens18, eno1, etc.) is already configured in /etc/network/interfaces—either via DHCP or static—you cannot simply add a bridge on top of it without moving the IP onto that bridge. Otherwise, the host will lose its address. The following steps will:
- Detect your primary interface.
- Move that interface into “manual” mode.
- Create a new bridge br0 that gets the same IP (DHCP or static).
-
Verify that the host still has network/internet connectivity via br0.
-
Identify the Primary Interface
Run:
You will see a list of all interfaces (loopback lo, physical NICs, etc.). For example:
1: lo: <LOOPBACK,UP,LOWER_UP> …
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 08:00:27:77:6c:fb brd ff:ff:ff:ff:ff:ff
3: enp0s8: <NO-CARRIER,BROADCAST,MULTICAST,DOWN> …
4: enp0s9: <NO-CARRIER,BROADCAST,MULTICAST,DOWN> …
In this example, the primary NIC is enp0s3 because it is UP and likely has an IP.
Note: Common Debian 13 interface names might be enp0s3, ens18, eno1, eno2, etc. Substitute your interface name wherever you see enp0s3 below.
Check the current IPv4 address on that interface to confirm:
You might see something like:
→ This tells you the host currently uses 192.168.1.50/24 via DHCP on enp0s3.- Backup & Edit /etc/network/interfaces
Back up the existing network configuration:
Now you can always revert by copying the .bak file back.
Open /etc/network/interfaces in an editor (e.g., nano):
You'll likely see something like:
# /etc/network/interfaces
# Loopback
auto lo
iface lo inet loopback
# Primary NIC (using DHCP)
auto enp0s3
iface enp0s3 inet dhcp
# (Possibly other interfaces here…)
Modify it so that: - enp0s3 is put into manual mode (no IP). - A new section for br0 is created that inherits the DHCP or static configuration.
If your host uses DHCP on enp0s3:
# Bridge setup for Incus containers
auto lo
iface lo inet loopback
# Put the physical NIC into manual mode
auto enp0s3
iface enp0s3 inet manual
# Create br0 and get an IP via DHCP (same network enp0s3 used to use)
auto br0
iface br0 inet dhcp
bridge_ports enp0s3
bridge_stp off # Disable Spanning Tree Protocol
bridge_fd 0 # No forwarding delay
bridge_maxwait 0 # No wait while the bridge comes up
If your host uses a static IP on enp0s3 (e.g., 192.168.1.50/24, gateway 192.168.1.1):
# Bridge setup for Incus containers
auto lo
iface lo inet loopback
# Put the physical NIC into manual mode
auto enp0s3
iface enp0s3 inet manual
# Create br0 with a static IP
auto br0
iface br0 inet static
address 192.168.1.50
netmask 255.255.255.0
gateway 192.168.1.1
bridge_ports enp0s3
bridge_stp off
bridge_fd 0
bridge_maxwait 0
Explanation of each directive:
auto enp0s3 / iface enp0s3 inet manual: - Tells Debian networking: “Bring enp0s3 up, but assign no IP (manual mode).”
bridge_ports enp0s3: - Puts enp0s3 as a “slave” of br0. Ethernet frames arriving on enp0s3 go onto br0 and vice versa.
bridge_stp off: - Disables Spanning Tree Protocol on the bridge. In small LANs, this is usually fine.
bridge_fd 0: - Sets the Forwarding Delay to 0 seconds (no waiting on topology changes).
bridge_maxwait 0: - Tells Debian’s ifupdown not to pause waiting for a STP root election.
-
Restart Networking & Verify Bridge
Bring down the old interface and bring up the new bridge Since you changed enp0s3 from DHCP to manual, do:
ifdown enp0s3 ifup br0
If ifdown enp0s3 complains “interface enp0s3 not configured,” you can ignore that.
Alternatively, restart the entire Debian networking service:
systemctl restart networking
This ensures the new /etc/network/interfaces configuration is in effect.
Confirm that br0 is up and has an IP
ip a show br0
You should see something like (for DHCP):
3: br0:
inet 192.168.1.50/24 (or your static) is now on br0.
Notice enp0s3 no longer has an inet line—its IP moved to br0.
Test connectivity from the host
ping -c 3 8.8.8.8
ping -c 3 google.com
The first checks raw IP routing via your gateway.
The second verifies DNS resolution.
Both should succeed, showing the host still has full network/internet access on br0.
At this point, the Debian 13 host is bridged onto your LAN via br0. Next, we’ll install Incus and configure it to attach containers to that same br0 bridge. Step 3: Install Incus
You can install Incus directly from Debian 13’s repositories. This will install the daemon, client, and any VM support packages. 3 .A Install incus Packages
Update package lists (again) and install Incus
apt update apt install -y incus incus-base
incus: Pulls in the full Incus meta-package (daemon, client, containers, VM support, etc.).
incus-base: Contains the minimal client/libraries; in most cases, you just need the full incus package.
Verify installation
which incus
Should output something like /usr/bin/incus.
incus --version
You should see something like incus 6.0.x (or whichever version Debian 13 provides).
3 .B (Optional) Install the Incus Web UI
If you want to use the visual web interface served by Incus (accessible over HTTPS), install:
apt install -y incus-ui-canonical
This package sets up the UI framework but does not automatically bind it to any network.
Later, we’ll configure core.https_address so that Incus’s API and Web UI listen on https://<br0-IP>:8443.
3 .C Add Your User to the incus-admin Group
Only users in the incus-admin group can perform full administrative tasks (creating containers, modifying networks, etc.). If your normal login is cyberatuc (for example), run:
usermod -aG incus-admin cyberatuc
-aG incus-admin appends the user to the incus-admin group without removing other groups.
After running that, you must log out and back in, or simply run:
newgrp incus-admin
so that your current shell picks up the new group membership.
At the end of Step 3, Incus is installed, and your user (cyberatuc) is in incus-admin. Step 4: Initialize Incus (Skip the Default Bridge)
By default, if you run incus admin init without any modifications, Incus will attempt to create:
A storage pool (and ask where to store data).
A default managed network (usually named incusbr0 or lxdbr0) with NAT and DHCP for containers.
Since our goal is to use the host’s existing bridge br0 (and not create a NAT’d network), we must explicitly tell the wizard not to create or manage any new bridge. 4 .A Run incus admin init
From your Debian host (as a member of incus-admin), run:
sudo incus admin init
You will see a series of questions. We will walk through each, focusing on the network portion:
Clustering?
Would you like to use clustering? (yes/no) [default=no]:
Leave it as no (unless you intend to cluster multiple Incus servers).
Press Enter to accept the default no.
Configure a new storage pool?
Do you want to configure a new storage pool? (yes/no) [default=yes]:
If you want to store container images and volumes on the default directory backend (/var/lib/incus), press Enter (default = yes).
You can optionally name it (e.g. default) and choose a path (e.g. /var/lib/incus/storage-pools/default), which you can also accept by pressing Enter at the defaults.
Network bridge creation?
Would you like to create a new local network bridge? (yes/no) [default=yes]: no
Type no, then press Enter.
This tells Incus: “Do not create an internal LXD-style incusbr0 bridge with NAT and DHCP.”
Use an existing bridge or host interface?
Would you like to use an existing bridge or host interface? (yes/no) [default=no]:
Type yes, then press Enter.
This tells Incus: “We already have a Linux bridge on the host; use that.”
Name of the existing interface?
What is the existing bridge or host interface you want to use? [default=br0]:
If your bridge is indeed named br0, simply press Enter to accept the default.
If your bridge had a different name (e.g. bridge0), type that name and press Enter.
Allow Incus to configure IPv4 on br0?
Would you like Incus to configure IPv4 addressing on br0? (yes/no) [default=yes]:
Type no, then press Enter.
Because you already moved the host’s IP onto br0 in Step 2, you do not want Incus to override it.
Allow Incus to configure IPv6 on br0?
Would you like Incus to configure IPv6 addressing on br0? (yes/no) [default=yes]:
Type no, then press Enter.
Again, the host already has the correct IPv6 (if any) on br0, so do not let Incus change it.
After finishing these questions, the wizard will complete setting up storage and any required certificates, but it will not create or manage any Incus-specific bridge or DHCP. Instead, Incus will reference your existing br0 for container networking.
Note: If at any point you see text like:
error: cannot use br0 because it is in use
that means your host is already using br0, which is expected. Just ensure you answered no to having Incus reconfigure it.
4 .B Verify incus info & “networks: []”
Run:
incus info
Look at the networks: line. You should see:
server:
...
networks: []
...
networks: [] confirms that Incus did not create any managed network.
Future containers will need either a profile device with parent=br0 (the host’s bridge) or you will manually create a new Incus network (with a different name) pointing at br0.
At the end of Step 4, Incus has been initialized with no default bridge. The host’s br0 remains configured exactly as in Step 2. Step 5: Attach Containers to the Host’s br0 Bridge
Now we must configure Incus so that any container we launch will attach its virtual NIC (eth0) to the host’s br0 and receive IPs from the same LAN. There are two common approaches:
Simplest approach (recommended):
Do not create any Incus network object named br0.
Instead, make the default profile’s eth0 device use nictype=bridged parent=br0.
Incus automatically detects that br0 is a host bridge (via incus network list).
Alternative approach (not used here, but useful for reference):
Create an Incus network with a different name (e.g. extbr0) that has --type=physical parent=br0.
Edit your default profile so that parent=extbr0 instead of parent=br0.
This fully separates the “Incus network name” from the host’s actual br0.
Because you initially ran incus network create br0 --type=physical parent=br0, Incus thought you were creating an Incus-managed network object named br0 of type physical. Then, your default profile’s parent: br0 referenced that Incus network object, causing validation errors (Specified network must be of type bridge). To fix:
Remove any existing Incus network object named br0 (since we want the profile to reference the host’s br0, not an Incus-managed network).
Ensure the default profile’s eth0 device is pointing at parent=br0 (the host’s bridge).
Launch containers and confirm they receive LAN IPs.
Below is a step-by-step breakdown of how to do exactly that, incorporating all lessons learned so far. 5 .A Understand Why “Creating an Incus Network Named br0” → Error
When you run:
sudo incus network create br0 --type=physical parent=br0
Incus creates an Incus network object in its own database named br0 of type=physical with parent=br0. (That second br0 refers to the host interface name.)
Your default profile still said:
devices: eth0: name: eth0 nictype: bridged parent: br0 type: nic root: path: / pool: default type: disk
In that profile, parent: br0 refers to the Incus network object named br0, not the host’s actual /sys/class/net/br0.
Incus validation: A device with nictype: bridged must be attached to a network of type=bridge (i.e. an Incus-managed bridge) if it is referencing a network object. But since you created it as type=physical, Incus refused:
Invalid devices: Device validation failed for "eth0": Specified network must be of type bridge
Lesson: If you name an Incus network object br0, Incus loses its ability to treat br0 as the host’s real Linux bridge. To allow “plugging directly into the host’s br0”, you must ensure Incus does not have a network object of that same name.
5 .B Remove Any Erroneously Created Incus Network & Profile References
If your default profile currently has an eth0 device, remove it (so that it no longer references an Incus network named br0).
incus profile device remove default eth0
This command removes the eth0 stanza from the default profile.
After running it, incus profile show default should display only:
config: {}
description: Default Incus profile
devices:
root:
path: /
pool: default
type: disk
name: default
used_by: []
project: default
There is no eth0 entry under devices:.
Delete any Incus network object named br0 (so Incus no longer thinks there is a network called br0 in its own database).
sudo incus network delete br0
Incus will respond: Network br0 deleted.
Now run:
incus network list
You should see only host interfaces (e.g. eno1, eno2, etc.) and possibly a row for br0 of TYPE=bridge, MANAGED=NO if Incus auto-detects host bridges. But you will not see a TYPE=physical network named br0 in the Incus database.
Example output might now look like:
+------+----------+---------+------+------+-------------+---------+-------+
| NAME | TYPE | MANAGED | IPV4 | IPV6 | DESCRIPTION | USED BY | STATE |
+------+----------+---------+------+------+-------------+---------+-------+
| br0 | bridge | NO | | | | 0 | |
| eno1 | physical | NO | | | | 0 | |
| eno2 | physical | NO | | | | 0 | |
| eno3 | physical | NO | | | | 0 | |
| eno4 | physical | NO | | | | 0 | |
| lo | loopback | NO | | | | 0 | |
+------+----------+---------+------+------+-------------+---------+-------+
Key point: Incus now sees br0 as a host bridge (TYPE=bridge, MANAGED=NO), not as an Incus‐managed network object.
5 .C Re‐Add the eth0 Device in the Default Profile, Pointing to Host br0
Now that Incus no longer has a network object named br0, you can re‐create your default profile’s eth0 device so containers will plug directly into the host’s br0 bridge.
Run:
incus profile device add default eth0 nic nictype=bridged parent=br0
profile device add default eth0: We are modifying the default profile, adding a device named eth0.
type=nic: This device is a network interface.
nictype=bridged: We want the container’s eth0 veth interface to be bridged on the host.
parent=br0: We are telling Incus, “Connect this bridged interface to the host’s br0 bridge.”
Because Incus sees a host br0 (of TYPE=bridge, MANAGED=NO), it interprets parent=br0 literally as the Linux bridge.
Incus will create a veth pair (e.g. vethXXX on the host) and place the host end into br0.
Verify the default profile now has both root and eth0 under devices::
incus profile show default
Expected output:
config: {}
description: Default Incus profile
devices:
eth0:
name: eth0
nictype: bridged
parent: br0
type: nic
root:
path: /
pool: default
type: disk
name: default
used_by: []
project: default
eth0.parent: br0 means “plug the container’s eth0 into the host’s br0.”
root remains your root disk backed by the default storage pool.
5 .D Launch & Verify a Test Container on br0
Now that the profile is correct, let’s launch a container and confirm it really lives on the same LAN as the host.
Launch a Debian 13 (Trixie) container (named test-net):
incus launch images:debian/trixie test-net
incus launch images:debian/trixie test-net tells Incus:
Pull the Debian 13 Trixie image from the official image server (images: remote).
Create and start a container named test-net using the default profile (which now has eth0 bridged to br0).
Check that the container’s eth0 has an IP from your LAN’s DHCP server (or static if you configured inside the container):
incus exec test-net -- ip a show eth0
Sample output:
3: eth0@if4:
The container’s eth0 was bridged onto br0, so it got 192.168.1.123/24 from your LAN’s DHCP.
Ping an external IP from inside the container (tests raw IP routing):
incus exec test-net -- ping -c 3 8.8.8.8
Expected:
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data. 64 bytes from 8.8.8.8: icmp_seq=1 ttl=115 time=14.2 ms 64 bytes from 8.8.8.8: icmp_seq=2 ttl=115 time=13.7 ms 64 bytes from 8.8.8.8: icmp_seq=3 ttl=115 time=13.9 ms
Ping a domain name from inside the container (tests DNS):
incus exec test-net -- ping -c 3 debian.org
If that works, DNS resolution is correct.
Ping the host from the container:
On the host, find the IP assigned to br0, e.g.:
ip a show br0 | grep 'inet '
Suppose the host’s br0 IP is 192.168.1.50/24.
From inside the container:
incus exec test-net -- ping -c 3 192.168.1.50
You should see:
PING 192.168.1.50 (192.168.1.50) 56(84) bytes of data.
64 bytes from 192.168.1.50: icmp_seq=1 ttl=64 time=0.123 ms
64 bytes from 192.168.1.50: icmp_seq=2 ttl=64 time=0.077 ms
64 bytes from 192.168.1.50: icmp_seq=3 ttl=64 time=0.085 ms
This confirms the container and host can see each other on br0.
Ping the container from the host:
On the host shell:
ping -c 3 192.168.1.123
Substitute 192.168.1.123 with the IP you saw in step 2.
You should receive replies, confirming two‐way connectivity on the LAN.
If all these tests pass, your container is genuinely bridged to the LAN via the host’s br0, and your Debian 13 server’s own IP on br0 remains intact (so you can still browse to https://192.168.1.50:8443/ to reach the Incus Web UI). 5 .E (Optional) Firewall / Sysctl Considerations
In a pure L2 bridge configuration, you typically do not need to enable IP forwarding on the host, because containers are on the same subnet as the host and route out through the LAN’s gateway (not through the host’s IP). However, if you have a restrictive firewall or plan to do more advanced networking, keep these tips in mind:
Check IP forwarding (only relevant if you want to do NAT or advanced routing—NOT required for basic bridged L2):
sysctl net.ipv4.ip_forward
If it reads net.ipv4.ip_forward = 0, that is okay for pure bridging (because the bridge is L2, not L3).
If you ever need to enable forwarding (e.g. you run OVS, do NAT, or route containers manually), you can do:
sysctl -w net.ipv4.ip_forward=1
And add net.ipv4.ip_forward=1 to /etc/sysctl.conf (or create /etc/sysctl.d/99-local.conf) to make it permanent.
If using iptables or nftables on the host:
A typical Debian host with ufw/iptables does not block bridged traffic by default, because bridging is Linux kernel L2, not routed L3.
However, if you have an aggressive FORWARD‐chain policy (e.g., DROP), you may need to explicitly allow traffic on br0:
# Example: if using iptables
iptables -A FORWARD -i br0 -o br0 -j ACCEPT
iptables -A FORWARD -i br0 ! -o br0 -j ACCEPT
iptables -A FORWARD ! -i br0 -o br0 -j ACCEPT
With nftables, ensure you allow forwarding between br0 and the physical NICs as needed.
Generally, if your LAN router is providing DHCP on br0, containers go out through the same gateway as the host, and no further forwarding/NAT is required. Only enforce firewall rules if you have specific security requirements. Appendix: Complete List of Commands
Below is a consolidated list of all the commands used in this guide. You can copy/paste them in order, or refer to each section above for details. Remember to substitute your own primary interface name (e.g. enp0s3, eno1, etc.) if it differs.
Click to expand “All Commands”
################################################################################ # Step 1: Update OS & Install Prerequisites ################################################################################ sudo -i apt update apt upgrade -y apt install -y bridge-utils dnsmasq-base ################################################################################ # Step 2: Create Host Bridge (br0) Without Losing Connectivity ################################################################################ # 2.A Identify Primary Interface ip link show # → Note the interface that is UP and has an IP, e.g. enp0s3 ip a show enp0s3 | grep 'inet ' # 2.B Backup & Edit /etc/network/interfaces cp /etc/network/interfaces /etc/network/interfaces.bak nano /etc/network/interfaces # 2.C Restart Networking & Verify Bridge ifdown enp0s3 ifup br0 # (or: systemctl restart networking) ip a show br0 ping -c 3 8.8.8.8 ping -c 3 google.com ################################################################################ # Step 3: Install Incus ################################################################################ apt update apt install -y incus incus-base # (Optional) Install the Incus Web UI apt install -y incus-ui-canonical # Add your user (e.g. cyberatuc) to incus-admin group usermod -aG incus-admin cyberatuc newgrp incus-admin ################################################################################ # Step 4: Initialize Incus (Skip the Default Bridge) ################################################################################ sudo incus admin init # → Answer “no” to creating a new bridge # → Answer “yes” to using existing interface # → Enter “br0” (or your bridge’s name) # → Answer “no” to IPv4 and IPv6 configuration by Incus # Verify no Incus-managed networks exist incus info # → Look for “networks: []” ################################################################################ # Step 5: Attach Containers to Host’s br0 Bridge ################################################################################ # 5.B Remove any existing eth0 device from default profile incus profile device remove default eth0 # 5.B Delete any Incus network object named “br0” sudo incus network delete br0 # 5.C Re-add the eth0 device in default profile, pointing at host’s br0 incus profile device add default eth0 nic nictype=bridged parent=br0 # 5.D Launch a test container to verify bridged networking incus launch images:debian/trixie test-net # 5.D Inside the container, check IP incus exec test-net -- ip a show eth0 # 5.D Inside the container, test connectivity incus exec test-net -- ping -c 3 8.8.8.8 incus exec test-net -- ping -c 3 debian.org # 5.D On host, find br0’s IP (e.g. 192.168.1.50) ip a show br0 | grep 'inet ' # 5.D Inside container, ping the host’s br0 IP incus exec test-net -- ping -c 3 192.168.1.50 # 5.D On host, ping the container’s IP (e.g. 192.168.1.123) ping -c 3 192.168.1.123 # 5.E (Optional) Firewall / sysctl adjustments sysctl net.ipv4.ip_forward # (If you need forwarding, enable it:) sysctl -w net.ipv4.ip_forward=1 # Add to /etc/sysctl.conf or /etc/sysctl.d/99-local.conf: # net.ipv4.ip_forward=1 # (If using iptables firewall and default DROP on FORWARD, allow bridged traffic): iptables -A FORWARD -i br0 -o br0 -j ACCEPT iptables -A FORWARD -i br0 ! -o br0 -j ACCEPT iptables -A FORWARD ! -i br0 -o br0 -j ACCEPTDetailed Breakdown of Key Commands
Below is a thorough explanation of each command (or group of commands) listed above, so that anyone following this guide understands why and how each step works. Step 1 Commands
sudo -i
Elevates your shell to root. Everything you run in this session has root privileges.
If you’re already logged in as root, skip this.
apt update
Updates Debian’s package index files, so that you get the latest information about available packages.
apt upgrade -y
Installs the latest versions of all currently‐installed packages on the system.
The -y flag automatically answers “yes” to any prompts, making it non‐interactive.
apt install -y bridge-utils dnsmasq-base
Installs:
bridge-utils: Provides brctl commands for creating and managing Linux bridges.
dnsmasq-base: A minimal DHCP/DNS caching server (not strictly needed unless Incus tries to use it for a managed network, but installing it avoids missing‐package errors later).
dpkg -l bridge-utils (Optional Validation)
Lists the bridge-utils package and verifies that it is installed (you’ll see a line beginning with ii bridge-utils).
Step 2 Commands 2.A Identify Primary Interface
ip link show
Lists all network interfaces on the host, their state (UP, DOWN), MTU, queue discipline, etc.
Look for an interface that is UP and has an IP (check next command).
ip a show enp0s3 | grep 'inet '
Shows the IPv4 address assigned to enp0s3 (if that is your primary NIC). Replace enp0s3 with your actual interface name.
If using DHCP, you might see inet 192.168.1.50/24. If using static, you’ll see the configured static.
2.B Backup & Edit /etc/network/interfaces
cp /etc/network/interfaces /etc/network/interfaces.bak
Makes a backup of your existing network configuration file. If anything goes wrong, you can restore via:
cp /etc/network/interfaces.bak /etc/network/interfaces
systemctl restart networking
nano /etc/network/interfaces (or vi, vim, etc.)
Opens the config file in an editor. Replace its contents for your primary NIC with the following “manual + bridge” setup.
DHCP example (if your server originally got its IP via DHCP on enp0s3):
auto lo iface lo inet loopback
auto enp0s3 iface enp0s3 inet manual
auto br0 iface br0 inet dhcp bridge_ports enp0s3 bridge_stp off bridge_fd 0 bridge_maxwait 0
Static IP example (if your server originally had a static on enp0s3):
auto lo
iface lo inet loopback
auto enp0s3
iface enp0s3 inet manual
auto br0
iface br0 inet static
address 192.168.1.50
netmask 255.255.255.0
gateway 192.168.1.1
bridge_ports enp0s3
bridge_stp off
bridge_fd 0
bridge_maxwait 0
The key is that enp0s3 is no longer assigned an IP directly. Instead, br0 (the bridge) inherits that IP.
2.C Restart Networking & Verify Bridge
ifdown enp0s3
Tears down enp0s3. It will lose its IP. It does not remove it from any bridge yet (that happens next).
ifup br0
Brings up the br0 interface. Because bridge_ports enp0s3 is configured, enp0s3 is enslaved and carries the new br0 interface’s IP (whether DHCP or static).
If you see errors:
If you get “interface enp0s3 not configured” or similar, double‐check that you spelled the interface name correctly in /etc/network/interfaces.
You can also run systemctl restart networking as a fallback to apply all changes in one go:
systemctl restart networking
ip a show br0
Confirms that br0 is up and has an inet line.
Example output for DHCP scenario:
3: br0:
Example for static:
3: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 …
inet 192.168.1.50/24 brd 192.168.1.255 scope global br0
ping -c 3 8.8.8.8
Tests raw IP connectivity to Google’s public DNS. If you get replies, your gateway route and upstream are correct.
ping -c 3 google.com
Tests DNS resolution and connectivity. If replies succeed, your /etc/resolv.conf or DNS setup works.
Step 3 Commands
apt update
Refreshes package lists again, ensuring the latest Incus packages are visible.
apt install -y incus incus-base
Installs Incus (daemon + client) and minimal support packages.
The -y flag automatically accepts all prompts.
apt install -y incus-ui-canonical (optional)
Installs the Incus Web UI package (if you want a browser‐based interface). This does not configure networking for the UI; you must still set core.https_address later.
usermod -aG incus-admin cyberatuc
Adds the user cyberatuc to the incus-admin group, granting full Incus administration privileges. If your username is different, replace cyberatuc with your actual login.
newgrp incus-admin
Starts a new shell with the updated group membership so you don’t have to log out and back in.
Step 4 Commands
sudo incus admin init
Starts the Incus initialization wizard. You’ll see interactive prompts. Follow these answers:
Would you like to use clustering? (yes/no) [default=no]:
Each <ENTER> means “accept the default” unless you type something else first.
The key questions are the “no” answers to creating a new bridge and letting Incus manage IPv4/IPv6 on br0.
incus info
Verifies that the Incus server reports:
networks: []
meaning no managed networks exist.
Step 5 Commands 5 .B Remove Erroneous Profile References & Delete Incus Network “br0”
incus profile device remove default eth0
Removes the eth0 device from the default profile. This ensures the profile no longer “uses” an Incus network named br0.
sudo incus network delete br0
Deletes any Incus-managed network object called br0 (type physical).
After deletion, incus network list will show either nothing named br0 or show br0 as a host bridge (TYPE=bridge, MANAGED=NO), which is exactly what we want.
5 .C Re‐Add the eth0 Device to Default Profile (Point to Host’s br0)
incus profile device add default eth0 nic nictype=bridged parent=br0
Instructs Incus: “When any container uses the default profile, create a veth pair, name it eth0 inside the container, and bridge the host end into /sys/class/net/br0.”
Since Incus now sees a host br0 of TYPE=bridge, MANAGED=NO, it treats parent=br0 as the actual Linux bridge, not as a network object.
incus profile show default
Verifies that the default profile’s devices: section now reads:
devices:
eth0:
name: eth0
nictype: bridged
parent: br0
type: nic
root:
path: /
pool: default
type: disk
If you see that, then the profile is correct.
5 .D Launch & Verify a Test Container
incus launch images:debian/trixie test-net
Launches a container named test-net using Debian 13 Trixie.
It automatically applies the default profile, so the container’s eth0 will be bridged onto host br0.
incus exec test-net -- ip a show eth0
Shows the container’s eth0 interface and its assigned IP:
3: eth0@if4: <…> mtu 1500 …
inet 192.168.1.123/24 brd 192.168.1.255 scope global dynamic eth0
Confirm that the IP is on the same subnet as your host.
incus exec test-net -- ping -c 3 8.8.8.8
Verifies that the container can reach an external IP (Google DNS).
incus exec test-net -- ping -c 3 debian.org
Verifies that DNS resolution works inside the container.
ip a show br0 | grep 'inet ' (on host)
Suppose this outputs inet 192.168.1.50/24 brd 192.168.1.255 scope global br0.
incus exec test-net -- ping -c 3 192.168.1.50
Verifies that the container can ping the host’s br0 IP.
ping -c 3 192.168.1.123 (on host)
Verifies that the host can ping the container’s IP.
All pings and connectivity tests should succeed, demonstrating that your container is truly on the same LAN as the host, bridged via br0. 5 .E (Optional) Firewall / sysctl
sysctl net.ipv4.ip_forward
Checks whether IP forwarding is enabled. For pure bridging, having 0 here is fine. If you plan to do additional routing/NAT, set it to 1.
sysctl -w net.ipv4.ip_forward=1
Temporarily enables IP forwarding immediately.
Add to /etc/sysctl.conf (or create /etc/sysctl.d/99-local.conf):
net.ipv4.ip_forward=1
Makes IP forwarding persist across reboots.
If you use iptables and have a default DROP policy on the FORWARD chain, allow bridged traffic:
iptables -A FORWARD -i br0 -o br0 -j ACCEPT
iptables -A FORWARD -i br0 ! -o br0 -j ACCEPT
iptables -A FORWARD ! -i br0 -o br0 -j ACCEPT
Final Summary & Best Practices
Never create an Incus network object named br0 if you intend to use the host’s real Linux bridge br0. Doing so causes validation errors for nictype=bridged.
Use the default Incus profile with eth0 set as:
devices: eth0: name: eth0 nictype: bridged parent: br0 type: nic root: path: / pool: default type: disk
This instructs Incus to “plug” the container’s veth into br0 at runtime.
Ensure the Debian host’s br0 bridge is up — has the host’s IP — before attaching containers. Otherwise, containers may fail to get a DHCP lease or route.
After launching the first container, verify inside:
incus exec
Confirm it has an IP from your LAN, then test connectivity.
To access the Incus Web UI, in most cases run:
incus config set core.https_address [::]:8443
Then visit https://<br0-IP>:8443/ from any browser on your LAN. Make sure your firewall (if any) allows port 8443.
By following this unified, corrected procedure, you will avoid the “Specified network must be of type bridge” error and have a robust host + container network configuration all sharing the same bridge (br0). Anyone copying these steps should be able to reproduce a working Incus environment on Debian 13 without network conflicts.