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

In How to run Wine (graphics-accelerated) in an LXD container on Ubuntu we had a quick look into how to run GUI programs in an LXD (Lex-Dee) container, and have the output appear on the local X11 server (your Ubuntu desktop).

In this post, we are going to see how to

  1. generalize the instructions in order to run most GUI apps in a LXD container but appear on your desktop
  2. have accelerated graphics support and audio
  3. test with Firefox, Chromium and Chrome
  4. create shortcuts to easily launch those apps

The benefits in running GUI apps in a LXD container are

  • clear separation of the installation data and settings, from what we have on our desktop
  • ability to create a snapshot of this container, save, rollback, delete, recreate; all these in a few seconds or less
  • does not mess up your installed package list (for example, all those i386 packages for Wine, Google Earth)
  • ability to create an image of such a perfect container, publish, and have others launch in a few clicks

What we are doing today is similar to having a Virtualbox/VMWare VM and running a Linux distribution in it. Let’s compare,

  • It is similar to the Virtualbox Seamless Mode or the VMWare Unity mode
  • A VM virtualizes a whole machine and has to do a lot of work in order to provide somewhat good graphics acceleration
  • With a container, we directly reuse the graphics card and get graphics acceleration
  • The specific set up we show today, can potential allow a container app to interact with the desktop apps (TODO: show desktop isolation in future post)

Browsers have started having containers and specifically in-browser containers. It shows a trend towards containers in general, it is browser-specific and is dictated by usability (passwords, form and search data are shared between the containers).

In the following, our desktop computer will called the host, and the LXD container as the container.

Setting up LXD

LXD is supported in Ubuntu and derivatives, as well as other distributions. When you initially set up LXD, you select where to store the containers. See LXD 2.0: Installing and configuring LXD [2/12] about your options. Ideally, if you select to pre-allocate disk space or use a partition, select at least 15GB but preferably more.

If you plan to play games, increase the space by the size of that game. For best results, select ZFS as the storage backend, and place the space on an SSD disk. Also Trying out LXD containers on our Ubuntu may help.

Creating the LXD container

Let’s create the new container for LXD. We are going to call it guiapps, and install Ubuntu 16.04 in it. There are options for other Ubuntu versions, and even other distributions.

$ lxc launch ubuntu:x guiapps
Creating guiapps
Starting guiapps
$ lxc list
+---------------+---------+--------------------+--------+------------+-----------+
|     NAME      |  STATE  |        IPV4        |  IPV6  |    TYPE    | SNAPSHOTS |
+---------------+---------+--------------------+--------+------------+-----------+
| guiapps       | RUNNING | 10.0.185.204(eth0) |        | PERSISTENT | 0         |
+---------------+---------+--------------------+--------+------------+-----------+
$

We created and started an Ubuntu 16.04 (ubuntu:x) container, called guiapps.

Let’s also install our initial testing applications. The first one is xclock, the simplest X11 GUI app. The second is glxinfo, that shows details about graphics acceleration. The third, glxgears, a minimal graphics-accelerated application. The fourth is speaker-test, to test for audio. We will know that our set up works, if all three xclock, glxinfo, glxgears and speaker-test work in the container!

$ lxc exec guiapps -- sudo --login --user ubuntu
ubuntu@guiapps:~$ sudo apt update
ubuntu@guiapps:~$ sudo apt install x11-apps
ubuntu@guiapps:~$ sudo apt install mesa-utils
ubuntu@guiapps:~$ sudo apt install alsa-utils
ubuntu@guiapps:~$ exit $

We execute a login shell in the guiapps container as user ubuntu, the default non-root user account in all Ubuntu LXD images. Other distribution images probably have another default non-root user account.

Then, we run apt update in order to update the package list and be able to install the subsequent three packages that provide xclock, glxinfo and glxgears, and speaker-test (or aplay). Finally, we exit the container.

Mapping the user ID of the host to the container (PREREQUISITE)

In the following steps we will be sharing files from the host (our desktop) to the container. There is the issue of what user ID will appear in the container for those shared files.

First, we run on the host (only once) the following command (source): (Note: if you do not have 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 (runs as root) to remap our user’s ID ($UID, from the host) as requested.

Then, we specify that we want this feature in our guiapps LXD container, and restart the container for the change to take effect.

$ lxc config set guiapps raw.idmap "both $UID 1000"
$ lxc restart guiapps
$

This “both $UID 1000” syntax is a shortcut that means to map the $UID/$GID of our username in the host, to the default non-root username in the container (which should be 1000 for Ubuntu images, at least).

Configuring graphics and graphics acceleration

For graphics acceleration, we are going to use the host graphics card and graphics acceleration. By default, the applications that run in a container do not have access to the host system and cannot start GUI apps.

We need two things; let the container to access the GPU devices of the host, and make sure that there are no restrictions because of different user-ids.

Let’s attempt to run xclock in the container.

$ echo $DISPLAY
:0
$ lxc exec guiapps -- sudo --login --user ubuntu
ubuntu@guiapps:~$ xclock
Error: Can't open display: 
ubuntu@guiapps:~$ export DISPLAY=:0
ubuntu@guiapps:~$ xclock
Error: Can't open display: :0
ubuntu@guiapps:~$ exit
$

First, we check the value of $DISPLAY on the host to verify that X11 is indeed listening on :0. If you have two graphics cards, or if you have a non-standard setup, then that value might be :1 or something similar.  We run xclock in the container, and as expected it does not run because we did not indicate where to send the display. We set the DISPLAY environment variable to the :0 that we got earlier (send to either a Unix socket or port 6000), which do not work either because we did not fully set them up yet. Let’s do that.

$ lxc config device add guiapps X0 disk path=/tmp/.X11-unix/X0 source=/tmp/.X11-unix/X0 
$ lxc config device add guiapps Xauthority disk path=/home/ubuntu/.Xauthority source=${XAUTHORITY}

We give access to the Unix socket of the X server (/tmp/.X11-unix/X0) to the container, and make it available at the same exactly path inside the container. In this way, DISPLAY=:0 would allow the apps in the containers to access our host’s X server through the Unix socket.

Then, we repeat this task with the ~/.Xauthority file that resides in our home directory. This file is for access control, and simply makes our host X server to allow the access from applications inside that container. For the host, this file can be found in the variable $XAUTHORITY and should be either at ~/.Xauthority or /run/user/1000/gdm/Xauthority. Obviously, we can set correctly the source= part, however the distribution in the container needs to be able to find the .Xauthority in the given location. If the container is the official Ubuntu, then it should be /home/ubuntu/.Xauthority Adjust accordingly if you use a different distribution. If something goes wrong in the whole guide, it most probably will be in this above two commands.

How do we get hardware acceleration for the GPU to the container apps? There is a special device for that, and it’s gpu. The hardware acceleration for the graphics card is collectively enabled by running the following,

$ lxc config device add guiapps mygpu gpu
$ lxc config device set guiapps mygpu uid 1000
$ lxc config device set guiapps mygpu gid 1000

We add the gpu device, and we happen to name it mygpu (any name would suffice). In addition to gpu device, we also set the permissions accordingly so that the device is fully accessible in  the container. The gpu device has been introduced in LXD 2.7, therefore if it is not found, you may have to upgrade your LXD according to https://launchpad.net/~ubuntu-lxc/+archive/ubuntu/lxd-stable Please leave a comment below if this was your case (mention what LXD version you have been running). Note that for Intel GPUs (my case), you may not need to add this device.

Note: If you have an NVidia graphics card and you are using the nouveau driver, you may get the following error,

libGL error: failed to open drm device: No such file or directory
libGL error: failed to load driver: nouveau

Marcos dos Santos de Oliveira in the comments suggests the following:

Fixed by adding the following:

lxc config device add guiapps card0 unix-char path=/dev/dri/card0 gid=44

This command add an unix-char device to the /dev/dri/ directory in the container… By the way, to keep it consistent with what I had in the host, I used the default uid and gid at the gpu device also, which is 0:44 (root:video), because the ubuntu user was already in the video group and if it wasn’t we could add it. I used the following command:

lxc config device add guiapps mygpu gpu gid=44

Let’s see what we got now.

$ lxc exec guiapps -- sudo --login --user ubuntu
ubuntu@guiapps:~$ export DISPLAY=:0
ubuntu@guiapps:~$ xclock

ubuntu@guiapps:~$ glxinfo -B
name of display: :0
display: :0  screen: 0
direct rendering: Yes
Extended renderer info (GLX_MESA_query_renderer):
    Vendor: Intel Open Source Technology Center (0x8086)
...
ubuntu@guiapps:~$ glxgears 

Running synchronized to the vertical refresh.  The framerate should be
approximately the same as the monitor refresh rate.
345 frames in 5.0 seconds = 68.783 FPS
309 frames in 5.0 seconds = 61.699 FPS
300 frames in 5.0 seconds = 60.000 FPS
^C
ubuntu@guiapps:~$ echo "export DISPLAY=:0" >> ~/.profile 
ubuntu@guiapps:~$ exit
$

Looks good, we are good to go! Note that we edited the ~/.profile file in order to set the $DISPLAY variable automatically whenever we connect to the container.

Configuring audio

The audio server in Ubuntu desktop is Pulseaudio, and Pulseaudio has a feature to allow authenticated access over the network. Just like the X11 server and what we did earlier. Let’s do this.

We install the paprefs (PulseAudio Preferences) package on the host.

$ sudo apt install paprefs
...
$ paprefs

This is the only option we need to enable (by default all other options are not check and can remain unchecked).

That is, under the Network Server tab, we tick Enable network access to local sound devices.

Then, just like with the X11 configuration, we need to deal with two things; the access to the Pulseaudio server of the host (either through a Unix socket or an IP address), and some way to get authorization to access the Pulseaudio server. Regarding the Unix socket of the Pulseaudio server, it is a bit of hit and miss (could not figure out how to use reliably), so we are going to use the IP address of the host (lxdbr0 interface).

First, the IP address of the host (that has Pulseaudio) is the IP of the lxdbr0 interface, or the default gateway (ip link show). Second, the authorization is provided through the cookie in the host at /home/${USER}/.config/pulse/cookie Let’s connect these to files inside the container.

$ lxc exec guiapps -- sudo --login --user ubuntu
ubuntu@guiapps:~$ echo export PULSE_SERVER="tcp:`ip route show 0/0 | awk '{print $3}'`" >> ~/.profile

This command will automatically set the variable PULSE_SERVER to a value like tcp:10.0.185.1, which is the IP address of the host, for the lxdbr0 interface. The next time we log in to the container, PULSE_SERVER will be configured properly.

ubuntu@guiapps:~$ mkdir -p ~/.config/pulse/
ubuntu@guiapps:~$ echo export PULSE_COOKIE=/home/ubuntu/.config/pulse/cookie >> ~/.profile
ubuntu@guiapps:~$ exit
$ lxc config device add guiapps PACookie disk path=/home/ubuntu/.config/pulse/cookie source=/home/${USER}/.config/pulse/cookie

Now, this is a tough cookie. By default, the Pulseaudio cookie is found at ~/.config/pulse/cookie. The directory tree ~/.config/pulse/ does not exist, and if we do not create it ourselves, then lxd config will autocreate it with the wrong ownership. So, we create it (mkdir -p), then add the correct PULSE_COOKIE line in the configuration file ~/.profile. Finally, we exit from the container and mount-bind the cookie from the host to the container. When we log in to the container again, the cookie variable will be correctly set!

Let’s test the audio!

$ lxc exec guiapps -- sudo --login --user ubuntu
ubuntu@pulseaudio:~$ speaker-test -Dpulse -c6 -twav

speaker-test 1.1.0

Playback device is default
Stream parameters are 48000Hz, S16_LE, 6 channels
WAV file(s)
Rate set to 48000Hz (requested 48000Hz)
Buffer size range from 32 to 349525
Period size range from 10 to 116509
Using max buffer size 349524
Periods = 4
was set period_size = 87381
was set buffer_size = 349524
 0 - Front Left
 4 - Center
 1 - Front Right
 3 - Rear Right
 2 - Rear Left
 5 - LFE
Time per period = 8.687798 ^C
ubuntu@pulseaudio:~$

If you do not have 6-channel audio output, you will hear audio on some of the channels only.

Let’s also test with an MP3 file, like that one from https://archive.org/details/testmp3testfile

ubuntu@pulseaudio:~$ sudo apt install mpg123
...
ubuntu@pulseaudio:~$ wget https://archive.org/download/testmp3testfile/mpthreetest.mp3
...
ubuntu@pulseaudio:~$ mplayer mpthreetest.mp3 
MPlayer 1.2.1 (Debian), built with gcc-5.3.1 (C) 2000-2016 MPlayer Team
...
AO: [pulse] 44100Hz 2ch s16le (2 bytes per sample)
Video: no video
Starting playback...
A:   3.7 (03.7) of 12.0 (12.0)  0.2% 

Exiting... (Quit)
ubuntu@pulseaudio:~$

All nice and loud!

Troubleshooting sound issues

Sound error: connection refused

AO: [pulse] Init failed: Connection refused

An application tries to connect to a PulseAudio server, but no PulseAudio server is found (either none autodetected, or the one we specified is not really there).

Make a test connection to the PulseAudio port from within the container. First, find the IP address that was configured in the container for the PulseAudio server of the host,

ubuntu@guiapps:~$ echo $PULSE_SERVER 
tcp:10.50.250.1
ubuntu@guiapps:~$

Then, connect to that IP address at port 4713 (the TCP port of PulseAudio),

ubuntu@guiapps:~$ telnet 10.50.250.1 4713
Trying 10.50.250.1...
Connected to 10.50.250.1.
Escape character is '^]'.
^]
telnet> q
Connection closed.
ubuntu@guiapps:~$

In this case, we managed to connect successfully over TCP. We do not know yet whether we are authorized to connect. That is an issue for the next error below; whether we have a valid access cookie to the PulseAudio server.

If you get instead the following, then you need to go back to the host’s PulseAudio server settings and make sure that the server is listening to the network for connections.

ubuntu@guiapps:~$ telnet 10.50.250.1 4715
Trying 10.50.250.1...
telnet: Unable to connect to remote host: Connection refused
ubuntu@guiapps:~$

Sound error: access denied

AO: [pulse] Init failed: Access denied

We specified a PulseAudio server, but we do not have access to connect to it. We need a valid cookie.

Run in the container the following command. If you get this output, then the cookie is readable, which is good. Our configuration makes this cookie identical to the cookie on the host, as they are the same file. There is a chance that the container’s cookie is different from the host’s cookie (if, for example, you are using a different user account on the host). In that case, take the sha1sum of the host’s PulseAudio cookie and check that they have the same hash.

ubuntu@guiapps:~$ sha1sum ~/.config/pulse/cookie 
db29fe97df4d20ffe13a8bc5d73d1ebef92d1dfa /home/ubuntu/.config/pulse/cookie
ubuntu@guiapps:~$

If you get instead the following, then the container has no access to the actual cookie and you need to create it again.

ubuntu@guiapps:~$ sha1sum ~/.config/pulse/cookie
sha1sum: /home/ubuntu/.config/pulse/cookie: Permission denied
ubuntu@guiapps:~$

Sound error: protocol error

AO: [pulse] Init failed: Protocol error

You were trying as well to make the Unix socket work, but something was wrong. If you can make it work, write a comment below.

Testing with Firefox

Let’s test with Firefox!

ubuntu@guiapps:~$ sudo apt install firefox
...
ubuntu@guiapps:~$ firefox 
Gtk-Message: Failed to load module "canberra-gtk-module"

We get a message that the GTK+ module is missing. Let’s close Firefox, install the module and start Firefox again.

ubuntu@guiapps:~$ sudo apt-get install libcanberra-gtk3-module
ubuntu@guiapps:~$ firefox

Here we are playing a Youtube music video at 1080p. It works as expected. The Firefox session is separated from the host’s Firefox.

Note that the theming is not exactly what you get with Ubuntu. This is due to the container being so lightweight that it does not have any theming support.

The screenshot may look a bit grainy; this is due to some plugin I use in WordPress that does too much compression.

You may notice that no menubar is showing. Just like with Windows, simply press the Alt key for a second, and the menu bar will appear.

Testing with Chromium

Let’s test with Chromium!

ubuntu@guiapps:~$ sudo apt install chromium-browser
ubuntu@guiapps:~$ chromium-browser
Gtk-Message: Failed to load module "canberra-gtk-module"

So, chromium-browser also needs a libcanberra package, and it’s the GTK+ 2 package.

ubuntu@guiapps:~$ sudo apt install libcanberra-gtk-module
ubuntu@guiapps:~$ chromium-browser

There is no menubar and there is no easy way to get to it. The menu on the top-right is available though.

Testing with Chrome

Let’s download Chrome, install it and launch it.

ubuntu@guiapps:~$ wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
...
ubuntu@guiapps:~$ sudo dpkg -i google-chrome-stable_current_amd64.deb
...
Errors were encountered while processing:
 google-chrome-stable
ubuntu@guiapps:~$ sudo apt install -f
...
ubuntu@guiapps:~$ google-chrome
[11180:11945:0503/222317.923975:ERROR:object_proxy.cc(583)] Failed to call method: org.freedesktop.UPower.GetDisplayDevice: object_path= /org/freedesktop/UPower: org.freedesktop.DBus.Error.ServiceUnknown: The name org.freedesktop.UPower was not provided by any .service files
[11180:11945:0503/222317.924441:ERROR:object_proxy.cc(583)] Failed to call method: org.freedesktop.UPower.EnumerateDevices: object_path= /org/freedesktop/UPower: org.freedesktop.DBus.Error.ServiceUnknown: The name org.freedesktop.UPower was not provided by any .service files
^C
ubuntu@guiapps:~$ sudo apt install upower
ubuntu@guiapps:~$ google-chrome

There are these two errors regarding UPower and they go away when we install the upower package.

Creating shortcuts to the container apps

If we want to run Firefox from the container, we can simply run

$ lxc exec guiapps -- sudo --login --user ubuntu firefox

and that’s it.

To make a shortcut, we create the following file on the host,

$ cat > ~/.local/share/applications/lxd-firefox.desktop[Desktop Entry]
Version=1.0
Name=Firefox in LXD
Comment=Access the Internet through an LXD container
Exec=lxc exec guiapps -- sudo --login --user ubuntu firefox %U
Icon=/usr/share/icons/HighContrast/scalable/apps-extra/firefox-icon.svg
Type=Application
Categories=Network;WebBrowser;
^D
$ chmod +x ~/.local/share/applications/lxd-firefox.desktop

We need to make it executable so that it gets picked up and we can then run it by double-clicking.

If it does not appear immediately in the Dash, use your File Manager to locate the directory ~/.local/share/applications/

This is how the icon looks like in a File Manager. The icon comes from the high-contrast set, which now I remember that it means just two colors 🙁

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

I hope the tutorial was useful. We explain the commands in detail. In a future tutorial, we are going to try to figure out how to automate these!

Permanent link to this article: https://blog.simos.info/how-to-run-graphics-accelerated-gui-apps-in-lxd-containers-on-your-ubuntu-desktop/

74 comments

8 pings

Skip to comment form

    • kelvin on May 8, 2017 at 16:33
    • Reply

    Hey thanks for this, really easy guide and super useful!

    I think I only had 3 deviations, don’t know whether others will find this useful… (host is ubuntu 17.04 with gnome3)

    I didn’t have an .Xauthority file in my hosts home directory so I had to create a symlink to /run/user/1000/gdm/Xauthority.
    When running paprefs on the host I needed to logout/login for changes to take affect.
    Maybe obvious but the pulseaudio package needs to be installed in the container for client/server audio routing to work.

    1. Thanks for the feedback.

      The Xauthority file should better be obtained from $XAUTHORITY (for the host). I updated the post to reflect this.
      In the container, I guess that it should check ~/.Xauthority as well, and therefore it would work.

      I wouldn’t think that the actual pulseaudio package needs to be installed in the container. Just like X11, it does not require the server to be installed or operational, but rather the necessary libraries that will be able to find the server.

      It is possible that with Ubuntu+GNOME Shell, those Pulseaudio libraries are not getting installed and require explicity installation. I’ll have to have a closer look on that.

        • Bill Wood on May 19, 2018 at 04:14

        I also had to install pulseaudio in the Ubuntu 18.04 container and also had to reboot before paprefs took effect.

        • Bill Wood on May 19, 2018 at 04:26

        Also this instruction did not work as it expanded to tcp: before being appended to .profile:

        echo export PULSE_SERVER=”tcp:`ip route show 0/0 | awk ‘{print $3}’`” >> ~/.profile

        I explicitly added the export into .profile and it works.

    • G13Man on May 28, 2017 at 14:39
    • Reply

    thanks , being older and suffering migraines ,
    I am glad to see others figuring ways to use Linux and virtual machines and now container to make our computing safer and easier !

    • Luis on May 29, 2017 at 06:37
    • Reply

    Hello.. in the mapping the user section O am getting the following errors,

    lxc 20170529053238.561 ERROR lxc_conf – conf.c:run_buffer:405 – Script exited with status 1.
    lxc 20170529053238.561 ERROR lxc_conf – conf.c:lxc_setup:3890 – failed to run mount hooks for container ‘guiapps’.
    lxc 20170529053238.561 ERROR lxc_start – start.c:do_start:811 – Failed to setup container “guiapps”.
    lxc 20170529053238.561 ERROR lxc_sync – sync.c:__sync_wait:57 – An error occurred in another process (expected sequence number 3)
    lxc 20170529053238.611 ERROR lxc_start – start.c:__lxc_start:1346 – Failed to spawn container “guiapps”.
    lxc 20170529053239.218 ERROR lxc_conf – conf.c:run_buffer:405 – Script exited with status 1.
    lxc 20170529053239.218 ERROR lxc_start – start.c:lxc_fini:546 – Failed to run lxc.hook.post-stop for container “guiapps”.
    lxc 20170529053239.218 WARN lxc_commands – commands.c:lxc_cmd_rsp_recv:172 – Command get_cgroup failed to receive response: Connection reset by peer.
    lxc 20170529053239.218 WARN lxc_commands – commands.c:lxc_cmd_rsp_recv:172 – Command get_cgroup failed to receive response: Connection reset by peer.

    First I made a mistake, I executed the mapping inside the container, realised it and manually deleted from both files. then I got the error.
    I deleted the container, reproduced all the steps correctly and got the same error.

    Any ideas? (I am really new to LXD/LXC)

    • Luis on May 29, 2017 at 07:20
    • Reply

    It seems that a restart of the host solved the issue. Sorry I couldn’t find out what it was. Basically if manually edited “lxc config edit guiapps” and remove the rawid I was able to start the container, when I added it again, it didnt work .

    After restarting the host it was fixed

    WIth the audio I had a similar issue,, the playback was working on the host but not on the container. host restarting fixed the issue too.

    1. Can you provide the following:
      1. Which Linux distribution and version you are using? (run, for example, ‘lsb_release -a’)
      2. Which version of LXD you are running? (run ‘lxd –version’)

      For the container to have access to the X11 and Pulseaudio sockets, you need to have the correct ID mapping.
      Can you verify the User ID (UID) of your host that it is indeed 1000? (run ‘echo $UID’ and it should print 1000 or a similar number).

    • Luis on May 29, 2017 at 07:48
    • Reply

    Ok.. I started from scratch in a new container after restart. I didn’t get the error after mapping the user

    Audio I got the following error:

    ubuntu@guiapps:~$ speaker-test -c6 -twav

    speaker-test 1.1.0

    Playback device is default
    Stream parameters are 48000Hz, S16_LE, 6 channels
    WAV file(s)
    ALSA lib confmisc.c:768:(parse_card) cannot find card ‘0’
    ALSA lib conf.c:4292:(_snd_config_evaluate) function snd_func_card_driver returned error: No such file or directory
    ALSA lib confmisc.c:392:(snd_func_concat) error evaluating strings
    ALSA lib conf.c:4292:(_snd_config_evaluate) function snd_func_concat returned error: No such file or directory
    ALSA lib confmisc.c:1251:(snd_func_refer) error evaluating name
    ALSA lib conf.c:4292:(_snd_config_evaluate) function snd_func_refer returned error: No such file or directory
    ALSA lib conf.c:4771:(snd_config_expand) Evaluate error: No such file or directory
    ALSA lib pcm.c:2266:(snd_pcm_open_noupdate) Unknown PCM default
    Playback open error: -2,No such file or directory
    ubuntu@guiapps:~$ exit
    logout

    Maybe alsa-utils is not enough. I installed mplayer (and its dependencies) inside the container and it worked.

    ubuntu@guiapps:~$ sudo apt install mplayer

    • Luis on May 29, 2017 at 08:03
    • Reply

    No LSB modules are available.
    Distributor ID: Ubuntu
    Description: Ubuntu 17.04
    Release: 17.04
    Codename: zesty

    lxd version 2.12

    However, As I sad, I could’t reproduce the error after the host restart
    UID in the host is 1149 however it is added correctly in /etc/subuid /etc/subgid
    cat /etc/subuid
    iotroot:100000:65536
    lxd:165536:65536
    root:165536:65536
    root:1149:1
    root:0:1

    I didnt have to add the gpu device as I have an Intel one, glxgears is working fine

    glxinfo -B
    name of display: :0
    display: :0 screen: 0
    direct rendering: Yes
    Extended renderer info (GLX_MESA_query_renderer):
    Vendor: Intel Open Source Technology Center (0x8086)
    Device: Mesa DRI Intel(R) Haswell Mobile (0x416)
    Version: 17.0.3
    Accelerated: yes
    Video memory: 1536MB
    Unified memory: yes
    Preferred profile: core (0x1)
    Max core profile version: 4.2
    Max compat profile version: 3.0
    Max GLES1 profile version: 1.1
    Max GLES[23] profile version: 3.1
    OpenGL vendor string: Intel Open Source Technology Center
    OpenGL renderer string: Mesa DRI Intel(R) Haswell Mobile
    OpenGL core profile version string: 4.5 (Core Profile) Mesa 17.0.3
    OpenGL core profile shading language version string: 4.50
    OpenGL core profile context flags: (none)
    OpenGL core profile profile mask: core profile

    OpenGL version string: 3.0 Mesa 17.0.3
    OpenGL shading language version string: 1.30
    OpenGL context flags: (none)

    OpenGL ES profile version string: OpenGL ES 3.1 Mesa 17.0.3
    OpenGL ES profile shading language version string: OpenGL ES GLSL ES 3.10

    as for the audio, mplayer is working , speaker-test is working in the host but not in the container. fair enough for me as I can get audio from the container

    ubuntu@guiapps:~$ speaker-test -c6 -twav

    speaker-test 1.1.0

    Playback device is default
    Stream parameters are 48000Hz, S16_LE, 6 channels
    WAV file(s)
    ALSA lib confmisc.c:768:(parse_card) cannot find card ‘0’
    ALSA lib conf.c:4292:(_snd_config_evaluate) function snd_func_card_driver returned error: No such file or directory
    ALSA lib confmisc.c:392:(snd_func_concat) error evaluating strings
    ALSA lib conf.c:4292:(_snd_config_evaluate) function snd_func_concat returned error: No such file or directory
    ALSA lib confmisc.c:1251:(snd_func_refer) error evaluating name
    ALSA lib conf.c:4292:(_snd_config_evaluate) function snd_func_refer returned error: No such file or directory
    ALSA lib conf.c:4771:(snd_config_expand) Evaluate error: No such file or directory
    ALSA lib pcm.c:2266:(snd_pcm_open_noupdate) Unknown PCM default
    Playback open error: -2,No such file or directory
    ubuntu@guiapps:~$ exit
    logout

    1. If you can get one application in the container to play audio, then audio works in the container. You mention that mplayer works in the container, right?
      The “speaker-test” utility may bypass Pulseaudio, and I think this is what you get here.

      Thanks for reporting this, because it gives a hint that ALSA utilities might not be configured properly to use Pulseaudio in Ubuntu 17.04.

      Here is the background for this:
      1. The Linux kernel has only one option for an audio subsystem, and this is ALSA (alsa-driver). Any audio we hear on Linux, comes from ALSA/alsa-driver.
      2. The ALSA software distribution comes with the ALSA utilities like aplay, arecord, speaker-test, that by default would access directly the ALSA/alsa-driver kernel module in order to play audio. This guide requires from the apps (in the LXD container) to go through Pulseaudio. It is not possible to divert audio without a layer like Pulseaudio.
      3. The ALSA utilities can get automatically configured to go through Pulseaudio (if Pulseaudio libraries are present), and this guide makes use of this feature.
      4. In your case, your ALSA utilities in the container did not get autoconfigured to go through Pulseaudio, therefore they were unable to work.

      I probably need to update the guide so that the audio command explicitly specifies PulseAudio. Therefore, if there is an issue, the command would fail with a more helpful message.

        • Steven on March 29, 2018 at 20:35

        I think I solved one speaker test problem.

        I initially got the same output as Luis:

        ubuntu@guiapps:~$ speaker-test -c6 -twav

        speaker-test 1.1.0

        Playback device is default
        Stream parameters are 48000Hz, S16_LE, 6 channels
        WAV file(s)
        ALSA lib confmisc.c:768:(parse_card) cannot find card ‘0’
        ALSA lib conf.c:4292:(_snd_config_evaluate) function snd_func_card_driver returned error: No such file or directory
        ALSA lib confmisc.c:392:(snd_func_concat) error evaluating strings
        ALSA lib conf.c:4292:(_snd_config_evaluate) function snd_func_concat returned error: No such file or directory
        ALSA lib confmisc.c:1251:(snd_func_refer) error evaluating name
        ALSA lib conf.c:4292:(_snd_config_evaluate) function snd_func_refer returned error: No such file or directory
        ALSA lib conf.c:4771:(snd_config_expand) Evaluate error: No such file or directory
        ALSA lib pcm.c:2266:(snd_pcm_open_noupdate) Unknown PCM default
        Playback open error: -2,No such file or directory

        But when running mplayer I ended up with:
        AO: [pulse] Init failed: Connection refused

        If I run ‘aplay -L’ I get the output
        null
        Discard all samples (playback) or generate zero samples (capture)
        pulse
        PulseAudio Sound Server

        speaker-test was using the default ‘null’ device. So speaker-test works like this:
        ubuntu@guiapps:~$ speaker-test -Dpulse -c6 -twav

        speaker-test 1.1.0

        Playback device is pulse
        Stream parameters are 48000Hz, S16_LE, 6 channels
        WAV file(s)
        ALSA lib pulse.c:243:(pulse_connect) PulseAudio: Unable to connect: Connection refused

        Playback open error: -111,Connection refused

        Unfortunately I’m back to an error. Any ideas on the Connection refused?

      1. When I run “speaker-test -c6 -twav”, I do get exactly the same ALSA errors.
        The instructions in the guide manage to set up only PulseAudio, therefore it is a telling error if there is a message relating to “ALSA” in any way.

        When I specify though `pulse` like in your command, then it works (and I’ll update the post regarding this):

        ubuntu@guiapps:~$ speaker-test -Dpulse -c6 -twav

        speaker-test 1.1.0

        Playback device is pulse
        Stream parameters are 48000Hz, S16_LE, 6 channels
        WAV file(s)
        Rate set to 48000Hz (requested 48000Hz)
        Buffer size range from 32 to 349525
        Period size range from 10 to 116509
        Using max buffer size 349524
        Periods = 4
        was set period_size = 87381
        was set buffer_size = 349524
        0 – Front Left
        4 – Center
        1 – Front Right
        3 – Rear Right
        2 – Rear Left
        5 – LFE
        Time per period = 8.685323

        In your case, the error is quite helpful: “(pulse_connect) PulseAudio: Unable to connect: Connection refused”. This means that your container has the necessary PulseAudio libraries installed. What is missing, is the connection to the PulseAudio server on the host.

        Run the following command,

        ubuntu@guiapps:~$ sha1sum ~/.config/pulse/cookie
        db29fe97df4d20ffe13a8bc5d73d1ebef92d1dfa /home/ubuntu/.config/pulse/cookie
        ubuntu@guiapps:~$

        It does not matter what output you get. The important issue is that your user account can read the contents of the cookie file (and therefore calculate the sum).
        If you cannot read the cookie, then work on that.

        The PulseAudio connection to the host takes place over TCP. Run in the container the command:

        buntu@guiapps:~$ echo $PULSE_SERVER
        tcp:10.50.250.1
        ubuntu@guiapps:~$

        Then, try to connect to that IP on port 4713 (PulseAudio):

        ubuntu@guiapps:~$ telnet 10.50.250.1 4713
        Trying 10.52.252.1…
        Connected to 10.52.252.1.
        Escape character is ‘^]’.
        ^]
        telnet> q
        Connection closed.
        ubuntu@guiapps:~$

        If instead you get “Connection refused”, then you need to verify again that PulseAudio is listening to all network interfaces.

    • Luis on May 29, 2017 at 08:35
    • Reply

    I’m sorry i’m posting so many comments.

    One last thought is that I have to ‘lxc restart guiapps’ every time I log out/log in in my host account

    thank you very much.. amazing work!

    • Luis on June 27, 2017 at 10:15
    • Reply

    Is there a way to run this graphic accelerated apps on a remote server instead of a local one?

    I found this for docker rubbing on AWS.

    https://medium.com/@pigiuz/hw-accelerated-gui-apps-on-docker-7fd424fe813e

    Have you tried something similar?

    1. Hi Luis!

      That article describes the same process, giving access from the container to the X11 Unix socket of the desktop.

      To make all this work on remote systems, it then introduces VirtualGL. VirtualGL would work here as well, though I have not tried it. I’ll try it out soon, unless someone else gives it a go sooner.

    • Satya on June 30, 2017 at 16:51
    • Reply

    For audio to WORK, apart from the above steps, I followed this article:

    https://bmullan.wordpress.com/2013/11/20/how-to-enable-sound-in-lxc-linux-containers/

    Let me write what I did after reading from article:

    1)
    find the ipaddress of the bride used (ifconfig -a)

    for me it is: 10.200.191.1

    lxdbr0: flags=4163 mtu 1500
    inet 10.200.191.1 netmask 255.255.255.0 broadcast 0.0.0.0
    inet6 fe80::20d7:8ff:fe72:cf53 prefixlen 64 scopeid 0x20
    inet6 fd42:5180:d828:a541::1 prefixlen 64 scopeid 0x0
    ether fe:8f:be:e7:4e:a4 txqueuelen 1000 (Ethernet)
    RX packets 92637 bytes 83560968 (83.5 MB)
    RX errors 0 dropped 0 overruns 0 frame 0
    TX packets 61822 bytes 52415104 (52.4 MB)
    TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

    2)

    change ipaddress(the last subnet can be 0. so i used 10.200.191.0) and add the below lines to /etc/pulse/system.pa

    load-module module-native-protocol-tcp auth-ip-acl=127.0.0.1;10.200.191.0/24
    load-module module-zeroconf-publish

    3)

    ps -eaf|grep pulseaudio ; kill it; it will restart automatically

    4) now login to container: make sure your .profile/.bashrc has

    export PULSE_SERVER=tcp:10.200.191.1

    5) logout and login again

    6) now sound worked

    1. In Ubuntu (and probably in other distributions), Pulseaudio opens a Unix socket for the communication between processes that want access to audio. In this howto, the containers get access to both GUI and Audio through Unix sockets.

      Both X11 and Pulseaudio can be configured to be accessed by others through TCP/IP, though we try to avoid it for performance reasons. Those Unix sockets work find with local access (on same computer) but TCP/IP is typically required if there is a need to access remotely.

      Did you try to access Pulseaudio through the Unix socket and it did not work? We can work through it and figure out what went wrong. The most common issue is with permissions in ~/.config/ (in the container). You may need to mkdir ~/.config/pulse/, then run the lxc device command.

      It is good to have a variation of this guide that uses TCP/IP instead of Unix socket. That way, it would be possible to have the container run somewhere remote.

      Thanks for the instructions!

    • Asuranceturix on July 18, 2017 at 18:00
    • Reply

    I cannot reproduce the results you give in this tutorial. I am on Ubuntu 16.04 x64, with LXD 2.15. I follow all the steps, cutting and pasting then literally, but when I should get xclock to display correctly, I get this instead:

    ubuntu@guiapps:~$ xclock
    No protocol specified
    Error: Can’t open display: :0

    I have also noticed that, whereas /tmp/.X11-unix/X0 is persistents across restarts of the ‘guiapps’ container, the Xauthority file that should be found at /run/user/1000/gdm/Xauthority in the container does not reappear after a restart. When I try to set it again, lxd tells me the device already exists. However, even if I create it again, the results are the same:

    —- HOST —-
    dbd@zridi2:~$ lxc restart guiapps
    —- GUEST —-
    ubuntu@guiapps:~$ ls -l /tmp/.X11-unix/X0
    srwxrwxrwx 1 nobody nogroup 0 Jul 18 16:33 /tmp/.X11-unix/X0
    ubuntu@guiapps:~$ ls -l /run/user/
    total 0
    —- HOST —-
    dbd@zridi2:~$ lxc config device add guiapps Xauthority disk path=${XAUTHORITY} source=/home/${USER}/.Xauthority
    error: The device already exists
    dbd@zridi2:~$ lxc config device remove guiapps Xauthority
    Device Xauthority removed from guiapps
    dbd@zridi2:~$ lxc config device add guiapps Xauthority disk path=${XAUTHORITY} source=/home/${USER}/.Xauthority
    Device Xauthority added to guiapps
    —- GUEST —-
    ubuntu@guiapps:~$ ls -l /run/user/1000/gdm/Xauthority
    -rw——- 1 ubuntu ubuntu 102 Jul 17 16:45 /run/user/1000/gdm/Xauthority
    ubuntu@guiapps:~$ xclock
    No protocol specified
    Error: Can’t open display: :0

    What am I doing wrong?

    Thanks!

    • uti on July 27, 2017 at 20:00
    • Reply

    Nice tutorial. But one question remains for me. I use Ubuntu 16.04 and if i start Firefox inside the container Firefox (and all other appositions) have no menu. Unlike the other applications that are run on the host there is no menu showing when i hover over the top bar in unity. Is there a known solution?

  1. @Simos

    I got the same results as Luis when trying to run:

    ubuntu@guiapps:~$ speaker-test -c6 -twav
    speaker-test 1.1.0

    Playback device is default
    Stream parameters are 48000Hz, S16_LE, 6 channels
    WAV file(s)
    ALSA lib confmisc.c:768:(parse_card) cannot find card ‘0’
    ALSA lib conf.c:4292:(_snd_config_evaluate) function snd_func_card_driver returned error: No such file or directory
    ALSA lib confmisc.c:392:(snd_func_concat) error evaluating strings
    ALSA lib conf.c:4292:(_snd_config_evaluate) function snd_func_concat returned error: No such file or directory
    ALSA lib confmisc.c:1251:(snd_func_refer) error evaluating name
    ALSA lib conf.c:4292:(_snd_config_evaluate) function snd_func_refer returned error: No such file or directory
    ALSA lib conf.c:4771:(snd_config_expand) Evaluate error: No such file or directory
    ALSA lib pcm.c:2266:(snd_pcm_open_noupdate) Unknown PCM default
    Playback open error: -2,No such file or directory

    I too could only get sound/audio if I changed the HOST /etc/pulse/system.pa to allow TCP connections from my LXDBR0 subnet
    as pointed out by Satya (where he used my Pulseaudio TCP solution).

    I am pretty sure I followed your config instructions correctly.

    Although I did notice in the section where you executed “speaker -test -c6 -twav” the prompt had changed from “ubuntu@guiapps”
    to
    ubuntu@pulseaudio:~$ speaker-test -c6 -twav (see above in your instructions)

    so maybe that was 2 different containers ?? and maybe one was configured differently than the other ??

    Brian

  2. @Simos

    I went back and tested again but this time I deviated from your instructions of the settings for paprefs.

    In paprefs I selected the first 3 options:

    Enable network access to local sound devices
    Allow other machines on the LAN to discover local sound devices
    Don’t require authentication

    I then commented out the statements I had added to /etc/pulse/system.pa and restarted pulseaudio:

    $ killall pulseaudio # which kills pulseaudio but it automatically restarts & re-reads the new /etc/pulse/system.pa

    NOW… in the container sound works…!

    ubuntu@guiapps:~$ speaker-test -c6 -twav

    So I think your instructions just need to add those 2 extra settings in paprefs to work.

    • Tiger on August 12, 2017 at 22:59
    • Reply

    Hi Simos,
    thank you for your HOWTO with helpful explanations. Amazing job! Exactly what I was looking for. Now let’s install Steam… 🙂

    I’m running Ubuntu Desktop 17.04 as host and same as LXD container.
    I was running into the same problems with audio as some other poster here. bmullan’s trick did the job. audio works via IP now. Still, I would like to know what configurations are necessary to tunnel audio through Unix sockets… Simos can you include the additional setting in paprefs in the HOWTO too, for others to know?

    Simos, I came across an error, probably a typo in the section where you explain how to set up sockets for the display.
    I think the dollar sign at the path-part needs to go behind the parenthesis, like this…
    lxc config device add guiapps Xauthority disk path={$XAUTHORITY} source=/home/${USER}/.Xauthority

    Cheers, Tiger

    • Michael on September 17, 2017 at 07:24
    • Reply

    Hi Simos,

    Thank you for your guide. I noticed in a forum post that you’d used Steam to test this. I have Steam running in a container too with the host passing through xbox360 wireless controllers, it works really well.

    The problem I’m struggling with at the moment is to get Steam to recognise the addition of new wireless controllers during execution of Steam. If they are activated before starting Steam it picks them up, but if they come online while Steam is running they are not detected. Further, if an already working controller goes offline during Steam execution, Steam has to be restarted before it picks it up again. Wondering if you’ve come across this, or if you have any pointers for me in troubleshooting this?

    My current thinking is Steam might be monitoring udev events, and since udev doesn’t run inside the container it is missing the add/remove event. But I’m not really sure how to test this theory.

    Many thanks,
    Michael.

    1. Hi Michael!

      Which Linux kernel version do you have?
      I think that up to Linux 4.4 (default in Ubuntu 16.04), the device files for the controller where static files in /dev/, which was good.
      But newer versions of the kernel (that is, newer xpad.ko), the device files are created (and are removed) dynamically.

      See https://bugzilla.kernel.org/show_bug.cgi?id=115311
      It describes that the same problem exists with emulators as well.

      LXD supports USB passthrough; see https://stgraber.org/2017/03/27/usb-hotplug-with-lxd-containers/ See if you have get it working with USB passthrough. Please report back whether it works or not.

    • nick on October 11, 2017 at 05:15
    • Reply

    Hi everyone, I’m configuring LXD on Ubuntu 17.10 Final Beta. So that I can run from an external USB stick, a single, portable windows EXE that launches a GUI window.

    My understanding is that this version of Ubuntu uses Wayland and may not have X11 installed. How would we replace X11, with Wayland, in the commands?

    These are the commands I am referring to:
    $ lxc config device add wine-games X0 disk path=/tmp/.X11-unix/X0 source=/tmp/.X11-unix/X0
    $ lxc config device add wine-games Xauthority disk path=/home/ubuntu/.Xauthority source=/home/MYUSERNAME/.Xauthority

    Found here: https://blog.simos.info/how-to-run-wine-graphics-accelerated-in-an-lxd-container-on-ubuntu/

    I’m relatively new to Linux so don’t have any experience with most of the details in the commands. Thanks!

    1. In 17.10 it is possible to easily switch to X11, if required. This functionality is there to help NVidia users that may have trouble running Wayland. Therefore, that would be an option.

      I do not have an installation with Wayland yet. I know there is a compatibility X11 layer in Wayland, so that could be an option.
      The ideal way is to figure out what a native GUI app requires to display in Wayland, and try to provide that to the app in an LXD container.

    • Mangesh on October 18, 2017 at 03:12
    • Reply

    Hi,

    When I am trying to restart my guiapps, got below error.

    /home/max # lxc config set guiapps raw.idmap “both $UID 1000”
    root@lxdserver /home/max # lxc restart guiapps
    error: Error calling ‘lxd forkstart guiapps /var/lib/lxd/containers /var/log/lxd/guiapps/lxc.conf’: err=’Failed to run: /usr/bin/lxd forkstart guiapps /var/lib/lxd/containers /var/log/lxd/guiapps/lxc.conf: ‘
    lxc 20171018015541.497 ERROR lxc_conf – conf.c:run_buffer:416 – Script exited with status 1.
    lxc 20171018015541.497 ERROR lxc_conf – conf.c:lxc_setup:4039 – failed to run mount hooks for container ‘guiapps’.
    lxc 20171018015541.497 ERROR lxc_start – start.c:do_start:811 – Failed to setup container “guiapps”.
    lxc 20171018015541.497 ERROR lxc_sync – sync.c:__sync_wait:57 – An error occurred in another process (expected sequence number 3)
    lxc 20171018015541.570 ERROR lxc_start – start.c:__lxc_start:1358 – Failed to spawn container “guiapps”.
    lxc 20171018015542.130 ERROR lxc_conf – conf.c:run_buffer:416 – Script exited with status 1.
    lxc 20171018015542.130 ERROR lxc_start – start.c:lxc_fini:546 – Failed to run lxc.hook.post-stop for container “guiapps”.

    Try `lxc info –show-log guiapps` for more info

    Please let me know, how to resolve the issue.

    Regards,
    Mangesh

    1. It is an error, and the message says that you need to run ‘lxc info –show-log guiapps’ to obtain more info.

      Do that, and post a question at https://discuss.linuxcontainers.org/ in order to figure out what went wrong.

    • Jan on December 31, 2017 at 16:02
    • Reply

    Dear Simos,
    thank you very much for this article; it helped me starting a Firefox instance via Wayland (on Arch Linux, however). I have not played around with the audio yet, though.
    I put together a gist for making it work with Wayland: https://gist.github.com/stueja/447bd3bc0d510a0a7e50f9f1ef58ad75

    1. Thanks Jan!
      As I see it, you are using XWayland in Wayland in order to get the X apps to work.

        • Jan on January 21, 2018 at 21:26

        Dear Simos, yes, I did not find another `way’ so far 🙂

    • Giorgos on January 12, 2018 at 12:25
    • Reply

    I followed this tutorial but can’t get the xclock to show up
    ubuntu@guiapps:~$ export DISPLAY=:0
    ubuntu@guiapps:~$ xclock
    Invalid MIT-MAGIC-COOKIE-1 keyError: Can’t open display: :0
    everything is done ok until this step

    1. What OS do you run in the host? Check to see if you run Wayland (see the output of “echo $XDG_SESSION_TYPE”) which would require a bit of different instructions (xwayland, etc).

      The error means that the .Xauthority file (which contains the MIT-MAGIC-COOKIE security key) was not correct. Perhaps your host has a .ICEauthority instead? Check the timestamp of the .Xauthority to see if it is in use in the host.

        • Giorgos on January 13, 2018 at 06:56

        Hi!
        I use Ubuntu-16.04 for host, the output for session type is X11 and timestamp of .Xauthority is Nov 27.
        I have to mention that I use bridged network at the host and lxc is configured accordingly so to get lan reachable ips

        • Giorgos on January 13, 2018 at 06:57

        All these under gnome-shell

      1. The problem is then the .Xauthority file. Yours has a timestamp from a couple of months ago, while in reality it should have the timestamp of when you last booted your Ubuntu. When you boot your computer, the .Xauthority gets regenerated with a fresh cookie (by the X server). The apps read this cookie and use it to get access to the X server (who already knows the cookie value).

        Your session is “x11”, which means that your .Xauthority is probably located somewhere else and not in the home directory. Have a look in /var/. Normally, the $XAUTHORITY environment variable should have the location of .Xauthority (which is set by xauth). The apps check what $XAUTHORITY says, so it looks a bit weird for other GUI apps to work while ~myusername/.Xauthority is stale.

        It is OK if your LXD networking gives LAN IP addresses to the containers. The apps here communicate over sockets (not over IP).

        • Giorgos on January 13, 2018 at 13:14

        I found these two files but Iam not sure if it’s relevant to this

        ls -la
        Jan 13 12:34 /run/user/1000/gdm/Xauthority
        Jan 13 12:33 /run/user/121/gdm/Xauthority

      2. Most likely it is this one, /run/user/1000/gdm/Xauthority The default UID of the first user account in Ubuntu is 1000.

        Therefore, adapt the command in the tutorial to replace $XAUTHORITY with /run/user/1000/gdm/Xauthority

    • Giorgos on January 22, 2018 at 07:46
    • Reply

    I tried but
    xxxxxxx@desktop:~$ lxc config device add guiapps Xauthority disk path=/run/user/1000/gdm/Xauthority source=${XAUTHORITY}
    error: The device already exists
    and therefore xclock will not open
    xclock
    Error: Can’t open display:

    1. In your case, $XAUTHORITY is blank (if I understand correctly). Therefore, the source should be written as /run/user/1000/gdm/Xauthority

      All in all, first remove the old device, then add it as follows:

      $ lxc config device remove guiapps Xauthority

      $ lxc config device add guiapps Xauthority disk path=/home/ubuntu/.Xauthority source=/run/user/1000/gdm/Xauthority

  3. managed to get this howto to work great on a Linux mint laptop with intel graphics (for sound used tcp/ip rather than socket for pulseaudio). Good work and post!

    But on a pc with nvidia GT240

    lxc config device add ub3 mygpu gpu
    error: open /proc/driver/nvidia/gpus/0000:01:00.0/information: no such file or directory

    ub3 being the name of my container

  4. probably because I’m running lxd 2.18?

    lxd –version
    2.18

    but this is Ubuntu Mate 17.10!

    1. LXD 2.18 was released in September 2017. The GPU passthrough support was added much earlier in 2017,
      https://stgraber.org/2017/03/21/cuda-in-lxd/
      The full documentation of the options of the gpu device can be found at https://github.com/lxc/lxd/blob/master/doc/containers.md#type-gpu

      I suggest to start a new thread at https://discuss.linuxcontainers.org/ to look into this.

    • garnham on February 19, 2018 at 15:53
    • Reply

    Great article! This is way outside of my normal skill set and I’m really getting it with your writing style. So, thanks for sharing your skills.
    I got hung up on the gpu device but was able to get things moving without too much drama. I pasted the relevant bits below, in case it proves useful.

    —-
    Xubuntu 17.10
    Intel Mesa DRI Intel(R) HD Graphics 620 (Kaby Lake GT2)
    —-

    $ lxc config device add guiapps mygpu gpu
    error: open /proc/driver/nvidia/gpus/0000:01:00.0/information: no such file or directory

    $ apt show lxd
    Package: lxd
    Version: 2.18-0ubuntu6

    $ sudo apt-cache policy lxd
    lxd:
    Installed: 2.18-0ubuntu6
    Candidate: 2.18-0ubuntu6
    Version table:
    2.21-0ubuntu3~17.10.1 100
    100 http://ca.archive.ubuntu.com/ubuntu artful-backports/main amd64 Packages
    *** 2.18-0ubuntu6 500
    500 http://ca.archive.ubuntu.com/ubuntu artful/main amd64 Packages
    100 /var/lib/dpkg/status

    $ sudo apt install lxd=2.21-0ubuntu3~17.10.1

    The following packages have unmet dependencies:
    lxd : Depends: lxd-client (= 2.21-0ubuntu3~17.10.1) but 2.18-0ubuntu6 is to be installed
    E: Unable to correct problems, you have held broken packages.

    $ apt show lxd-client
    Package: lxd-client
    Version: 2.18-0ubuntu6

    $ sudo apt-cache policy lxd-client
    lxd-client:
    Installed: 2.18-0ubuntu6
    Candidate: 2.18-0ubuntu6
    Version table:
    2.21-0ubuntu3~17.10.1 100
    100 http://ca.archive.ubuntu.com/ubuntu artful-backports/main amd64 Packages
    *** 2.18-0ubuntu6 500
    500 http://ca.archive.ubuntu.com/ubuntu artful/main amd64 Packages
    100 /var/lib/dpkg/status

    sudo apt install lxd=2.21-0ubuntu3~17.10.1 lxd-client=2.21-0ubuntu3~17.10.1

    The following packages will be upgraded:
    lxd lxd-client
    2 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
    Need to get 6,130 kB of archives.
    After this operation, 16.6 MB of additional disk space will be used.
    Get:1 http://ca.archive.ubuntu.com/ubuntu artful-backports/main amd64 lxd amd64 2.21-0ubuntu3~17.10.1 [3,704 kB]
    Get:2 http://ca.archive.ubuntu.com/ubuntu artful-backports/main amd64 lxd-client amd64 2.21-0ubuntu3~17.10.1 [2,427 kB]
    Fetched 6,130 kB in 7s (854 kB/s)
    (Reading database … 234653 files and directories currently installed.)
    Preparing to unpack …/lxd_2.21-0ubuntu3~17.10.1_amd64.deb …
    Warning: Stopping lxd.service, but it can still be activated by:
    lxd.socket
    Unpacking lxd (2.21-0ubuntu3~17.10.1) over (2.18-0ubuntu6) …
    Preparing to unpack …/lxd-client_2.21-0ubuntu3~17.10.1_amd64.deb …
    Unpacking lxd-client (2.21-0ubuntu3~17.10.1) over (2.18-0ubuntu6) …
    Processing triggers for ureadahead (0.100.0-20) …
    Setting up lxd-client (2.21-0ubuntu3~17.10.1) …
    Processing triggers for systemd (234-2ubuntu12.1) …
    Processing triggers for man-db (2.7.6.1-2) …
    Setting up lxd (2.21-0ubuntu3~17.10.1) …

    1. Thanks!

      You have Ubuntu 17.10 which comes by default with LXD 2.18. However, by using the backports repository, you are installing the latest LXD, version 2.21.
      An alternative would be to migrate to the snap package of LXD, according to the instructions at https://blog.simos.info/how-to-migrate-lxd-from-deb-ppa-package-to-snap-package/
      However, since it works with the backports package, it is fine to keep using it.

      I notice that when you add the gpu device, it complains about an nvidia card (error: open /proc/driver/nvidia/gpus/0000:01:00.0/information: no such file or directory).
      Do you have a second graphics card on your computer (other than the Intel graphics card)?
      In one situation with a PC with an Intel graphics card, I think I managed to get the guide without adding the gpu device.
      I am not sure if you managed to complete the guide; if you cannot fix the issue with the gpu device, perform the test shown in the guide about graphics acceleration. It might work, so you can continue with the rest of the guide.

  5. Hi Simos,

    Great article. This is my first time trying out lxd containers.

    First my setup.
    My host is Ubuntu 17.10
    I have an onboard Intel video card that I’m not using.
    The video card I am using is: VGA compatible controller: NVIDIA Corporation GM204 [GeForce GTX 980] (rev a1)
    I’m running dual monitors from that card.
    I’m following your instructions as is so the lxd container is running ubuntu:x (16.04)
    $XDG_SESSION_TYPE is X11

    I’m was having a problem similar to Giorgos. I’m getting an error:
    Invalid MIT-MAGIC-COOKIE-1 keyError: unable to open display :0
    I was able to fix that by creating an X1 device and changing display to be :1 instead of :0.

    After that xclock runs just fine. The problem I now have is glxinfo -B give the output:
    name of display: :1
    libGL error: No matching fbConfigs or visuals found
    libGL error: failed to load driver: swrast
    Error: couldn’t find RGB GLX visual or fbconfig

    I’m not sure where to go from there. If you have any insights I’d appreciate it.

    Thanks

    1. Thanks!

      I think you are stumbling into driver issues inside the container.
      Have a look at this post, https://askubuntu.com/questions/834254/steam-libgl-error-no-matching-fbconfigs-or-visuals-found-libgl-error-failed-t
      You may have to attempt to install the NVidia driver in the container so that as a side-effect it will install any necessary drivers (swrast_dri.so) that are required.

        • Steven on March 29, 2018 at 19:53

        Awesome! That looks like it did it.

        Just for clarification. I opened the ‘Software & Updates’ app on the host machine and went to the ‘Additional Drivers’ tab. This listed the nvidia drivers installed, I am currently using the nvidia-384 package.

        Logged into the container and ran ‘sudo apt-get install nvidia-384’. Took a bit.

        Now I have:

        ubuntu@guiapps:~$ glxinfo -B
        name of display: :1
        display: :1 screen: 0
        direct rendering: Yes
        OpenGL vendor string: NVIDIA Corporation
        OpenGL renderer string: GeForce GTX 980/PCIe/SSE2
        OpenGL core profile version string: 4.5.0 NVIDIA 384.111
        OpenGL core profile shading language version string: 4.50 NVIDIA
        OpenGL core profile context flags: (none)
        OpenGL core profile profile mask: core profile

        OpenGL version string: 4.5.0 NVIDIA 384.111
        OpenGL shading language version string: 4.50 NVIDIA
        OpenGL context flags: (none)
        OpenGL profile mask: (none)

        OpenGL ES profile version string: OpenGL ES 3.2 NVIDIA 384.111
        OpenGL ES profile shading language version string: OpenGL ES GLSL ES 3.20

        ubuntu@guiapps:~$ glxgears
        Running synchronized to the vertical refresh. The framerate should be
        approximately the same as the monitor refresh rate.
        300 frames in 5.0 seconds = 59.921 FPS
        300 frames in 5.0 seconds = 59.949 FPS
        300 frames in 5.0 seconds = 59.950 FPS

        Thanks for the quick reply.

      1. Excellent! Thanks for reporting back!

        • Bill Wood on May 19, 2018 at 05:21

        Thanks so much for this guide, it is so well documented!

        I am getting this with glxinfo:
        libGL error: No matching fbConfigs or visuals found
        libGL error: failed to load driver: swrast

        My container is running in Ubuntu VM under Parallels on a Mac with an NVidia card. glxgears works ok although the framerate is very high.

        Here is the output from glxinfo:

        ubuntu@ub18:~$ glxinfo -B
        name of display: :0
        libGL error: No matching fbConfigs or visuals found
        libGL error: failed to load driver: swrast
        display: :0 screen: 0
        direct rendering: No (If you want to find out why, try setting LIBGL_DEBUG=verbose)
        OpenGL vendor string: Parallels and NVIDIA Corporation
        OpenGL renderer string: Parallels using NVIDIA GeForce GT 650M OpenGL Engine
        OpenGL version string: 1.4 (2.1 NVIDIA-10.30.25 355.11.10.10.30.120)

        Any ideas why I am getting the errors?

        • Bill Wood on May 19, 2018 at 05:24

        I forgot to add, I get this error in the host when adding the gpu:
        $ lxc config device add ub18 mygpu gpu
        Error: Failed to detect requested GPU device

        But glxgears runs

      2. @Bill Wood:

        The error message on *swrast* indicates that something more serious is wrong here.
        *swrast* is a driver for software-based graphics, therefore no hardware acceleration.

        Does Parallels offer hardware acceleration to a Linux distribution? Can you upload the output of `glxinfo` to pastebin and post the URL here?
        All these have been tested with Ubuntu 16.04 for both the host and the container. If you use different versions, then your mileage may vary.
        Others verified that these work with Ubuntu 18.04 (both host and container).

  6. Thank you very much for this tutorial. I am running into a problem with the command:

    lxc config device set lxcGaming gpu0 uid 1000

    it returns:

    error: Failed to setup device: Failed to create device /var/lib/lxd/devices/lxcGaming/unix.gpu2.dev-nvidia-modeset for /dev/nvidia-modeset: file exists

    i get the same return for gid 1000

    I have multiple Nvidia cards, and I’m trying to use my GTX1080 for an LXC container.

    Host and Guest are Ubuntu 16.04

    Thank you!

    1. Thanks!

      You mention you have many GPUs. Did you specify which GPU you are adding like below?

      lxc config device add lxcGaming gpu0 id=0

      The full documentation on this is at
      https://github.com/lxc/lxd/blob/master/doc/containers.md#type-gpu

      I am not familiar with the error. If the above does not fix it, then post at https://discuss.linuxcontainers.org/ (the support forum for LXD) and we will have a look at it.

      • Sergey on May 28, 2018 at 00:01
      • Reply

      You should stop the container before setting rights on the gpu device.
      lxc stop guiapps
      And then start it back after rights setting
      lxc start guiapps

    • Marcos dos Santos de Oliveira on April 4, 2018 at 21:07
    • Reply

    Very good guide, but I was having the following errors on my setup (nvidia card with nouveau drivers):
    libGL error: failed to open drm device: No such file or directory
    libGL error: failed to load driver: nouveau

    Fixed adding the following:
    lxc config device add guiapps card0 unix-char path=/dev/dri/card0 gid=44

    This command add an unix-char device to the /dev/dri/ directory in the container… By the way, to keep it consistent with what I had in the host, I used the default uid and gid at the gpu device also, which is 0:44 (root:video), because the ubuntu user was already in the video group and if it wasn’t we could add it. I used the following command:

    lxc config device add guiapps mygpu gpu gid=44

    1. Many thanks!

      I added your comment to the main article.

  7. Exceptional useful! Thanks your effort!

    1. Thanks!

    • Eloston on April 10, 2018 at 19:55
    • Reply

    Thanks for the guide! It helped me transition my unprivileged LXC container over to LXD. I’m running Debian 9 with a Debian 9 container, Linux 4.14 from stretch-backports, and a custom backport based on LXD 3.0.0-0ubuntu3.

    Though I ran into some weird troubles with accelerated graphics. By using the “gpu” device type for acceleration, my OpenGL program (Wine) would cause the display to hang for a little bit before crashing with “libGL error: MESA-LOADER: failed to retrieve device information”. I initially worked around the problem by using the disk type on /dev/dri, but some searching led me to find out that libdrm in the container was the problem: libdrm 2.4.74 that comes by default is too old; 2.4.89 from stretch-backports works. (I’m also running Kabylake graphics which may be impacting this).

    About PulseAudio: It might be worth mentioning how to use the Unix socket instead of a TCP connection for those who exclusively run their containers on their local machines. I was able to get mines to work by mounting /run/user/1000/pulse/native to /tmp/.pulse_native, and then setting that path for PULSE_SERVER. No pulse cookie needed.

    1. Thanks for the feedback.

      Indeed, the versions of core libraries in the container should roughly match the versions on the host. That is required specifically for good accelerated graphics support. Ideally, there should be a table listing which container OS versions match with what host OS.

      I’ll try again with the PulseAudio Unix socket for the updated tutorial.

    • Martin John on April 27, 2018 at 14:52
    • Reply

    I found issues on the audio side when running on Ubuntu 18.04, where I’d get the following error

    $ speaker-test -Dpulse -c6 -twav

    speaker-test 1.1.3

    Playback device is pulse
    Stream parameters are 48000Hz, S16_LE, 6 channels
    WAV file(s)
    ALSA lib pcm.c:2495:(snd_pcm_open_noupdate) Unknown PCM pulse
    Playback open error: -2,No such file or directory

    Once I installed pulseaudio in the container (sudo apt install pulseaudio), it works fine

    $ speaker-test -Dpulse -c6 -twav

    speaker-test 1.1.3

    Playback device is pulse
    Stream parameters are 48000Hz, S16_LE, 6 channels
    WAV file(s)
    Rate set to 48000Hz (requested 48000Hz)
    Buffer size range from 32 to 349525
    Period size range from 10 to 116509
    Using max buffer size 349524
    Periods = 4
    was set period_size = 87381
    was set buffer_size = 349524
    0 – Front Left
    4 – Center
    1 – Front Right
    3 – Rear Right
    2 – Rear Left
    5 – LFE

    1. Thanks for the feedback.

  8. Howdy! I’m trying to run through this example on ubuntu 18.04. A few notes:

    1) The text says “For the host, this file can be found in the variable $XAUTHORITY and should be either at ~/.Xauthority or /run/myusername/1000/gdm/Xauthority”
    That 2nd path should probably be /run/user/1000/gdm/Xauthority.

    2) $UID is not set in sh, only in bash. If you’re using sh, you have to do UID=$(id -u)
    to use the examples.

    3) Check the value of $DISPLAY before following the tutorial. In my case it was :1… which surprised the heck out of me, and caused mysterious “Invalid MIT-MAGIC-COOKIE-1 keyError: Can’t open display: :0” errors when running xclock inside the container. Evidently my system has two copies of Xorg running, possibly because I have both intel and nvidia graphics cards.

    4) after lxc launch, I had to wait a while before networking came up in the container, e.g.

    lxc launch ubuntu:18.04 guiapps
    until lxc exec guiapps apt update && lxc exec guiapps apt install x11-apps mesa-utils alsa-utils
    do
    sleep 2
    done

    5) Tearing down lxd properly to try the recipe again is a bit of a challenge, see
    https://discuss.linuxcontainers.org/t/reliable-script-to-set-up-and-tear-down-a-demo-of-lxd-was-hard-to-write/1931/2

    I’m collecting possible workarounds for some these problems in my canned script that runs through your demo, http://kegel.com/linux/lxdgpu.sh.txt

    1. Thanks for the feedback!

      I updated the post to reflect items 1, 2 and 3.

      For item 4, it is possible to include those package management commands in *cloud-init* so they happen automatically. Still, it takes a tens of seconds for a freshly launched container to update the package list and install the packages.

      For item 5, I think that it would be good to separate the tearing-down of the whole LXD installation from the setup of GUI containers (I know we talked about this already on discuss.linuxcontainers.org 🙂 ).

      Thanks for putting them all in a script. It will help me when I try to automate the process as well.

  9. Found one more gotcha! I tried running through the recipe without rebooting, and was getting “No protocol specified” errors from xclock. Turns out Xorg didn’t realize I was in the lxd group, so was rejecting my unix socket credentials (had to strace Xorg to see that). Rebooting after installing lxd solves that.

    And one more nice thing: you can tell lxd exec to pass an environment variable, e.g. -e DISPLAY=$DISPLAY to avoid hardcoding its value. Turns out it’s pretty common for that to be something other than :0 these days.

    I’ve updated http://kegel.com/linux/lxdgpu.sh.txt to mention/use those, it’s now rather reliable.

    Finally, those who have older nvidia cards may run into the error “No device minor index detected”. I filed https://github.com/lxc/lxd/issues/4617 for that and https://github.com/lxc/lxd/pull/4618 to fix the most common case.

    1. Grr. Rebooting does *not* solve the “no protocol specified” errors in my specific case. xhost + works around it. Still investigating.

        • Hegz on June 14, 2018 at 18:05

        I’m in the same boat at the moment. Only the ‘xhost +’ will allow xclock to work..

        • Hegz on June 14, 2018 at 19:17

        Okay, So I think I found something on this:

        it looks like in my case the hostname included in the x authority file is important. I was able to get things working without the xhost requirement with the following:

        (guest)$ xauth list
        Host/unix:0  MIT-MAGIC-COOKIE-1  HostHexKey…
        (guest)$ export XAUTHORITY=/home/ubuntu/.Xauthority-n
        (guest)$ xauth add $DISPLAY . HostHexKey…

        now

        (guest)$ xauth list
        Guest/unix:0  MIT-MAGIC-COOKIE-1  HostHexKey…

        and xclock works as expected.

        Just need to figure out a way to do that automatically…. and solve my nvidia driver mismatch issue..

      1. @Hegz:

        Is your case also on Ubuntu 18.04 (and container Ubuntu 18.04)?

        • Hegz on June 16, 2018 at 15:10

        No my host is arch. Guest was ubuntu.

      2. @Hegz: When you have to use *xauth add …*, it’s an indication that the sharing of the X11 host key to the container did not work. And you end up allowing the client manually, as if you have a separate computer that wants to display on your desktop’s X11 server.

        When you see *.Xauthority-n* (the **n**), it is an indication that the software did not manage to work with the plan .Xauthority. Personally, I would clear up and start over.

        • Adam J Fairbrother on June 18, 2018 at 04:13

        I have to assume that you’re right on all points above, However all of the xauth commands were run from withing the container, guiapps. The Xauthority file was there, and identical to the host, referenced correctly by the shell variable and able to be queried by xauth.

        I did leave out the bit where ‘xauth add …’ reported that it was unable to write to .Xauthority and as such created .Xauthority-n, at the time the guest being unable to write to the hosts file seemed quite normal.

        Either way, I have a solution for this small issue that works for me, and I just wanted to share it here to help anyone else that may be in a similar situation. If it’s bad information please remove my posts.

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

  2. […] Θέλουμε να εγκαταστήσουμε μια εφαρμογή γραφικού περιβάλλοντος με χρήση επιτάχυνσης υλικού για γραφικά, αλλά να μην μπλέξει με το σύστημά μας. Εγκαθιστούμε την εφαρμογή γραφικού περιβάλλοντος σε π…. […]

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

  4. […] LXD containers are located on your desktop computer, then you have the option to follow the guide How to run graphics-accelerated GUI apps in LXD containers on your Ubuntu desktop. There is an alternative though with the X2Go remote desktop, which has the following […]

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

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

  7. […] the H.264 codec following this guide works, just like last time. I let the container use hardware acceleration on the graphics […]

  8. […] to the host. I have not been able to find any guide for this, the closest thing I found was this guide, which explains how to let the container create windows in your already running X session. I will […]

Leave a Reply

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

%d bloggers like this: