How to easily run graphics-accelerated GUI apps in LXD containers on your Ubuntu desktop

Note: This post is about LXD containers. These are system containers, which means they are similar to Docker but behave somewhat like virtual machines. When you start a LXD (lex-dee) container, you are starting a new system on your computer, with its own IP address and all. You can get LXD as a snap package. Go to install snap support, then sudo snap install lxd. See also Getting Started with LXD.

In that older post, we saw how to manually setup a LXD container in order to run GUI apps from there, and have them appear on our X11 desktop.

In this post, we are going to see how to easily set up our LXD installation in order to be able to launch on demand containers that we can run GUI apps in them. First, we will see the instructions and explanation on how to use them. Then, we explain these instructions in detail. And finally we go through some common troubleshooting issues.


The following have been tested with

  • the host runs either Ubuntu 18.04 or Ubuntu 16.04
  • the containers run either Ubuntu 18.04 or Ubuntu 16.04 or Ubuntu 14.04 or Ubuntu 12.04
  • LXD version 3.0 or newer (probably works fine with LXD 2.0.8+ as well)
  • works fine with either the LXD deb package or the LXD snap package
    To verify whether you run the deb package or the snap package, run the command which lxd

    $ which lxd
    /usr/bin/lxd              # NOTE: you have the deb package of LXD
    /snap/bin/lxd             # NOTE: you have the snap package of LXD

These instructions should work with other distributions as well. Read further below on the detailed explanation of the instructions in order to adapt to your favorite distribution.

In the following, we see the two steps to set up our system so that we can then create GUI containers on demand. Step 1 is only required if you run the deb package of LXD. In subsequent sections, we see an explanation of the instructions so that you can easily port of other Linux distributions. At the end, have a look at the Troubleshooting section to see commons issues and how to solve them.

Step 1 Mapping the user ID of the host to the container

This step is only required if you run the deb package of LXD. If instead you have the snap package of LXD, skip to Step 2.

Run on the host (only once) the following command (source): (Note: if you do not use the bash shell, then $UID is the user-id of the current user. You can replace $UID with $(id -u) in that case.)

$ echo "root:$UID:1" | sudo tee -a /etc/subuid /etc/subgid
[sudo] password for myusername: 

The command appends a new entry in both the /etc/subuid and /etc/subgid subordinate UID/GID files. It allows the LXD service (that runs as root) to remap our user’s ID ($UID, from the host) as requested.

Step 2 Creating the gui LXD profile

You will be creating a LXD profile with settings relevant to launching GUI applications. All configuration that you did manually at the old How to run graphics-accelerated GUI apps in LXD containers on your Ubuntu desktop post, are now included in a single LXD profile.

Download the file lxdguiprofile.txt and save it locally.

Then, create an empty LXD profile with the name gui. Finally, put the downloaded profile configuration into the newly created gui profile.

$ lxc profile create gui
Profile gui created

$ cat lxdguiprofile.txt | lxc profile edit gui

Verify that the profile has been created.

$ lxc profile list
| NAME          | USED BY |
| default       | 10      |
| gui           | 0       |

You can view the contents of the profile gui by running lxc profile show gui. A discussion on the profile contents is found two sections below.

Launching gui containers in LXD

Let’s launch some GUI containers in LXD. The gui LXD profile only has instructions related to running GUI applications. Due to this, you need to specify first another profile with information on the disk and the networking. The default LXD profile is suitable for this. You may use a bridge profile or macvlan profile instead.

$ lxc launch --profile default --profile gui ubuntu:18.04 gui1804
Creating gui1804
Starting gui1804

$ lxc launch --profile default --profile gui ubuntu:16.04 gui1604
Creating gui1604
Starting gui1604

You have launched two containers, with Ubuntu 18.04 and Ubuntu 16.04 respectively. You have specified two LXD profiles, default and gui. This means that the new container gets configuration from default, then from gui.

Next, make sure that the containers are up and running. In the LXD profile there are instructions to install additional packages automatically for us. That takes time. Here is how we check. We get a shell as the non-root account ubuntu in the container, and tail the end of the cloud-init log file. It says that it has 0 failures, it took (on this case) about 22 seconds to complete, and the startup was successful.

$ lxc exec gui1804 -- sudo --user ubuntu --login
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.

ubuntu@gui1804:~$ tail -6 /var/log/cloud-init.log 
2018-06-25 13:11:54,175 -[DEBUG]: Ran 20 modules with 0 failures
2018-06-25 13:11:54,176 -[DEBUG]: Creating symbolic link from '/run/cloud-init/result.json' => '../../var/lib/cloud/data/result.json'
2018-06-25 13:11:54,176 -[DEBUG]: Reading from /proc/uptime (quiet=False)
2018-06-25 13:11:54,177 -[DEBUG]: Read 12 bytes from /proc/uptime
2018-06-25 13:11:54,177 -[DEBUG]: cloud-init mode 'modules' took 21.822 seconds (22.00)
2018-06-25 13:11:54,177 -[DEBUG]: finish: modules-final: SUCCESS: running modules for final

Subsequently, run glxgears to test graphics hardware acceleration. You may also try glxinfo.

ubuntu@gui1804:~$ glxgears 
366 frames in 5.0 seconds = 73.161 FPS
300 frames in 5.0 seconds = 59.999 FPS
300 frames in 5.0 seconds = 60.000 FPS

XIO: fatal IO error 11 (Resource temporarily unavailable) on X server ":0"
after 1047 requests (42 known processed) with 0 events remaining.

Finally, test the audio and whether Pulseaudio works.

ubuntu@gui1804:~$ pactl info
Server String: unix:/tmp/.pulse-native
Library Protocol Version: 32
Server Protocol Version: 32
Is Local: yes
Client Index: 12
Tile Size: 65472
User Name: myusername
Host Name: mycomputer
Server Name: pulseaudio
Server Version: 8.0
Default Sample Specification: s16le 2ch 44100Hz
Default Channel Map: front-left,front-right
Default Sink: noechosink
Default Source: noechosource
Cookie: 4a83:ba9b

Audio works fine as well. If there was an error, the pactl info command would have showed it here.

Now, you can install deb packages of GUI programs in these containers, such as Firefox, Chromium browser, Chrome, Steam and so on. Installing snap packages inside the containers and having them appear on your desktop is not supported yet. That would require LXD 3.2 and a few modifications to the profile (not covered in this post).

In the following subsections, we see some useful examples.

Running a separate instance of a program

We are creating a GUI container in order to run Firefox from it. It will be a separate and independent instance of Firefox compared to our desktop browser.

$ lxc launch --profile default --profile gui ubuntu:18.04 firefox
Creating firefox
Starting firefox

$ lxc exec firefox -- sudo --user ubuntu --login
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.

ubuntu@firefox:~$ sudo apt install firefox
ubuntu@firefox:~$ firefox

Running old programs in old versions of Ubuntu

redet is a Tcl/Tk program that does not run easily on Ubuntu 18.04 because it needs some extra packaging effort for newer versions of Ubuntu. One option would have been to install Ubuntu 12.04 in VirtualBox. Here is the LXD alternative: We launch an Ubuntu 12.04 container, then install redet and finally run it. It took around 40 seconds from launch to GUI.

$ lxc launch --profile default --profile gui ubuntu:12.04 redet
Creating redet
Starting redet

$ lxc exec redet -- sudo su -l ubuntu
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.

ubuntu@redet:~$ sudo apt-get install redet
...ubuntu@redet:~$ redet
Redet 8.26
Copyright (C) 2003-2008 William J. Poser.
This program is free software; you can redistribute it
and/or modify it under the terms of version 3 of the GNU General
Public License as published by the Free Software Foundation.

Running Windows programs with Wine

When you need to run a particular Windows program with Wine, you would prefer not to install all the dependencies on your desktop Ubuntu but rather have them confined into a container. Here is how to do this. We launch a new GUI container called wine, then install Wine (package wine-stable, Wine version 3.0) according to the official instructions, and finally install a Windows program. We can reuse the same container to install more Windows programs.

$ lxc launch --profile default --profile gui ubuntu:18.04 wine
Creating wine
Starting wine

$ lxc ubuntu wine
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.

ubuntu@wine:~$ sudo dpkg --add-architecture i386 
ubuntu@wine:~$ wget -nc

ubuntu@wine:~$ sudo apt-key add Release.key
ubuntu@wine:~$ sudo apt-add-repository
ubuntu@wine:~$ sudo apt install wine-stable

Then, you can set up the environment to run winetricks in order to easily install Windows programs.

ubuntu@wine:~$ echo export PATH=\"/opt/wine-stable/bin:\$PATH\" >> ~/.profile 
ubuntu@wine:~$ source ~/.profile 
ubuntu@wine:~$ which wine
ubuntu@wine:~$ sudo apt install zenity unzip cabextract
ubuntu@wine:~$ wget
ubuntu@wine:~$ chmod +x winetricks 
ubuntu@wine:~$ ./winetricks

We have installed Internet Explorer through winetricks and here it is,

ubuntu@wine:~$ wine .wine/drive_c/Program\ Files/Internet\ Explorer/iexplore.exe

A closer look into the gui LXD profile

Let’s have a closer look at the gui LXD profile contents.

$ lxc profile show gui
  environment.DISPLAY: :0
  raw.idmap: both 1000 1000
  user.user-data: |
      - 'sed -i "s/; enable-shm = yes/enable-shm = no/g" /etc/pulse/client.conf'
      - 'echo export PULSE_SERVER=unix:/tmp/.pulse-native | tee --append /home/ubuntu/.profile'
      - x11-apps
      - mesa-utils
      - pulseaudio
description: GUI LXD profile
    path: /tmp/.pulse-native
    source: /run/user/1000/pulse/native
    type: disk
    path: /tmp/.X11-unix/X0
    source: /tmp/.X11-unix/X0
    type: disk
    type: gpu
    name: gui
- /1.0/containers/gui1804

The config node

First, there is environment.DISPLAY, with the default value :0. This is an environment variable, and has the value of the default display of the host’s X11 server. You may have to change this to :1 if you have more displays (for example, multiple graphics cards). Here is how to set this to :1,

$ lxc profile set gui environment.DISPLAY :1

The raw.idmap has a value that refers to the sets of $UID/$GID of the non-root user on the host and in the container. By default on Ubuntu the default ID for the first non-root account is 1000 (both user ID and group ID). This is necessary for the bind-mounting of sockets of the host to the container. If you need to change it, here is how to do it. Because we use the both keyword, the first number (i.e. 1000) is the $UID/$GID on the host, and the second number (i.e. 1001) is the $UID/$GID of the non-user account in the container.

$ lxc profile set gui raw.idmap "both 1000 1001"

The user.user-data are instructions for cloud-init. The LXD container images from the ubuntu: repository support cloud-init, and we use it to pass configuration to the newly created container.

In cloud-init, we use runcmd to run two commands. First, disable shm in PulseAudio so that it uses an alternative that works in LXD. Second, set the PULSE_SERVER environment variable to the Unix socket that have bind-mounted in the devices node.

In packages, we get cloud-init to install for us the minimal packages to get X11 libraries, Mesa libraries and the PulseAudio client libraries. On top of that, we get cloud-init to run apt update for us so that when we get into the container, we can install packages straight away.

The description node

This node has the description text of the LXD profile.

The devices node

The devices node has two Unix sockets, one for PulseAudio and one for X11.

It also gives access to the gpu device.

The used_by node

We do not edit this node, it will include the created containers that have this profile.

Creating shortcuts to the gui container applications

If you want to run Internet Exploerr from the container, you can simply run from a terminal window the following,

$ lxc exec wine -- sudo --login --user ubuntu /opt/wine-stable/bin/wine /home/ubuntu/.wine/drive_c/Program\ Files/Internet\ Explorer/iexplore.exe

and that’s it.

To make a shortcut, create the following .desktop file on the host and finally use desktop-file-install to install into /usr/share/applications/.

$ cat > lxd-iexplore.desktop
[Desktop Entry]
Name=Internet Explorer in LXD
Comment=Access the Internet with Wine Internet Explorer through a LXD container
Exec=lxc exec wine -- sudo --login --user ubuntu /opt/wine-stable/bin/wine /home/ubuntu/.wine/drive_c/Program\ Files/Internet\ Explorer/iexplore.exe %U
$ sudo desktop-file-install lxd-iexplore.desktop

This is how the (randomly-selected) icon looks like in a File Manager.

Here is the icon on the Launcher. Simply drag from the File Manager and drop to the Launcher in order to get the application at your fingertips.


Error sudo: unknown user: ubuntu and unable to initialize policy plugin

You get this error when you create a container and then very quickly try to connect to it with a shell. Here is how it looks.

$ lxc launch --profile default --profile gui ubuntu:18.04 gui1804
Creating gui1804
Starting gui1804

$ lxc ubuntu gui1804
sudo: unknown user: ubuntu
sudo: unable to initialize policy plugin

The Ubuntu container images come with cloud-init instructions that, among others, create the non-root account ubuntu. When you launch a container, it takes several seconds to start the runtime and then execute the cloud-init instructions. You get this error when you try to connect too soon, when the ubuntu account has not been created yet. You can try again until the account is created.

Error Pulseaudio, Connection failure: Connection refused

You got a shell in the newly created container, but when you try to use the audio, you get Connection refused. Here is how it looks,

ubuntu@gui1804:~$ pactl info
Connection failure: Connection refused

The cloud-init instructions in the gui LXD profile have commands to install packages and commands to setup the PulseAudio environment variable. The sequence is to install first the packages, and then add PULSE_SERVER in the ~/.profile. This means that if you get a shell in the container before cloud-init has completed, you have missed the addition of PULSE_SERVER in ~/.profile. As a solution, you can log out and then connect again. Or, do

ubuntu@gui1804:~$ source ~/.profile
ubuntu@gui1804:~$ pactl info
Server String: unix:/tmp/.pulse-native
Library Protocol Version: 32
Server Protocol Version: 32

I have an existing container, can I make it a gui container?

Yes, you can. You can assign profiles to a container, then restart the container. Here is how,

$ lxc profile assign oldcontainer default,gui
Profiles default,gui applied to oldcontainer
$ lxc restart oldcontainer

I have a gui container, can I remove the gui profile from it?

Yes, by assigning the default or any other profile. Then, restart the container.

$ lxc profile assign gui1804 default
Profiles default applied to gui1804
$ lxc restart gui1804

More errors

Report in the comments any issues that you encounter and I will be adding here.

I tested this on both Intel and AMD GPUs and they worked fine for me. For NVidia there might be some additional issues, so I would rather investigate again rather than copy from the old post.


A year ago, I wrote the first version of the post on how to run GUI application in a LXD system container. I had put together older sources from the Internet while writing that post. In this post, I used the comments and feedback of last year’s post to automate the process and make it less error-prone.

Up to now, we have seen how to reuse the existing display of our desktop for any GUI apps running in a container. The downside is that a malicious application in a container can attack the desktop because X11. One solution is to use Xephyr instead of our desktop’s DISPLAY (:0). It is elemental to adapt this post to use Xephyr. However, in terms of usability, it would be ideal to create some sort of VirtualBox clone that would use LXD containers instead of VMs to launch Linux distributions. In this VirtualBox clone, it would be easy to select whether we want to output in a window on the desktop’s DISPLAY or in a Xephyr window. Also, in a Xephyr window we can launch a window manager, therefore we can have a proper Linux desktop environment in a window.

Permanent link to this article:


8 pings

Skip to comment form

  1. Simos,
    Trying to follow [New post] How to easily run graphics-accelerated GUI apps in LXD containers on your Ubuntu desktop.

    I am on an Ubuntu 18.04 system

    SNAP LXD version 3.1

    I get to these steps and get an error:

    $ lxc launch –profile default –profile gui ubuntu:18.04 gui1
    Creating gui1
    Starting gui1
    Error: Failed to create devices path: open /dev/dri/controlD64: no such file or directory

    I don’t think I skipped any steps exept Step 1 but instructions said that Step 1 was only if you were not running SNAP LXD.

    $ snap –version
    snap 2.33
    snapd 2.33
    series 16
    ubuntu 18.04
    kernel 4.13.0-25-generic

    anyway… fyi.

    1. Hi Brian,

      There is this recent report,
      which was fixed a few days ago.
      If you are comfortable in switching to the candidate snap, you can see whether it gets resolved.

      Which graphics card do you have?

      1. My graphics card is nothing potent…

        NVIDIA Corporation GM206 [GeForce GTX 960

      2. I changed to the “candidate” lxd snap and had the same failure.. At least you pointing me to the bug allows me to watch for it getting fixed.


        • bmullan on June 26, 2018 at 12:46

        Simos… I tried this guide on a different 18.04 system (still using SNAP LXD) and it all worked… awesome job!
        Now I have to figure out I why the other system has that failure I reported…

  2. I should have also showed that on my system /dev/dri only contains the following:

    $ ls /dev/dri
    by-path card0 renderD128

  3. Brilliant tips here! Managed to install myslq-workbench inside the percona cluster LXD container as it would not allow access other than local host and using your gui profile tip and also how to assign that to the existing container I now have x-ray vision into my Broken OpenStack (brought up with conjure-up OpenStack LXD but facing some neutron issues! Many thanks indeed 🙂

    1. Thanks!
      Glad it worked.

    • Michał "phoe" Herda on June 27, 2018 at 07:33
    • Reply

    Hey! I will try checking this out on a Debian host with LXD from snap while running Debian or Ubuntu containers, and possibly write a follow-up with my findings.

    1. Once you make this, please post the link here in order to have a look at it.

    • crash on July 24, 2018 at 20:11
    • Reply

    Tried this on ubuntu 16.04 host with deb lxd 3.0.1 and ubuntu 16.04 client. I have 2x nvidia cards and my monitors are on gpu0 and x screen 0.

    ubuntu@test:~$ glxinfo -B
    No protocol specified
    Error: unable to open display :0

    Installing nvidia drivers does not change this error.

    For audio, I get a similar error…

    ubuntu@test:~$ pactl info
    No protocol specified
    xcb_connection_has_error() returned true
    Server String: unix:/tmp/.pulse-native
    Library Protocol Version: 30
    Server Protocol Version: 30
    Is Local: yes
    Client Index: 152
    Tile Size: 65472
    User Name:
    Host Name:
    Server Name: pulseaudio
    Server Version: 8.0
    Default Sample Specification: s16le 2ch 44100Hz
    Default Channel Map: front-left,front-right
    Default Sink: alsa_output.pci-0000_31_00.3.analog-stereo
    Default Source: alsa_input.pci-0000_31_00.3.analog-stereo
    Cookie: b044:1390

    Any thoughts?

      • Pilou on September 6, 2018 at 14:35
      • Reply


      Try the following command on the host:
      $ xhost +local:

      The container should now be allowed to use the :0 display.

  4. It is an NVidia issue, which requires a bit of extra work. I do not have such a GPU so I did not add the full details from the older guide because I do not know which ones are actually still needed.

    Have a look at and specifically the section about configuring the GPU. There are some extra instructions on setting the UID and GID of the GPU device. In addition, look into the comments about NVidia. There are more information about what is needed.

    Please write back whether it worked or not.

    The audio is fine and you can play music from the container with any application that uses PulseAudio.
    The error that you see there, is from “pactl info” (i.e. PulseAudio client library) attempting to get the PulseAudio server details from the X server. PulseAudio does that because it has found the socket /tmp/.X11-unix/X0 and made an attempt to read it. However, our audio setup is sufficient to play audio and does not depend on the access of /tmp/.X11-unix/X0
    You can play music with any CLI music player, like “mplayer”.

    • Ingvar on August 27, 2018 at 12:48
    • Reply

    Hello Simos,

    I followed your guide and managed to run firefox from an ubuntu guest, however, my application is only supported on centos and I do not manage to get even glxgears running:

    Error: couldn’t open display (null)

    When trying to run glxgears through ssh X11-Forwarding, I get this error:


    debug1: confirm x11

    libGL error: unable to load driver:

    libGL error: failed to load driver: swrast

    X Error of failed request: BadValue (integer parameter out of range for operation)

    Major opcode of failed request: 154 (GLX)

    Minor opcode of failed request: 3 (X_GLXCreateContext)

    Value in failed request: 0x0

    Serial number of failed request: 37

    Current serial number in output stream: 39

    My host OS is fedora 28. I installed stable lxd 3 via snapd.

    Any idea hint what is / can solve the problem?


    1. Hi Ingvar!

      Your host is Fedora 28. It is quite likely that it runs Wayland with no support for X11.
      If that is the case, you would need to add the supporting X11 libraries (XWayland?) to the host so that an X11 application can run natively on the host. Then, you can get X11 applications to run in the container and redirect the output to the host.

    • max on November 6, 2018 at 05:56
    • Reply

    Hi Simos,

    already thanks for the tutorial – i’m still working on it 😉 but i’m facing an unknown error. i’m using ubuntu18.04LTS with lxd/lxc 3.0.1 and followed your tutorial till the launch command throws following error:

    $ lxc launch --profile default --profile gui ubuntu:18.04 gui1804
    Creating gui1804
    Starting gui1804
    Error: strconv.Atoi: parsing "0\nBlacklisted:\t": invalid syntax
    lxc info --show-log local:gui1804 for more info

    google does not give any result. it seems to be an error in some GO-script which is related to the gui profile because running the launch command without gui profile works fine. calling the container log as proposed does not given any further information:

    $ lxc info --show-log local:gui1804
    Name: gui1804
    Remote: unix://
    Architecture: x86_64
    Created: 2018/11/06 05:25 UTC
    Status: Stopped
    Type: persistent
    Profiles: default, gui


    here’s my copy-pasted gui profile:

    $ lxc profile show gui
    environment.DISPLAY: :0
    raw.idmap: both 1000 1000
    user.user-data: |
    - 'sed -i "s/; enable-shm = yes/enable-shm = no/g" /etc/pulse/client.conf'
    - 'echo export PULSE_SERVER=unix:/tmp/.pulse-native | tee --append /home/ubuntu/.profile'
    - x11-apps
    - mesa-utils
    - pulseaudio
    description: GUI LXD profile
    path: /tmp/.pulse-native
    source: /run/user/1000/pulse/native
    type: disk
    path: /tmp/.X11-unix/X0
    source: /tmp/.X11-unix/X0
    type: disk
    type: gpu
    name: gui
    - /1.0/containers/gui1804

    any idea what i’m doing wrong?

    thanks a lot in advance!


    1. Hi!

      You have an NVidia graphics card and you are hitting on this issue,
      See the last few comments where a user reports that the “Blacklisted: ???” line is confusing LXD.

      The fix has been added to LXD 3.0.2 and has just (a day or two ago) been released to Ubuntu 18.04.
      Please update your LXD and try again.

        • max on November 7, 2018 at 22:22

        hi Simos,

        thx a lot! that fixed my problem! couldn’t find the issue for 2h… & you just saved me some more hours on that one :)))


    • lxdNix on November 22, 2018 at 00:13
    • Reply

    Hi Nice blog! I am wondering if you know anything about how to run gui apps in lxd containers on a NixOS host. I have tried using the same lxdguiprofile.txt but it didn’t work. Apparently I need to change something to make it suitable for NixOS, but I am new to both lxd and NixOS, so do you have any suggestions? Thanks a lot!

      • lxdNix on November 24, 2018 at 00:37
      • Reply

      I found your another post about how to run gui apps in lxd containers, which actually used x2go. ( I tried it on NixOS and found that it works well. I only used ssh with X11 to forward the GUI of programs running in an LXD container to my NixOS host and actually did not used x2go at all.

      Anyway, that post fixed my problem. Thanks again!

      • andy on January 13, 2019 at 22:25
      • Reply

      I will document how I got this to work with NixOS.

      In configuration.nix:

      services.xserver.displayManager.sessionCommands = ''
      xhost +local:lxd

      virtualisation.lxd.enable = true;

      users.users.andy.extraGroups = [ "audio" "wheel" "lxd" ];

      users.users.root.subUidRanges = [ { startUid = 1000; count = 1; } ];

      # Not really sure about the subgid thing. My uid is 1000 and my gid is 100. Add both:
      users.users.root.subGidRanges = [ { startGid = 1000; count = 1; }
      { startGid = 100; count = 1; } ];

      Follow the steps in this blog. When trying to run glxgears will get “libgl error failed to load driver swrast”

      To solve this I had to install nvidia drivers in the container:

      sudo add-apt-repository ppa:graphics-drivers
      sudo apt-get update
      sudo apt install nvidia-390

      And confirmed that audio and graphics works!

        • lxdNix on January 14, 2019 at 05:02

        Well done, andy 😉 I am glad that this finally works! Thanks~

    • bob mcgrath on January 28, 2019 at 04:43
    • Reply

    I cant be sure following your instructions was the cause of my error message. After working fine all day I now get this message when starting a container. error: LXD doesn’t have a uid/gid allocation. In this mode, only privileged containers are supported.

    1. Do you run the DEB (apt) package of LXD? In that case, you would need to go through Step 1 again.

      1. Hello.
        I got the same error, but /etc/sub{gid,uid} exists and are not empty, so there is no need to go through step 1.

        $ lxc{lxd} –version

        However in syslog i see a different error:
        $ journalctl –since “5 minutes ago”
        Aug 15 23:06:57 hyper sudo[10228]: colt : TTY=pts/3 ; PWD=/etc/netctl ; USER=root ; COMMAND=/usr/bin/lxc launch –profile default –profile gui ubuntu:18.04 gui1804
        Aug 15 23:06:57 hyper lxd[9034]: t=2019-08-15T23:06:57+0300 lvl=warn msg=”Failed to init storage: Load storage pool for container \”gui1804\” in project \”default\”: No such obj>
        Aug 15 23:06:57 hyper lxd[9034]: t=2019-08-15T23:06:57+0300 lvl=eror msg=”Failed creating container” ephemeral=false name=gui1804 project=default

        and no logs in /var/log/lxd/

        changed ownership of sub*** files:
        $ ls -la /etc/sub*
        -rw-r–r– 1 root lxd 24 Aug 15 23:17 /etc/subgid
        -rw-r–r– 1 root lxd 23 Aug 15 23:17 /etc/subuid

        some points from this link doesnt help either.

    • Tielo on May 3, 2019 at 09:42
    • Reply

    Hey Simos,
    many thanks for the excellent tutorial!!!
    Pulseaudio, xclock and other GUI apps run without errors. However, glxgears and glxinfo return following errors:


    libGL error: No matching fbConfigs or visuals found
    libGL error: failed to load driver: swrast
    X Error of failed request: BadValue (integer parameter out of range for operation)
    Major opcode of failed request: 155 (GLX)
    Minor opcode of failed request: 3 (X_GLXCreateContext)
    Value in failed request: 0x0
    Serial number of failed request: 45
    Current serial number in output stream: 47


    name of display: :0
    libGL error: No matching fbConfigs or visuals found
    libGL error: failed to load driver: swrast
    X Error of failed request: GLXBadContext
    Major opcode of failed request: 155 (GLX)
    Minor opcode of failed request: 6 (X_GLXIsDirect)
    Serial number of failed request: 60
    Current serial number in output stream: 59

    Tried some instructions from your “old” post (esp. regarding GPU), but no luck (No protocol specified Error: unable to open display :0)

    System info:
    host: Ubuntu 18.04
    Lxd/Lxc version 3.12 snap package
    container: ubuntu 18.04
    graphics: nvidia-driver-390

    Please kindly advise.

    Thanks in advance!


    1. Hi Tielo!

      In addition to the instructions in this post, you would need to install the following package in the container, “nvidia-driver-390”. This, being the driver on the host.

      This is the easy answer, considering that the nvidia driver package installs quite a lot of stuff (kernel driver) which are not required in the container. The container just uses the libGL Nvidia shared library, but doing “sudo apt install nvidia-driver-390” in the container would just make it work in a single additional step.

    • John on May 17, 2019 at 18:15
    • Reply

    Same libGL error on Ubuntu 18.04.2 LTS. Any resolution?

    1. If you have an Nvidia GPU and you are using the closed-source driver, you need to install the exact same version in the container. Actually, the container will just make use of the “libGL” shared library from the whole lot of stuff from the Nvidia driver package.

    • Follpvosten on June 20, 2019 at 08:17
    • Reply

    I know this topic isn’t really discussed here, but for some reason, I can’t set a GTK2 theme using lxappearance inside my container.

    I think this worked previously, but now I can only see the theme in lxappearance when I just set it, it doesn’t seem to persist, newly started applications always use the not-so-beautiful Raleigh theme.

    Do you have experience with setting GTK themes inside LXD containers? I’d really like to know if there’s just some package I’m missing.

    1. Hi!

      If you do not need hardware acceleration, you could follow this guide, instead.
      Theming should work out of the box, and you get quite more goodies as well.

        • Follpvosten on June 21, 2019 at 19:11

        Well, I would prefer to use the direct Unix socket approach to reduce overhead, regardless of if I’m using hardware accel or not…I guess I’ll try some more things and then maybe try the x2go approach if nothing else works.


        • Follpvosten on June 22, 2019 at 10:01

        Alright, while I have no idea how it works, I’ve figured out that the programs inside the container for some reason try to use the themes of the host system. So installing the theme I’m using on the host side inside the container solves this issue for me! (At least for now, anyways.)

    • ste on July 9, 2019 at 14:46
    • Reply

    Thank you a lot for the tutorial! But your example lxc profile set gui raw.idmap "both 1001 1001" is a bit confusing. it suggests that this is the correct setting for host-user with uid=1001 and gid=1001 (second-default-user within ubuntu). but the second number is a mapping destination for the container uid/gid and mostly the container uid is still 1000. then we need lxc profile set gui raw.idmap "both 1001 1000". (sorry for my bad english. – I hope I’ve made my point clear.)

    1. You are right, and I am updating the post now. There have been a few users that got stuck by this.
      For example,

    • Mike Saho on August 30, 2019 at 04:57
    • Reply

    Hi – This doesn’t seem to work any longer. I’ve been using this method for quite some time based on your post. Did a fresh Ubuntu 18.04 install and wanted to create gui containers for development activities (also 18.04). After applying the gui profile, I get the following error: Error: Failed to run: /usr/lib/lxd/lxd forkstart. When I remove the gui profile, the container will start up again. Any ideas?

    1. Hi!

      When you reinstalled Ubuntu 18.04, you got by default LXD 3.0.3 (deb package). I know that because the error mentions /usr/lib/lxd/lxd (it’s is a different path for the snap package).

      Having said that, the general LXD logs can be found at /var/log/lxd/lxd.log You can have a look in there if there is anything relevant.

      In addition, along with the error message you got, there should be an additional line that instructions you on how to get per-container error messages. Here is how this command looks like:

      lxc info –show-log local:mycontainer

    • Mike Saho on August 30, 2019 at 17:29
    • Reply

    Figured it out. I had an error in the command to map the user id of the host to the container and didn’t noticed it failed. 🙁

  5. Hi! More than helpful article!

    find a script for ubuntu which automates the process here:

    • PJ Zoulin on October 4, 2019 at 05:28
    • Reply

    Simos, your work here is amazing. It has worked very well for me so far, except in the following cases:

    1) GUI snaps don’t appear to work. They just hang when I try to start one from the command line in the container. Console snaps work fine.

    2) LibreOffice seems to not work in either case, either installed as a snap or using apt install. As a snap, it just hangs as happens with other GUI snaps. when installed using apt, I get a message on the console that it can’t open the display. Other apps work fine in the same container.

    Any ideas?

    1. I had the same issue. I tried the AppImage and it works great.

    2. Thanks for trying this guide!

      1. Snap packages that use the default strict confinement (most of them) do not have access to the /tmp/ directory, and each snap gets it own private tmp. Due to this, the snap application cannot access the X11 Unix socket at /tmp/.X11-unix. So, what can you do? Well, instead of using Unix sockets, you can use abstract Unix sockets. This sockets are not bound to the filesystem, therefore they are accessible by the snap package.

      To switch from “Unix sockets” to “abstract Unix sockets”, you just need to add a @ in two places in the profile. The end result should look like the following,

          bind: container
          connect: unix:@/tmp/.X11-unix/X1
          listen: unix:@/tmp/.X11-unix/X0
          security.gid: "1000"
          security.uid: "1000"
          type: proxy

      Then, restart the container.

      1. LibreOffice requires working GPU acceleration. I just managed to run the deb package of LibreOffice in a LXD container. Can you verify that it was the deb package of LibreOffice that was not able to run?
  6. Thanks was able to get this method to work on Debian 10 using the latest snap version of LXD. The ability to run graphical apps in Ubuntu containers is very useful for a particular game I like to play, OpenRCT2, and try as I might I’ve been unable to get this game to work or compile on Debian. I recently switched a lot of machines over from Ubuntu to Debian and the ability to run containers has eased the transition! Also running old Windows games under WINE in containers too. I’ve also been experimenting Xephyr windows too which worked though I probably doing it the wrong way..launching the Xephyr window from inside the container. Whether this is doing much in the way of security isolation is another matter. I notice that for Docker, there is X11docker to avoid X security leaks

    1. Thanks for reporting back that it worked with Debian!

      Running Xephyr from within the container is actually a good and bad idea.

      It is a good idea because if a malware manages to find a vulnerability (an escape) from Xephyr, it will be at least be confined in the filesystem of the container (and not the host).

      It is a bad idea because the malware could look for the real X11 socket of the host, and use that directly.

      x11docker is a full-featured script at over 8K lines, and supports using a second X server (default), Xephyr, xpra and a few more. These could be achieved with LXD as well, but at the moment the configuration is just a LXD profile of about 60 lines.

      You would LXD+GUI or x11docker if you want some custom setup. For the case of the OpenRCT2 came, it makes sense to create a snap package. By doing so, the game will be available to all Linux distributions and will help their project tremendously. See for the feature request. It shouldn’t be difficult to create the snap package.

  1. […] June 2018: See updated post How to easily run graphics-accelerated GUI apps in LXD containers on your Ubuntu desktop  which describes how to use LXD profiles to simplify the creation of containers that can show the […]

  2. […] June 2018: See updated post How to easily run graphics-accelerated GUI apps in LXD containers on your Ubuntu desktop  which describes how to use LXD profiles to simplify the creation of containers that can show the […]

  3. […] How to easily run graphics-accelerated GUI apps in LXD containers on your Ubuntu desktop […]

  4. […] next step would be to install the Arduino IDE into the container. See the post on how to set up a GUI LXD container. As a hint, you can easily install the Arduino IDE using […]

  5. […] support in order to show the window of Arduino IDE. We do that by following the instructions at How to easily run graphics-accelerated GUI apps in LXD containers. These instructions tell us to create a LXD profile that has the necessary instructions to launch […]

  6. […] tried to install LXD with gui access using the instructions at:…buntu-desktop/ . Tried both LXD from snap and from apt. When I test it’s 3D GUI in either, I get […]

  7. […] is possible to run GUI tools in the Kali system container, though this is not shown in this […]

  8. […] I wrote that you can make a connection in any direction. For example, you can expose the host’s Unix socket for X11 into the container so that the container can run X11 ap…. Or, in the other way round, you can make available LXD’s Unix socket at the host to a […]

Leave a Reply to Simos Xenitellis Cancel reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: