Testing FUSS with LXD

1. Introduction

FUSS is a GNU/Linux distribution based on Debian, for a Digitally Sustainable School.

fuss network architecture cur
Figure 1. Typical topology of a FUSS network

Because I don’t have resources for testing it locally, I got a VDS on contabo and tried to test FUSS with virtual machines, virtual LANs etc.

I tried different virtualization technologies, like libvirt, proxmox, OpenNebula etc. but finally decided to use LXD, for being simpler and more convenient. It can handle both containers and virtual machines, has a nice command line interface, can be managed remotely, etc.

2. Install LXD

On the server (ubuntu:20.04) I have installed LXD with snap, like this:

apt install snap
snap install lxd --channel=latest/stable
snap list
lxc list
lxd init
I have used a btrfs storage backend.
Installation on Debian

If using Debian (tested with Debian 10 "buster"), snap is provided by package snapd. Moreover the snap package core needs to be installed before lxd. The above steps for Debian are therefore:

apt install snapd
snap install core --channel=latest/stable
snap install lxd --channel=latest/stable
snap list
lxc list
lxd init

3. Connect to LXD remotely

We can connect to the LXD from a local machine, for example a laptop, and manage it remotely.

  • Install LXD on the local machine (without initializing it with lxc init):

    apt install snap
    snap install lxd --channel=latest/stable
    snap list
    lxc list
  • Enable remote connection on the server:

    lxc config set core.https_address "[::]"
    lxc config set core.trust_password some-password
  • The port 8443 on the server should be open as well:

    firewall-cmd --zone=public --add-port=8443/tcp --permanent
    firewall-cmd --reload
  • On the local machine add a remote, like this:

    lxc remote add lxd1 11.12.13.14

    This will prompt you to confirm the remote server fingerprint and then ask you for the password.

  • Make it the default remote and test it:

    lxc remote list
    lxc remote switch lxd1
    lxc remote list
    lxc ls

    Now all the lxc commands on the laptop will be executed by default on the remote LXD server.

  • Once we can connect remotely to the LXD server, we should unset core.trust_password on the server, for security reasons:

    lxc config get core.trust_password
    lxc config set core.trust_password ""
    lxc config get core.trust_password
  • On the client machine (laptop) install also virt-viewer (or spice-client-gtk), which is needed to access the VGA console of the virtual machines:

    apt install spice-client-gtk

4. Create a virtual LAN

All the containers and VMs are connected by default to a bridge, which provides them with DHCP, DNS, and allows them to connect to the internet. It acts like a gateway for the VMs.

But we also need another virtual LAN to connect the clients and the server. This LAN should not provide DHCP and should not act as a gateway for the VMs, because this should be done by the FUSS server.

lxc network list
lxc network create LAN1 --type=bridge

lxc network show LAN1
lxc network unset LAN1 ipv4.address
lxc network unset LAN1 ipv4.nat
lxc network show LAN1

We should also add this interface to the trusted zone of the firewall, otherwise the VMs connected to this network will not be able to communicate with each-other:

firewall-cmd --zone=trusted --add-interface=LAN1 --permanent
firewall-cmd --reload

5. Install the server

5.1. Create a VM

lxc init images:debian/10/cloud FUSS --vm \
    -c limits.memory=4GB -c limits.cpu=2
lxc config device override FUSS root size=60GB
lxc network attach LAN1 FUSS
lxc start FUSS
lxc ls

The first time that it is started it takes longer than usual to come up, because cloud-init does the necessary configurations (including a resize of the partition and the filesystem).

5.2. Fix the network configuration

Let’s get a shell inside the VM in order to check and fix the network configuration:

lxc exec FUSS -- bash

ip addr
ip link
ip link set enp6s0 up
dhclient enp6s0
ip addr
ip ro
ping 8.8.8.8
ping google.com

# remove cloud-init
apt purge cloud-init
apt autoremove

mv /etc/network/interfaces.d/50-cloud-init /etc/network/interfaces
cat /etc/network/interfaces
sed -i /etc/network/interfaces -e 's/enp5s0/enp6s0/'

# set a static IP to the LAN interface
cat <<EOF >> /etc/network/interfaces
auto enp5s0
iface enp5s0 inet static
    address 192.168.1.1
    netmask 255.255.255.0
EOF

# restart to make sure that network configuration works
exit
lxc stop FUSS
lxc start FUSS
lxc ls

lxc exec FUSS -- bash
ip addr
ip ro
ping 8.8.8.8
ping google.com

5.3. Install and setup the FUSS server

# install some dependencies
apt install wget gnupg2 nfs-common python ansible

# add contrib and non-free package repos
sed -i /etc/apt/sources.list -e 's/main/main contrib non-free/g'

# add the FUSS package repo
echo 'deb http://archive.fuss.bz.it/ buster main contrib non-free' \
    >> /etc/apt/sources.list
wget -qO - https://archive.fuss.bz.it/apt.key | apt-key add -

apt update
apt install fuss-server fuss-backup
fuss-server create

6. Install a client

6.1. Create a VM

We will start from a basic debian system that is created from an image (not installed from an iso).

lxc init images:debian/10/cloud client1 \
    --vm --network=LAN1 \
    -c limits.memory=2GB -c limits.cpu=1
lxc config device override client1 root size=30GB
lxc start client1
lxc ls

6.2. Install xfce-desktop

lxc exec client1 -- bash
export http_proxy=http://proxy:8080
export https_proxy=http://proxy:8080
apt install tasksel
tasksel --list-tasks
tasksel install desktop xfce-desktop
clear
exit
lxc stop client1
lxc start client1
# lxc console client1 --type=vga

6.3. Install fuss-client

lxc exec client1 -- bash
export http_proxy=http://proxy:8080
export https_proxy=http://proxy:8080

echo 'deb http://archive.fuss.bz.it/ buster main' \
    > /etc/apt/sources.list.d/archive_fuss_bz_it.list
cat /etc/apt/sources.list.d/archive_fuss_bz_it.list
apt install wget
wget -qO - https://archive.fuss.bz.it/apt.key | apt-key add -
apt update
apt install fuss-client
fuss-client --help

apt install python cups-browsed
# fuss-client -H client1 -a
# fuss-client -H client1 -a --light
fuss-client -a

6.4. Fix the screen resolution

Let’s also fix the screen resolution of the client (because it gets automatically a very big resolution):

sed -i /etc/fuss-client/display-setup-script/setDisplayResolution \
    -e 's/autorandr/#autorandr/'
sed -i /etc/fuss-client/display-setup-script/setDisplayResolution \
    -e '/#autorandr/a xrandr -s 1024x768'

6.5. Test it

Now let’s restart and test it:

exit
lxc stop client1
lxc start client1
lxc console client1 --type=vga

Login with

  • username: local-fuss-user

  • password: local-fuss-user

7. System configuration

From the client, open in browser http://proxy:13402 and login with username root and the master password that was set during installation of the server.

Now we can add groups, users, etc.

8. Using Clonezilla

8.1. Save a client image

To start Clonezilla on client1, we have to boot it from the LAN. But first we need to disable secure boot:

lxc config set client1 security.secureboot=false

Now as soon as we start the console, keep pressing ESC until we get to the BIOS the menu, then select Boot Manager, then UEFI PXEv4:

lxc stop client1 --force
lxc start client1 --console=vga
To unlock the mouse press Shift_L + F12.

Now it will show the Clonezilla menu and you can save the image of the client on the server. For more details see this page.

8.2. Install a client from image

lxc init client2 --empty --vm --network=LAN1 \
    -c limits.memory=2GB -c limits.cpu=1
lxc config device override client2 root size=30GB
lxc config set client2 security.secureboot=false
lxc start client2 --console=vga

Again, keep pressing ESC, then select Boot Manager, then UEFI PXEv4, etc.

9. Testing Captive Portal

9.1. Create a new virtual LAN

lxc network create LAN2 --type=bridge
lxc network list

lxc network show LAN2
lxc network unset LAN2 ipv4.address
lxc network unset LAN2 ipv4.nat

9.2. Attach the server to this LAN

lxc stop FUSS
lxc network attach LAN2 FUSS
lxc start FUSS
lxc network show LAN2

9.3. Fix the configuration of the server

Unfortunately, when a new interface is attached to the virtual machine, the names of the existing interfaces change, so we need to fix the configuration of the server again.

lxc exec FUSS -- bash
ip addr
ip ro

vim /etc/network/interfaces

Edit /etc/network/interfaces so that it looks like this:

auto lo
iface lo inet loopback

auto enp7s0
iface enp7s0 inet dhcp

auto enp6s0
iface enp6s0 inet static
    address 192.168.1.1
    netmask 255.255.255.0

iface enp5s0 inet manual

Here enp5s0 is the new interface that will be used for the captive portal.

We should also edit /etc/fuss-server/fuss-server.yaml and correct the interfaces, like this:

external_ifaces:
- enp7s0
internal_ifaces:
- enp6s0
hotspot_iface: ''
hotspot_network: ''

Let’s restart the server:

exit
lxc stop FUSS
lxc start FUSS

Finally, let’s also re-run the configuration scripts and restart again:

lxc exec FUSS -- bash
fuss-server upgrade
exit
lxc stop FUSS
lxc start FUSS

9.4. Install the CP

lxc exec FUSS -- bash
fuss-server cp
exit

9.5. Test it with a client

Let’s create a VM that is connected to LAN2:

lxc init images:debian/10/cloud client3 \
    --vm --network=LAN2 \
    -c limits.memory=2GB -c limits.cpu=1
lxc config device override client3 root size=20GB
lxc start client3
lxc ls

lxc exec client3 -- bash
export http_proxy=http://proxy:8080
export https_proxy=http://proxy:8080
apt install tasksel
tasksel install desktop xfce-desktop
clear
exit
lxc stop client3
lxc start client3
# lxc console client3 --type=vga

10. Appendix: Install a client from iso

This is not necessary, since installing a test client from an LXD image is much simpler, but just in case. It might be used for distros for which LXD does not provide an image.

  • Download the iso:

    debarchive='https://cdimage.debian.org/cdimage/archive'
    path='10.11.0/amd64/iso-cd'
    wget "$debarchive/$path/debian-10.11.0-amd64-netinst.iso"
  • Create an empty VM, connected to LAN1:

    lxc init client4 \
        --empty --vm --network=LAN1 \
        -c limits.memory=1GB -c limits.cpu=1
    lxc config device override client4 root size=25GB
    # lxc network attach LAN1 client4
  • Attach the iso file as a device of type disk, and make it the first boot option:

    lxc config device add client4 cdrom \
        disk source=/home/admin/debian-10.11.0-amd64-netinst.iso \
        boot.priority=1
  • Disable secure boot:

    lxc config set client4 security.secureboot=false
  • Start it with a VGA console:

    lxc start client4 --console=vga

    Or start it and access the VGA console:

    lxc start client4
    lxc console client4 --type=vga
  • Stop and remove the iso device:

    lxc stop client4
    lxc config device remove client4 cdrom

11. Appendix: Use Xpra for accessing the GUI console

Xpra is an open-source multi-platform persistent remote display server and client for forwarding applications and desktop screens. It has a much better performance, compared to X forwarding, and also has some extra nice features. We need to install it both on the server and on the client:

apt install xpra

On the server we also need to install the package virt-viewer (which provides remote-viewer):

apt install virt-viewer

Then we can start Xpra on the server, like this:

xpra start :7
DISPLAY=:7 tmux

On the client, we can attach to the Xpra server like this:

xpra attach ssh:user@example.com:7

If we use a non-standard key and port, then the command can be like this:

xpra attach ssh:user@10.11.12.13:7 \
     --ssh="ssh -i ssh-key -p 222"

Now, from the tmux on the server we can start any GUI application, and it will be displayed on the local machine:

lxc console client1 --type=vga
lxc start client2 --console=vga