LXC are a great way of creating linux containers that are lightweight and can be used to sandbox applications you run inside it. Quite often it is required that your application needs to interact with other devices on the network. By default, lxc-usernet service is configured to assign an IP address to your LXC containers, using the device lxc-br0. To change this behaviour, we need to configure lxc to use our own bridge. Let’s see how we need to do that:

Important Notes
  • Please note that this article assumes that you are trying to bridge a wired interface, it takes lot more (and different) configuration to make it possible (if it is) to bridge a wireless (WiFi) interface.
Step 0: Installing prerequisites
ajinkya@metaverse:~$ sudo apt-get install ifupdown bridge-utils
Step 1: Configuring your own bridge

To know what interface we are going to bridge, you can run ip a show to see all available interfaces.

ajinkya@metaverse:~$ ip a show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
    valid_lft forever preferred_lft forever
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 52:54:00:8c:62:44 brd ff:ff:ff:ff:ff:ff
    inet 192.168.121.241/24 brd 192.168.121.255 scope global dynamic eth0
    valid_lft 2900sec preferred_lft 2900sec
    inet6 fe80::5054:ff:fe8c:6244/64 scope link 
    valid_lft forever preferred_lft forever

In my case, the interface is enp0s3 instead of eth0, so I will be using that. Open /etc/network/interfaces in the text editor of your choice, and edit it so that contents of the file look like this:

ajinkya@metaverse:~$ cat /etc/network/interfaces
auto br0
iface br0 inet dhcp
    bridge-ifaces enp0s3
    bridge-ports enp0s3
    up ifconfig enp0s3 up
iface eth0 inet manual

What we’re doing here is two things: adding our own bridge br0 and setting the eth0 interface to be configured manually. Now, to make these changes take effect, run the ifup command:

ajinkya@metaverse:~$ sudo ifup br0

At this point we have created and activated a bridge to our local network, but we haven’t configured LXC to use this bridge yet. Assuming you already have LXC installed on your machine, we proceed with the LXC configuration.

Step 3: Configuring LXC to use our bridge

We can configure this by either editing the ~/.config/lxc/default.conf or the /etc/lxc/default.conf. I wanted this configuration as a default configuration so I edited the later to look like this:

ajinkya@metaverse:~$ cat etc/lxc/default.conf
lxc.net.0.type = veth
lxc.net.0.link = br0
lxc.net.0.flags = up
lxc.net.0.hwaddr = 00:16:3e:xx:xx:xx

ajinkya@metaverse:~$ cat .config/lxc/default.conf
lxc.include = /etc/lxc/default.conf
# for unprivileged containers #output of sudo grep ajinkya /etc/sub{uid,gid} 
lxc.idmap = u 0 100000 65536
lxc.idmap = g 0 100000 65536
Step 4: Verify the results:

Creating a lxc container, and verifying the assigned IP address:

ajinkya@metaverse:~$ lxc-create -t download -n mycontainer -- -d ubuntu -r xenial -a amd64 --keyserver hkp://keyserver.ubuntu.com
Using image from local cache
Unpacking the rootfs

---
You just created an Ubuntu xenial amd64 (20210830_07:42) container.
ajinkya@metaverse:~$ lxc-start -n con2
ajinkya@metaverse:~$ lxc-ls --fancy
NAME         STATE     AUTOSTART    GROUPS  IPV4            UNPRIVILEGED
mycontainer  RUNNING   0            -       192.168.1.155   true

Refereneces: