Run accelerated GUI apps in LXC containers

Not many know you can run accelerated GUI apps in your LXC containers locally and its fairly simple to do. Yes, we are talking about Xserver with proper acceleration and audio and not a VNC based solution which would be the way to run X apps remotely.

For instance in this post by LXC developer Stephane Graber you can see how he uses this to run Google Chrome in a container locally. He uses unprivileged containers for the post.

Unprivileged containers are an exciting upstream feature of LXC but current dependencies limit them to latest versions of Ubuntu Trusty for now. Please see our using unprivileged containers guide for more.

We are going to show you how to run GUI apps in both normal and unprivileged containers. Here is a screencast of the LXC GUI container in action.

Stephane's Google Chrome example basically sets up Google Chrome in an Ubuntu container, gives the container access to the X server, and setups a script to launch Chrome. Its also exports pulse audio. Pulseaudio can be fussy and involved and may not work in all environments and distributions.

Conceptually you are exporting the dri, video and audio devices into the container and using these to run your apps. So there is no need to install X or drivers in the container. The GUI apps will use the hosts display and audio. Nice!

You can install something like Wine or Steam in a container and use it to run Windows Apps and Games isolated in their own container. Or like Stephane you can run apps like Chrome in a container to isolate it from the rest of your system. This makes sense for a number of use cases.

You can launch X apps from within the container and they will open up in a new window in your host. Or use a script on the host that executes the X app in the container and gives you a window, behaving much like any other GUI app on the system.

If you are new to LXC please head to our LXC getting started guide before trying this.

For those who are on Ubuntu Trusty and above we have a separate section and download below on how to run GUI apps in unprivileged containers.

Running GUI apps in normal containers

Browse to the Flockport container section and download the LXC GUI container. Once downloaded untar it in your LXC folder /var/lib/lxc

tar -xpJf lxcgui.tar.xz -C /var/lib/lxc --numeric-owner

Or if you are using the flockport utility

flockport get lxcgui

Before you can start the container let's take a quick look at what is making the GUI in the container possible. Head to the /var/lib/lxc/lxcgui folder and open the config file in your favorite editor. You will see the following 5 lines, and this is all you need to create you own LXC GUI container.

lxc.mount.entry = /dev/dri dev/dri none bind,optional,create=dir
lxc.mount.entry = /dev/snd dev/snd none bind,optional,create=dir
lxc.mount.entry = /tmp/.X11-unix tmp/.X11-unix none bind,optional,create=dir
lxc.mount.entry = /dev/video0 dev/video0 none bind,optional,create=file
lxc.hook.pre-start = /var/lib/lxc/lxcgui/

As you can see the configuration above line 1-4 are mounting the dri, snd, video devices in the container along with the /tmp/.X11-unix folder. This is all it takes to run accelerated GUI apps in your container.

Simples! For the GUI yes and it works smoothly. The audio is a bit involved, pulseaudio may fail weirdly on different systems. We have tested this on Debian Wheezy and Ubuntu Trusty hosts.

You will notice on the last line we are loading a script. This is for audio. Let's have a look at what it does. Open the setup-pulse script located in /var/lib/lxc/lxcgui folder.



if [ ! -e "$PULSE_PATH" ] || [ -z "$(lsof -n $PULSE_PATH 2>&1)" ]; then
    sudo -u username -i pactl load-module module-native-protocol-unix auth-anonymous=1 \

As you can see the script exports pulseaudio via a socket into the container. But trying to run the pactl command in the script as root is going to fail. That's why there is a sudo switch username. Change the 'username' in the script to your normal username on your host.

Start the container

lxc-start -n lxcgui -d

The container should start without any errors. If you get any errors it will most likely be because of pulseaudio permission issues.

We will explore pulseaudio troubleshooting solutions at the end of this article. In the interim open the container config file and comment out the lxc.hook.pre-start line, so we can proceed with the GUI.

#lxc.hook.pre-start = /var/lib/lxc/lxcgui/

Start the container after commenting out the line.

Now that the container is running we can use lxc-attach to get into it. However since we are going to run most of the GUI apps as the ubuntu user in the container, its better to ssh into the container. To do that first get the container IP

lxc-ls -f

Now let's ssh as user ubuntu into the container. In my case the container IP is Like with all Flockport ubuntu containers the pass for the ubuntu user is ubuntu Please change this after first login with the passwd ubuntu command.

ssh [email protected]

Once you are logged into the container we are ready to run some GUI apps. The container has Chromium and some utilities to test. To run GUI we first need to set some environmental variables. On the command line run the following 2 commands

export DISPLAY=:0
export PULSE_SERVER=/home/ubuntu/.pulse_socket

Please note: The default display is usually :0. If you have changed this for any reason then please change the variable as suitable.

Now let's run a couple of apps.

chromium-browser --disable-setuid-sandbox

This should launch a Chromium browser window on your host. Browse to Youtube and check if its working as expected with audio. This is actually running in your container. Chrome and Chromium do not play well with container namespaces and that's why we need to use the disable-setuid option.

Let's test an mp3


This should open up audacious. Test an mp3 to confirm audio working.

Now let's do an elementary 3D GUI test


This should give you a frame rate identical to your host, so there is no overhead running your 3D apps in the container. You can run Steam in an LXC container and see for yourself.

You can basically run any GUI app including a desktop environment, Wine Windows apps, 3D games with near zero performance penalty and additional flexibility. Awesome!

Using another X session
You can also start a separate X instance on another VT and use that for GUI apps running on your container. For instance start a separate X instance with 'startx' from another VT, and in the container change the 'export DISPLAY=:0' to 'export DISPLAY=:1' . This will launch all GUI apps started on the container on your separate X window.

Launching GUI container app with a script directly from the host
It would be a hassle to start the container, log into it, set environmental variables every time you want to run a GUI app. So you can use a script to launch the GUI app directly from the container.

For instance the script below from Stephane's Chrome guide automatically starts the container, setups environmental variables and launches Google Chrome in the container.

You can set up a link to it on your desktop to execute the script. Chrome launches in about 3 seconds from the container. To use it to launch other apps just change the CMD-LINE value.

CMD_LINE="chromium-browser --disable-setuid-sandbox $*"

if ! lxc-wait -n $CONTAINER -s RUNNING -t 0; then
lxc-start -n $CONTAINER -d
lxc-wait -n $CONTAINER -s RUNNING


lxc-attach --clear-env -n $CONTAINER -- sudo -u ubuntu -i \

if [ "$STARTED" = "true" ]; then
lxc-stop -n $CONTAINER -t 10

Running GUI apps in unprivileged containers

Unprivileged container are an exciting new feature of LXC that let non-root users run containers. However dependencies on a number of upstream packages that are not yet widely available in other distributions limit it to the latest versions of Ubuntu for now.

Please see our Using unprivileged containers guide to learn more

Please go through the guide above for general overview of running GUI apps in containers as we are only going to cover the differences for unprivileged containers below. Everything more or less remains the same apart from the changes below.

  1. Browse to the Flockport container section and download the LXC GUI unprivileged container.  Once downloaded untar it to your user's LXC folder which is usually in/home/username/.local/share/lxc
    sudo tar -xpJf lxcgui.tar.xz -C /home/username/.local/share/lxc --numeric-owner
  2. Head to the container folder, and open the container config in your favourite text editor. Notice the lxc.id_map entries. UID and GID mapping is required for unprivileged containers
    lxc.id_map = u 0 100000 1000
    lxc.id_map = g 0 100000 1000
    lxc.id_map = u 1000 1000 1
    lxc.id_map = g 1000 1000 1
    lxc.id_map = u 1001 101001 64535
    lxc.id_map = g 1001 101001 64535
  3. The lxc.hook.pre-start location in the container's config file also changes from/var/lib/lxc to your user's LXC folder
    lxc.hook.pre-start = /home/username/.local/share/lxc/lxcgui/
  4. The script in the container folder does not need to change user.
    if [ ! -e "$PULSE_PATH" ] || [ -z "$(lsof -n $PULSE_PATH 2>&1)" ]; then
        pactl load-module module-native-protocol-unix auth-anonymous=1 \
  5. Go to the Flockport lxcgui container folder. The permission for the Ubuntu user is 1000:1000. It's already set in the Flockport container but when you want to create your own unprivileged GUI container remember to run this chown command
    sudo chown -R 1000:1000 rootfs/home/ubuntu
    That's all. The container should work without issues.

Troubleshooting pulseaudio issues

Pulseaudio issues usually boil down to permissions for normal containers. This is in the context of our tests in Debian Wheezy and Ubuntu Trusty hosts. Please note pulseaudio can be fussy and difficult to troubleshoot and there could be other issues in other distributions.

In many cases the pactl script will fail to run as root and as the user. There could be permission problems in your /var/lib/lxc folder or the container preventing pactl running as your user and creating the .pulse_socket.

One work around is to change the .pulse_socket location in the setup pulse script to the hosts /tmp folder and bind mount that in the lxcgui container config script. This may help avoid a lot of permission issues for pulseaudio.

For instance let your local user (not root) create an .lxc folder in /tmp.

mkdir /tmp/.lxc

Now in the change the socket location or PULSE_PATH value to /tmp/.lxc/.pulse-socket like below, and change username to your username.


if [ ! -e "$PULSE_PATH" ] || [ -z "$(lsof -n $PULSE_PATH 2>&1)" ]; then
    sudo -u username -i pactl load-module module-native-protocol-unix auth-anonymous=1 \

The add an entry to the container's config bind mounting /tmp/.lxc to the container like below.

lxc.mount.entry = /tmp/.lxc tmp/.lxc none bind,optional,create=dir

Then if you want a run a app from within a container without using a launch script then you would export pulse-server to the tmp location ie

export PULSE_SERVER=/tmp/.lxc/.pulse-socket

This should work in most cases.

Stay updated on Flockport News

Recommended Posts

Leave a Comment


Register | Lost your password?