Wrapper scripts for LXC unprivileged containers

December 22, 2022 by Roberto Puzzanghera 0 comments


A common use of the LXC containers is to isolate services like sql, ftp, httpd, mail etc. in an host server where the only user who will ever login is root. In this case, handling the unprivileged containers can be quite annoying.

In fact, one would like to have all the containers' filesystems inside the same directory, tipically /lxc, while LXC will install them in the $HOME/.local/share/lxc directory of the container's owner user. In addition, root has to administer a container as its owner user (i.e. using sudo -u <user>), by defining the configuration file and other parameters by means of a long command to type and remember. If you have many unprivileged containers and have to perform tasks like start/stop/attach frequently, your patience will come to an end very quickly.

This is the reason why at a certain point I started to write my own wrapper scripts for the most common LXC commands. Nothing special, but it seems that no one has published any tools to simplify the LXC common tasks with unprivileged containers, so it may be worth posting here what I have done.

Let's start with some examples.

Running lxc-ls as root shows all the unprivileged containers as stopped even when they are running:

root@host:~# lxc-ls --fancy 
c1       STOPPED 1         -      -    -    true          
c2       STOPPED 1         -      -    -    true          
c3       STOPPED 0         -      -    -    true          
c4       STOPPED 1         -      -    -    true          

An output like this would be more convenient:

root@host:~# lxl # which is my lxc-ls wrapper that I'll show later on
Unprivileged running containers of user user1 
c1     RUNNING 1         -  -    false         
Unprivileged running containers of user user2
c2     RUNNING 1         -  -    false         
Unprivileged running containers of user user3
c3     RUNNING 1         -  -    false         
c4     RUNNING 0         -  -    false         
c5     RUNNING 1         -  -    false         

Let's consider a few more LXC commands. Obviously lxc-start aborts the containers' startup sequence due to id mapping issues if you try to start an unprivileged container as root:

root@host:~# lxc-start -n c1 
lxc-start: c1: lxccontainer.c: wait_on_daemonized_start: 867 Received container state "ABORTING" instead of "RUNNING" 
lxc-start: c1: tools/lxc_start.c: main: 306 The container failed to start 
lxc-start: c1: tools/lxc_start.c: main: 309 To get more details, run the container in foreground mode 
lxc-start: c1: tools/lxc_start.c: main: 311 Additional information can be obtained by setting the --logfile and --logpriority options

Also, you may have to type long commands like this to attach to a container in the proper way

root@host:~# sudo -u user1 lxc-attach \
  -n c1 \
  --keep-env \
  --set-var HOSTNAME=c1.domain \
  --set-var USER=root \
  --set-var HOME=/root \
  -- /bin/bash --rcfile /etc/profile

What if you can do it with a simple command apparently with no need to become the owner of that container? For example

root@host:~# lxu c1 # container c1 UP (container is started, its owner determined dinamically)
root@host:~# lxa c1 # attaching container c1 (your env variables and /etc/profile will be passed)
root@c1:/root#      # inside the container c1
root@c1:/root# exit # exiting from the container c1
root@host:~#        # back to the host prompt again
root@host:~# lxd c1 # container c1 DOWN

Let's see an example where the creation of a container is made simple. This is how I create a Slackware 15.0 container owned by the user user1 (unprivileged), and with an ip address I want to use my personal list of packages (SLACKPKG_TEMPLATE) and also a personal LXC template (LXC_TEMPLATE) to perform this task:

SLACKPKG_TEMPLATE=my_15.0_template \
LXC_TEMPLATE=my_lxc_template \
RELEASE=15.0 \
my_lxc-create -n <container_name> -i -u user1

or simply

my_lxc-create -n <container_name> -i -u user1

if you set your defaults parameters inside the script. Of course, if you're not a Slackware user, you can load the LXC template for your distro and use this same script.

Creating a container owned by root is even simpler. It will be sufficient not to specify any user (-u):

my_lxc-create -n <container_name> -i

...and so on for other common LXC commands like lxc-console, lxc-destroy, lxc-copy etc.

I'll show also below how to install all of your containers (unprivileged included!) in the same directory, say /lxc, rather than installing each one in the owner's home directory.

Which distro?

My wrapper scripts will work both for privileged containers (owned by root itself) and unprivileged containers. I wrote them for my Slackware linux distro, but I think that they can be useful for any other Linux flavors, as they can be easily adapted.

This is the configuration where I tested my scripts:

  • Slackware Linux 15.0
  • LXC 4.0.11
  • libcgroup 0.41


If you are a Slackware user and you are looking for unprivileged containers documentation, you should start by reading the Christoph Willing's guide. Thanks to him I migrated from Linux-VServer, which is no longer maintained. The Cristoph Willing's guide explains in detail how to use libcgroup to run unprivileged containers and it's the starting point on this topic. In the following I will assume that you are already familiar with the creation and configuration of unprivileged containers. In fact, my installation is mostly an automation of the tasks explained in that guide.

Also the Stéphane Graber's articles are a suitable reading at the beginning.

A special credit is addressed to Matteo Bernardini (Ponce) for his great support to the Slackware community, not only concerning LXC.

Add a comment

Recent comments
Recent posts

RSS feeds