These instructions are for setting up a privileged LXC container with
a Haskell development environment. The container runs Debian GNU/Linux
10 (code-named Buster). One can connect to the container via SSH and
VNC. When connected via VNC, the clipboard is shared between the
container and the host machine thanks to the autocutsel
tool.
LXC (Linux Containers) is a virtualization method specific to operating systems based on the Linux kernel. Therefore, you need to have a Linux-based operating system to follow these instructions. Furthermore, the instructions are written for the GNU/Linux Debian Buster operating system, though they should be applicable to other GNU/Linux distributions (possibly with minor modifications).
These are instructions for LXC 3.0.3 in Debian GNU/Linux Buster. Follow the steps tagged “(LVM)” only if you use Logical Volume Management (LVM), in which case you should skip steps tagged (DIR).
- Choose a name for the LXC container. In this running example
buster-2
will be used:export CNAME=buster-2
- Create a list of Debian packages to install. The list is stored in an
environment variable:
export PKGS=sudo,emacs,xfonts-base,tightvncserver,xfce4,xfce4-goodies,xfce4-pulseaudio-plugin,pavucontrol,x11-xserver-utils,dbus-x11,haskell-platform,haskell-stack,elpa-haskell-mode,elpa-smex,firefox-esr,xserver-xorg-core,curl,autocutsel,git,unar,rsync,bzip2,wget,hlint
- (LVM) Choose an LVM volume group (set to the group you have on your host
machine):
export VGNAME=howard-vg
- (LVM) Choose an LVM volume:
export LVNAME=$CNAME
- (LVM) Choose the size of the container’s root file system:
export FSSIZE=50G
- (LVM) To create a privileged container named “buster-2” with several
things installed, where the root file system is stored in an LVM volume:
sudo lxc-create --name $CNAME --bdev lvm --lvname $LVNAME --vgname $VGNAME --fssize $FSSIZE --template debian -- --release buster --package $PKGS
- (DIR) To create a privileged container with several things installed,
where the root file system is stored in a directory:
sudo lxc-create --name $CNAME --template debian -- --release buster --package $PKGS
- Start the container:
sudo lxc-start --name $CNAME
- Set a password for the root user:
sudo lxc-attach --name $CNAME passwd
- Install the packages given bz the PKGS variable:
sudo lxc-attach --name $CNAME -- apt install $(echo $PKGS | tr "," " ")
- Add a user
dev
to the container:sudo lxc-attach --name $CNAME -- useradd -m -s /bin/bash dev
- Set the password for the
dev
user:sudo lxc-attach --name $CNAME -- passwd dev
- Add
dev
to thesudo
group for the root privileges:sudo lxc-attach --name $CNAME -- usermod -a -G sudo dev
- (Something here is missing about
TTY
; it is resolved by adding thedev
user viavisudo
). - Copy the public SSH key of your user on the host machine to the
dev
user in the container:ssh-copy-id -i ~/.ssh/id_rsa.pub dev@192.168.122.195
- Start the VNC server as the
dev
user:sudo lxc-attach --name $CNAME -- su - dev -c vncserver
This will ask for a password so create one.
- Kill the VNC server:
sudo lxc-attach --name $CNAME -- su - dev -c "vncserver -kill :1"
- Put the following in
~/.vnc/xstartup
in the container:#!/bin/bash xrdb $HOME/.Xresources autocutsel -fork startxfce4 &
- Create a
systemd
service in/etc/systemd/system/vncserver@1.service
in the container:[Unit] Description=Remote desktop service (VNC) After=syslog.target network.target [Service] Type=forking User=dev # Clean any existing files in /tmp/.X11-unix environment ExecStartPre=/bin/bash -c '/usr/bin/vncserver -kill %i > /dev/null 2>&1 || :' ExecStart=/usr/bin/vncserver -geometry 2320x1305 ExecStop=/usr/bin/vncserver -kill %i [Install] WantedBy=multi-user.target
- Reload a service daemon, enable the service and start it:
sudo systemctl daemon-reload sudo systemctl enable vncserver@1.service sudo systemctl start vncserver@1.service
- Install a VNC viewer on the host machine. I recommend Remmina, though
others will work. GNOME’s Remote Desktop Viewer captures certain
keystrokes such as Ctrl+W, which means they cannot be used in the VNC
session; this is why I decided to go with another VNC viewer, namely
Remmina.
sudo apt-get install remmina remmina-plugin-vnc
- Start a VNC viewer on the host machine. Provide the container’s IP address and a port (the port is typically 5901).
One might want to install the Nix package manager because a number of Haskell projects use it as a build system. Unfortunately, there is no official Debian binary package for Nix. Therefore, we will build the package ourselves from an unofficial Debian source package. To install the Nix package manager in the LXC container:
- Install
git-buildpackage
on the host:sudo apt-get install git-buildpackage
- Create a Debian GNU/Linux Buster image that will be used for building the
package for Nix:
DIST=buster git-pbuilder create
- Get the unofficial Debian source package from a Git repository:
git clone https://github.com/KaiHa/nix-debian.git cd nix-debian
- Build a Debian binary package for Nix:
gbp buildpackage --git-pbuilder --git-dist=buster
- Find two Debian packages in
../nix.deb-export/
. My host machine is theamd64
architecture, so for Nix 2.2.1 the packages arenix_2.2.1-1_amd64.deb
andnix-dbgsym_2.2.1-1_amd64.deb
. - Copy the
nix_2.2.1-1_amd64.deb
package to the LXC container:rsync -a --progress *deb dev@192.168.122.142:/tmp/
- In the LXC container install dependencies for the binary package for Nix:
sudo lxc-attach --name $CNAME -- su - dev -c "sudo apt-get install -y libdbd-sqlite3-perl libwww-curl-perl libboost-context1.67.0 libbrotli1 libreadline7 libsodium23 perl-dbdabi-94 readline-common"
- Finally install the
nix_2.2.1-1_amd64.deb
package:sudo lxc-attach --name $CNAME -- su - dev -c "sudo dpkg -i /tmp/nix_2.2.1-1_amd64.deb"
- Add the following to
/etc/nix/nix.conf
in the container (create the file if it does not exist):build-use-sandbox = false
- To have
nixpkgs
working properly, run the following in the container:nix-channel --add https://nixos.org/channels/nixpkgs-unstable nix-channel --update
- Stop the container. On the host machine add the following line to
/etc/sysctl.d/80-lxc-userns.conf
(create the file if it does not exist):kernel.unprivileged_userns_clone=1
- Restart
sysctl
on the host:sudo sysctl --system
- Start the LXC container:
sudo lxc-start --name $CNAME
- https://salsa.debian.org/debian/nix
- This is referenced by the currently used Debian source package for Nix.
- The default is a 20 GB root partition
/
, which can be too little, especially when Nix is used. When creating a container withlxc-create
, there is an option--bdev
that can take “lvm” as a value and further arguments can be provided, as explained in the man pages oflxc-create
.- [2019-08-28 wed]: I am not completely sure, but it might be the case
that I have to create LVM logical volumes via a live boot from
USB. When booted regularly from the disk, I attempted to run
sudo lvcreate -L 50G -n buster-2 howard-vg
, but I get this:Insufficient free space: 12800 extents needed, but only 0 available
yet there is 173 GB of free space in the volume group according to the output of
sudo vgdisplay
.- On [2019-10-23 sri] I confirmed this is really the case: I had to boot a live USB to create a new logical volume.
- [2019-08-28 wed]: I am not completely sure, but it might be the case
that I have to create LVM logical volumes via a live boot from
USB. When booted regularly from the disk, I attempted to run
- Maybe there is something to configure in
/etc/X11
as generated by thegtf
tool from thexserver-xorg-core
package with ModeLine and a dummy driver.
To the extent possible under law, Marko Dimjašević has waived all copyright and related or neighboring rights to this project (CC0).