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

UPDATE June 2020: See newer post at https://blog.simos.info/running-x11-software-in-lxd-containers/ for simplified instructions. They require a recent LXD (version 4.0 or newer), and snap packages work.

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 https://docs.snapcraft.io/core/install 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.

Prerequisites

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. If the output is /usr/bin/lxd, then you have the deb package of LXD. Otherwise, if it is /snap/bin/lxd, 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: 
root:1000:1
$

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

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.
ubuntu@gui1804:~$

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
ubuntu@gui1804:~$

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 exec wine -- sudo --user ubuntu --login
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 https://dl.winehq.org/wine-builds/Release.key


ubuntu@wine:~$ sudo apt-key add Release.key
OK
ubuntu@wine:~$ sudo apt-add-repository https://dl.winehq.org/wine-builds/ubuntu/
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
/opt/wine-stable/bin/wine
ubuntu@wine:~$ sudo apt install zenity unzip cabextract
ubuntu@wine:~$ wget  https://raw.githubusercontent.com/Winetricks/winetricks/master/src/winetricks
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
config:
  environment.DISPLAY: :0
  raw.idmap: both 1000 1000
  user.user-data: |
    #cloud-config
    runcmd:
      - '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'
    packages:
      - x11-apps
      - mesa-utils
      - pulseaudio
description: GUI LXD profile
devices:
  PASocket:
    path: /tmp/.pulse-native
    source: /run/user/1000/pulse/native
    type: disk
  X0:
    path: /tmp/.X11-unix/X0
    source: /tmp/.X11-unix/X0
    type: disk
  mygpu:
    type: gpu
    name: gui
used_by:
- /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]
Version=1.0
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
Icon=/usr/share/icons/HighContrast/scalable/apps-extra/firefox-icon.svg
Type=Application
Categories=Network;WebBrowser;
^D
$ 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.

Troubleshooting

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 exec gui1804 -- sudo --user ubuntu --login
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
ubuntu@gui1804:~$

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.

Discussion

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: https://blog.simos.info/how-to-easily-run-graphics-accelerated-gui-apps-in-lxd-containers-on-your-ubuntu-desktop/

67 comments

10 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, https://github.com/lxc/lxd/issues/4591
      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.

        thx
        brian

        • bmullan on June 26, 2018 at 12:46
        • Reply

        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 🙂
    Colum

    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

      Hello,

      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 https://blog.simos.info/how-to-run-graphics-accelerated-gui-apps-in-lxd-containers-on-your-ubuntu-desktop/ 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: swrast_dri.so

    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?

    thanks

    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
    Try
    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

    Log:

    here’s my copy-pasted gui profile:

    $ lxc profile show gui
    config:
    environment.DISPLAY: :0
    raw.idmap: both 1000 1000
    user.user-data: |
    #cloud-config
    runcmd:
    - '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'
    packages:
    - x11-apps
    - mesa-utils
    - pulseaudio
    description: GUI LXD profile
    devices:
    PASocket:
    path: /tmp/.pulse-native
    source: /run/user/1000/pulse/native
    type: disk
    X0:
    path: /tmp/.X11-unix/X0
    source: /tmp/.X11-unix/X0
    type: disk
    mygpu:
    type: gpu
    name: gui
    used_by:
    - /1.0/containers/gui1804

    any idea what i’m doing wrong?

    thanks a lot in advance!

    greets,
    max

    1. Hi!

      You have an NVidia graphics card and you are hitting on this issue, https://github.com/lxc/lxd/issues/3950
      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
        • Reply

        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 :)))

        greets!

    • 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. (https://blog.simos.info/how-to-use-the-x2go-remote-desktop-with-lxd-containers/) 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
        • Reply

        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
        3.16

        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.
        https://ubuntu.com/blog/custom-user-mappings-in-lxd-containers

    • 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:

    glxgears:

    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

    glxinfo:

    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!

    Tielo

    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, https://blog.simos.info/how-to-use-the-x2go-remote-desktop-with-lxd-containers/ instead.
      Theming should work out of the box, and you get quite more goodies as well.

        • Follpvosten on June 21, 2019 at 19:11
        • Reply

        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.

        Thanks!

        • Follpvosten on June 22, 2019 at 10:01
        • Reply

        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,
      https://discuss.linuxcontainers.org/t/gui-apps-in-lxd-container/4612/14

    • 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:

    https://github.com/lagerimsi-ds/lxd-gui-apps

    • 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.

      https://www.libreoffice.org/download/appimage/

    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,

      devices:
        X0:
          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 https://github.com/OpenRCT2/OpenRCT2/issues/6112 for the feature request. It shouldn’t be difficult to create the snap package.

    • Adam York on January 1, 2020 at 15:31
    • Reply

    Thank you so very much for your wonderful work on this! I use a container to run graphical apps daily. Question. Is there a way to issue a command from the host to the container without logging in first? I am looking for a way to simply issue a command from the host and have the container app run. I don’t know if there’s a way to do that without logging in first. And that takes a little more effort simply to run an app.

      • bmullan on January 1, 2020 at 16:07
      • Reply

      Hi Adam… yes LXD has many nice command line capabilities that alot of people are unaware of.

      Here is an LXD Cheat Sheet that is handy: https://medium.com/@tcij1013/lxc-lxd-cheetsheet-effb5389922d

      Take a look under the subject: Run a command in a container

      You can also do the above in a bash script and execute several commands.

      Brian

    • Adam York on January 1, 2020 at 16:44
    • Reply

    Thank you so very much for your wonderful work on this! I use a container to run graphical apps daily. Question. Is there a way to issue a command from the host to the container without logging in first? I am looking for a way to simply issue a command from the host and have the container app run. I don’t know if there’s a way to do that without logging in first. And that takes a little more effort simply to run an app.

    lxc exec gui1804 — /usr/bin/firefox

    No protocol specified
    Unable to init server: Could not connect: Connection refused
    Error: cannot open display: :0

    • Adam York on January 1, 2020 at 16:47
    • Reply

    Sorry. I was trying to reply to the post above by bmullan and I cut and pasted improperly.

    Thanks for your help, but my problems have been running gui apps. I thought it might be good to ask the question here since this post is about gui apps. When I try to run a gui app, like Firefox, I run into the following problem.

    lxc exec gui1804 — /usr/bin/firefox

    No protocol specified
    Unable to init server: Could not connect: Connection refused
    Error: cannot open display: :0

  7. When you run commands in a container, it is better to run them as a non-root user.
    In addition, the instructions in this post require to use a non-root account, otherwise audio would not work.
    If you were to run Firefox as the non-root account, you would:

    lxc exec gui1804 -- sudo --user ubuntu --login /usr/bin/firefox
    

    Having said that, I suggest to try again by creating a new GUI profile, according to by newer simplified post at
    https://blog.simos.info/running-x11-software-in-lxd-containers/
    The advantages here is that it is less likely to give errors.

      • Adam York on January 5, 2020 at 19:59
      • Reply

      Wonderful! That works. Thank you Simos! I really appreciate your posts on this issue!

      1. Thank you!

        Did you use the new tutorial, or did you just switch the command line to run the program as a non-root user?

        Once you get the command line working, you can create a .desktop file for this application. By doing do, you will get an icon for the application, and will not need to open a terminal to run the program.

    • Mike on January 5, 2020 at 22:39
    • Reply

    Thanks for the awesome guide! When I setup my LXD container this way, the one thing I’m unable to do is to mount NFS shares into the container:

    $ sudo mount -t nfs machine:location /mountpoint
    mount.nfs: Operation not permitted

    Is there something that should be added to the LXD profile to make mounts work?

    1. Thanks!

      Can you verify that you can indeed mount NFS shares from within other unprivileged containers on the same host, but cannot do so with a gui container?

      Make sure that the networking is of the same type for both cases of the test (i.e. both macvlan or both private bridge).

        • Mike on January 8, 2020 at 02:11
        • Reply

        Hi, sorry, I should have specified. My question was more about how to mount an NFS share inside a container in general, rather than that it wasn’t working with a container built with your instructions. (And I’m a bit of an LXC n00b).

        Should I make my container privileged to accomplish this? Would that work fine with the gui container?

      1. If you want to run an NFS server inside a LXD container, then you likely need a privileged container.
        See discussion at https://discuss.linuxcontainers.org/t/nfs-kernel-server-inside-a-lxd-container/654

        A client should be OK to run inside an unprivileged container.

    • Mike on January 17, 2020 at 04:39
    • Reply

    In this case, I only want an NFS client inside the LXD container, not a server.

    • mike on March 11, 2020 at 00:35
    • Reply

    DUDE !! This is awesome ! You are my ambassador to quan !

    1. Thank you!

    • Ray on May 3, 2020 at 04:54
    • Reply

    Thank you for the excellent guide. I’m new to LXD containers for 32 bit Wine due to moving from Ubuntu 14.04 to 20.04 on my Thinkpad T61 (w/Intel video).

    The first issue I encountered was with the ‘lxc profile list’. Your example shows ‘default’ = 10. On my system I received ‘default’ = 0, just like for ‘gui’. But ‘glxgears’ ran just fine at ~ 60 frames/sec.

    Is it a problem for ‘default’ to equal 0 and not 10 as in your example?

    1. Thanks!

      The output of lxc profile list shows the available profiles. The default is the one provided by default by LXD, and the rest have been created by you.
      The USED BY column shows how many containers are using each of the profiles.
      In my case, the 10 for the default profile means that I have created ten containers that are based on the default profile.
      Since we just created the gui profile, it should show 0 . When you create your first gui container, the USED BY will change to 1.

      If you run lxc profile show default, it will show you at the end the names of the container that are using this profile.

    • PJ Zoulin on June 11, 2020 at 13:26
    • Reply

    So, let me tell you first of all that this brilliant piece of work is now the basis for my daily driver. I keep almost all of my applications in LXC/LXD containers which has allowed me to greatly simplify my development environments. In 90% of the cases, everything works perfectly.

    Where I have noticed some problems is especially in the use of snap or flatpak applications. Some will work fine, and some will have have trouble installing or running (for instance, the snap for LibreOffice doesn’t work. Likewise the flatpak for Spotify, among others).

    I was thinking about trying to apply this same approach to an LXD VM instead and see if I could get around some of these problems. I did try a few months ago, but couldn’t seem to get GUI apps to recognize the display. I might try again, but I wanted to see if you have any recommendations for either of these points:

    Getting snap or flatpak containers to work in containers
    Applying the above approach to VM’s instead.

    1. Thanks!

      The instructions in this specific post place the Unix sockets for X11 and PulseAudio in /tmp/. This does not work with most snap packages, because due to security isolation, they cannot access the contents of the system-wide /tmp. For example, the Spotify snap has its own tmp, and is located in /tmp/snap.spotify/.

      Therefore, there is a newer guide that resolves most of these issues, at https://blog.simos.info/running-x11-software-in-lxd-containers/
      It uses the abstract Unix socket for X11, therefore there are no issues with filesystem permissions.
      It places the PulseAudio Unix socket in the home directory in the container, which means that if the snap package uses the home interface, then the socket is accessible.

      I am not familiar with flatpaks.

      An LXD VM can work as well, however there is the issue with hardware acceleration for the GPU and how fast are the graphics to have games being playable as on the host. You get the best performance if you can dedicate a separate GPU to that single VM (GPU Passthrough). Another alternative, somewhat slower, is to use an accelerated virtual GPU, where you can get several VMs to use semi-accelerated graphics.
      It is somewhat more involved to do these things.

    • 512YiB on March 3, 2021 at 12:36
    • Reply

    It’s brilliant!
    Simos, I have a problem with “runcmd:” and “packages:” section. Neither commands are executed, nor packages are installed.
    Maybe lxd is not enough and I need to install something else?

    lxd was installed from snap.
    Client version: 4.11
    Server version: 4.11

    1. Thanks!

      LXD sends verbatim the cloud-init instructions to the container, and it is up to the container to process them. If there is a typo or some other formatting issue, LXD will not know about it.

      In addition, can you tell me which container image you are using?
      Those from the ubuntu: repository have cloud-init support, but from the images: repository only those that have /cloud in their name have cloud-init support.

      If the container image has no cloud-init support, then the cloud-init instructions are ignored.

    • 512YiB on March 3, 2021 at 16:15
    • Reply

    I’ve installed cloud-init and enabled it in systemd and it works now. Thank you.
    Now I have another problem: when I use

    pics:
        path:   /home/ubuntu/pics
        source: /home/user/pics
        type:   disk
    

    in profile config the dir /home/ubuntu becomes owned by root. Of cource, I can do sudo chown, but after container restarts I have to do it again, because /home/ubuntu becomes owned by root again and again.
    Is there a solution?

    Also, commands are executed after packages installed, but I’d like to run some commands before the installation of packages begun. Do you know how to change the order?

    And I don’t know why it takes at least half of an hour for cloud-init to just install pluma in one container.

    1. When you want to share a directory on the host to the container, then you can use the shift=true option as described at https://linuxcontainers.org/lxd/docs/master/instances#type-disk

      See also https://discuss.linuxcontainers.org/t/lxd-usecases-of-shiftfs-volume-disk-share/7735 for more.

      Pluma requires 1GB of packages in order to get installed. If your internet speed is good enough and 1GB should be downloaded faster, then this should be investigated. Create a new container, and install pluma manually. It should show you whether you have any DNS issues, or whether the container is retrieving the packages from some slow far away server.

    • woynert on October 28, 2021 at 01:25
    • Reply

    Thank you very much! Excellent guide

  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: https://blog.simos.info/how-to-easil…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 […]

  9. […] the instructions for the second way to run X applications. Previously I have written several tutorials on […]

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

Leave a Reply to IngvarCancel reply

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