Configuring LXC and QEMU environment
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Tanya d8ef78aa77 Fixed terrible error 1 year ago
.editorconfig Initial commit 1 year ago
.gitignore Initial commit 1 year ago Fixed terrible error 1 year ago

Setting up QEMU/LXC virtualization on debian derivates

This tutorial considers you're using at least Debian 10 buster or similar ALL the command in this article MUST be made as root In config files substitute variables with their actual value


Note: this is for people with no UFW or firewall abstractions disabled, if you need to reimplement these you're on your own

Open /etc/sysctl.conf, both net.ipv4.ip_forward and net.ipv6.conf.all.forwarding, they both must be set to 1

Install iptables-persistent package

Create /etc/modules-load.d/ip_tables-fixes.conf and write inside it


These modules should also be enabled with modprobe <module>

Choose an interface name for your virtual network and your output interface name


Good names for the internal interface are something that express a virutal interface, vir0, virt0 and yadda yadda. If you're confused about which interface you should put as OUT_INTERFACE just write /sbin/route and pick the iface signed with default

iptables -P FORWARD DROP
iptables -t filter -A FORWARD -i $INTERFACE -o $OUT_INTERFACE -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -t filter -A FORWARD -i $OUT_INTERFACE -o $INTERFACE -j ACCEPT

ip6tables -P FORWARD DROP
ip6tables -t filter -A FORWARD -i $INTERFACE -o $OUT_INTERFACE -m state --state RELATED,ESTABLISHED -j ACCEPT
ip6tables -t filter -A FORWARD -i $OUT_INTERFACE -o $INTERFACE -j ACCEPT

These commands ensure the default policy for forward chain is DROP (you don't want the outside world to access your virtual interface, your VMs and your containers, right?), that packets from this interface are forwarded to the outside world and that they assume the machine's external IP upon exiting your system Let's save the changes

/usr/sbin/netfilter-persistent save

You may want to study in-depth iptables and use it as a firewall, but it's not covered in the scope of this article

Virtual Interface

Let's build our internal interface! First we need to enable the veth module

Create /etc/modules-load.d/lxc-fixes.conf and write inside veth, save and exit, then modprobe the modules as above, this will enable the virtual ethernet module right now and on bootup

Choose the range of ips that will be contained inside this interface. You must choose either from the subnet (small LANs) or the subnets (Wide Area Networks). Avoid 192.168.[1-10].0/24 as this is usually used by routers. In this example we'll use as $SUBNET value and as machine's ip inside this subnet ($MACHINE_IP)

Do the same for IPv6, here are some confortable defaults: fc00:0:0:fb::1 as $IPV6_SUBNET and fc00:0:0:fb::1/64 as $IPV6_NETMASK

You must choose also a mac address, it can contain anything as long it's hexadecimal [0-9a-f] and it respects this form: 8e:81:fb:XX:XX:XX (substitute appropriately), we'll call it $MAC_ADDR

Create the file that will store your virtual interface bringup settings

nano /etc/network/interfaces.d/$INTERFACE

Then write:

    iface $INTERFACE inet static
    bridge_ports none
    bridge_fd 0
    bridge_maxwait 0
    hwaddress ether $MAC_ADDR
    address $MACHINE_IP
    up /bin/ip -6 addr add $IPV6_NETMASK dev $IFACE label $IFACE
    up echo 0 > /proc/sys/net/ipv6/conf/$IFACE/accept_dad
    up mkdir -p /run/lxc
    up touch /run/lxc/network_up
    up rm -rf /run/lxc/network_down
    down /bin/ip -6 addr del $IPV6_NETMASK dev $IFACE label $IFACE
    down touch /run/lxc/network_down
    down rm -rf /run/lxc/network_up

Note: $IFACE is the only "variable" that must be kept as-is. It's interpreted by ifupdown when it brings up interfaces The extra lines are for making lxc-net know we already have our interface, just in case someone has the nice idea of executing it manually


Our interface is ready to roar, but it misses something: a DHCP server If you are out the loop, a DHCP server is a service which when asked, gives IPs to connected clients and identifies them through their MAC Address. Let's install it:

apt-get install isc-dhcp-server

and change its defaults:

nano /etc/default/isc-dhcp-server

uncomment DHCPDv4_CONF, DHCPDv4_PID and put our $INTERFACE into uncommented INTERFACESv4

Put this inside /etc/dhcp/dhcpd.conf:

ignore client-updates;
include "/etc/dhcp/ifaces/$INTERFACE.conf";

Now let's define our interface:

mkdir /etc/dhcp/ifaces
nano /etc/dhcp/ifaces/$INTERFACE.conf

subnet $MACHINE_IP[change last number in 0] netmask {
    range 192.168.253.[range_start, should be at least > 1];
    option subnet-mask;
    option broadcast-address;
    option routers $MACHINE_IP;

Substitute range IPs with those representing your network and you're set


Install LXC Packages

apt-get install lxc libvirt-clients libpam-cgfs bridge-utils python3-lxc

Disable lxc-net

update-rc.d lxc-net remove

Write lxc-net config file

nano /etc/default/lxc-net


Substitute the two ips with the same you've used in DHCP interface definition

Write lxc general config file

nano /etc/lxc/default.conf

lxc.apparmor.profile = generated

# Network = veth = up = $INTERFACE = eth0 = 00:16:3e:xx:xx:xx = 1500

# RootFS path

All set. You're now able to create new containers with lxc-create -n <name> -t <distro> -- -r <distro_version>


Install QEMU

apt-get install qemu qemu-kvm virt-viewer libvirt-daemon

Enable VM utilization from current user

nano /etc/polkit-1/localauthority/50-local.d/50-libvirt-local-access.pkla

[Allow group libvirt libvirt management permissions]


Bringing up the virtual bridge:


Loading firewall rules:

service netfilter-persistent restart

Starting the DHCP server:

service isc-dhcp-server start

Adding current user to libvirt group

adduser <your_user_here> libvirt

Can't quite remember if QEMU settings are applied straight after polkit insertion, probably they do If they don't and you're asked for administration password, reboot and report it


All set! For using your bridge in QEMU virt-manager, you must set $INTERFACE in Network > Specify name of shared device > Bridge name