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 5 months ago
.editorconfig Initial commit 5 months ago
.gitignore Initial commit 5 months ago
README.md Fixed terrible error 5 months ago

README.md

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

IPTABLES

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

ip_tables
ip6_tables

These modules should also be enabled with modprobe <module>

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

INTERFACE=internal_interface
OUT_INTERFACE=your_external_interface

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
iptables -t nat -A POSTROUTING -o $OUT_INTERFACE -j MASQUERADE

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
ip6tables -t nat -A POSTROUTING -o $OUT_INTERFACE -j MASQUERADE

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 192.168.0.0/12 subnet (small LANs) or the 10.0.0.0/6 subnets (Wide Area Networks). Avoid 192.168.[1-10].0/24 as this is usually used by routers. In this example we’ll use 192.168.253.0/24 as $SUBNET value and 192.168.253.1 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:

auto $INTERFACE
    iface $INTERFACE inet static
    bridge_ports none
    bridge_fd 0
    bridge_maxwait 0
    hwaddress ether $MAC_ADDR
    address $MACHINE_IP
    netmask 255.255.255.0
    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

DHCP

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 255.255.255.0 {
    range 192.168.253.[range_start, should be at least > 1] 192.168.253.250;
    option subnet-mask 255.255.255.0;
    option broadcast-address 255.255.255.0;
    option routers $MACHINE_IP;
}

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

LXC

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

USE_LXC_BRIDGE="false"
LXC_BRIDGE="$INTERFACE"
LXC_BRIDGE_MAC="$MAC_ADDR"
LXC_ADDR="$MACHINE_IP"
LXC_NETMASK="255.255.255.0"
LXC_NETWORK="$MACHINE_IP/24"
LXC_DHCP_RANGE="192.168.253.0,192.168.253.250"

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

Write lxc general config file

nano /etc/lxc/default.conf

# APPARMOR
lxc.apparmor.profile = generated

# Network
lxc.net.0.type = veth
lxc.net.0.flags = up
lxc.net.0.link = $INTERFACE
lxc.net.0.name = eth0
lxc.net.0.hwaddr = 00:16:3e:xx:xx:xx
lxc.net.0.mtu = 1500

# RootFS path

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

QEMU

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]
Identity=unix-group:libvirt
Action=org.libvirt.unix.manage
ResultAny=yes
ResultInactive=yes
ResultActive=yes

Finalizing

Bringing up the virtual bridge:

ifup $INTERFACE

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

DONE!

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

Enjoy!