This episode breaks down LXC networking: the default lxcbr0 bridge with NAT, veth pairs connecting containers to the bridge, configuration in /etc/lxc/default.conf and lxc-usernet, the none/veth/macvlan/phys network modes, and setting static IPs or DHCP.

Containers can live without networking, but a useful container almost always needs to talk to the outside world. In episode 6 we break down the LXC networking stack: the lxcbr0 bridge with NAT, the veth pairs connecting containers to the bridge, the network modes, and how to assign static IPs or DHCP. This is the episode that most often becomes a source of confusion in homelabs — so we'll cover it thoroughly.
By default, LXC creates the lxcbr0 bridge on the host — usually on the 10.0.3.0/24 network. A bridge is a "virtual switch": all containers attached to it can talk to each other, and outbound traffic is forwarded by the host.
ip addr show lxcbr0Each container gets one veth pair: a pair of virtual interfaces connected to each other like the ends of a cable. One end lives inside the container (eth0), the other end attaches to the bridge (vethXYZ). This is how LXC gives the container its own network namespace (remember the concept from episode 2).
Outbound traffic from lxcbr0 to the outside network is NATed by the host via iptables/nftables. This means containers can reach out to the internet, but from the outside, containers aren't directly reachable — unless you add port forwarding (e.g. DNAT from a host port to a container IP).
The /etc/lxc/default.conf file determines the network settings every new container uses. A typical content on an Ubuntu installation:
lxc.net.0.type = veth
lxc.net.0.link = lxcbr0
lxc.net.0.flags = up
lxc.net.0.hwaddr = 00:16:3e:xx:xx:xxtype = veth — uses a veth pair.link = lxcbr0 — the host end attaches to the lxcbr0 bridge.flags = up — the interface is brought up immediately when the container starts.hwaddr — MAC address (can be set per-container for DHCP lease stability).For unprivileged containers (which can't create bridges on the host), the /etc/lxc/lxc-usernet file grants regular users permission to create network interfaces:
# <user> <type> <link> <parent bridge> <count>
devnull veth lxcbr0 10The line above allows user devnull to create up to 10 veths attached to lxcbr0. Without this entry, a non-root user can't run unprivileged containers with veth networking.
Warning
Classic symptom: lxc-start fails with "Permission denied" or "lxc-usernet: Operation not permitted". The most common cause is that lxc-usernet has no entry for your user. Fix that file, then retry the start.
LXC supports four basic modes:
none — container with no interfaces at all. Good for truly isolated offline workloads.veth — veth pair to a bridge; the most flexible and most common mode.macvlan — an interface with its own MAC attached directly to a physical interface (e.g. eth0). The container appears as a physical device on the LAN. Keep in mind: macvlan can't communicate bidirectionally with its owning host directly.phys — the host's physical interface is handed over entirely to the container (passthrough). Only one container can use one physical NIC at a time.The mode is selected via lxc.net.0.type in the container config:
lxc.net.0.type = macvlan
lxc.net.0.link = eth0
lxc.net.0.flags = upThe easiest way: let the container get an IP from the bridge. On an Ubuntu container with systemd-networkd:
network:
version: 2
ethernets:
eth0:
dhcp4: trueFor a stable IP (needed by port forwarding or DNS), set a static IP inside the container. On the host, the LXC config can declare the network via lxc.net.0.ipv4.address:
lxc.net.0.type = veth
lxc.net.0.link = lxcbr0
lxc.net.0.flags = up
lxc.net.0.ipv4.address = 10.0.3.10
lxc.net.0.ipv4.gateway = 10.0.3.1Always keep consistency: the declaration in the LXC config and the configuration inside the container (netplan/NetworkManager) must point to the same IP.
To make a container reachable from outside the NAT, add DNAT on the host:
sudo iptables -t nat -A PREROUTING -p tcp --dport 8080 -j DNAT --to-destination 10.0.3.10:80
sudo iptables -A FORWARD -p tcp -d 10.0.3.10 --dport 80 -j ACCEPTTip
For unprivileged containers, using lxc.net.0.ipv4.address with lxc.net.0.ipv4.gateway is the cleanest approach — LXC manages the routes and ARP automatically, without needing to touch netplan manually.
ip addr inside the container and make sure lxc.net.0.flags = up is in the config.Key takeaways:
lxcbr0 is the default NAT bridge (10.0.3.0/24) for container networking.eth0 to the host bridge./etc/lxc/default.conf provides the network template; /etc/lxc/lxc-usernet grants veth quotas to unprivileged users.none, veth, macvlan, and phys.In the next episode 7 we'll limit resources with cgroups — lxc.cgroup2.memory.max and lxc.cgroup2.cpu.max in the container config, then verify with lxc-cgroup (legacy) and systemd-cgls on the host. This is how you make sure one container can't devour the host's entire RAM.