Documenting Problems That Were Difficult To Find The Answer To

Monthly Archives: May 2019

Getting NVidia Working with LXC Container and Steam Game Client

I’ve written before about creating an LXC container with X11 and sound support.

The process is much the same for the Steam game client (which requires GLX). But I’ll go through the entire process along with the Steam-specific actions requires.

This is written specifically for Ubuntu Linux 16.04 Xenial. The LXC container created, including libraries and Steam client, consumes around 2.3GB of storage. Download the game Cities Skylines with Mass Transit and that blows out to 9.4GB.

It is assumed that you installed your NVIDIA drivers on your host (not in a LXC container) by running (or similar) as root outside of any X session which you downloaded from the NVidia Unix driver archive.

Firstly create a LXC container with the name “steam”.

$ sudo lxc-create -n mysteam -t ubuntu -- -r xenial
# The default user is 'ubuntu' with password 'ubuntu'!
# Use the 'sudo' command to run tasks as root in the container.
$ sudo lxc-start -d -n mysteam
$ sudo lxc-ls -f
mysteam       RUNNING 0         - -

Then we need to install a variety of packages. So enter a console session (remember that you will need to press ctrl-A, Q to exit the console when finished):

$ sudo lxc-console -n mysteam
mysteam login: ubuntu
Password: ubuntu

# required for X11 forwarding over SSH
ubuntu@mysteam:~$ sudo apt-get install xauth

# optional install for xclock application (for testing)
ubuntu@mysteam:~$ sudo apt-get install x11-apps

# exit console
ctrl-A, then q

Next to install audio. First confirm you have pulseaudio running on your (non-LXC) host:

$ xprop -root PULSE_SERVER
PULSE_SERVER(STRING) = "{0e1da16b3f5b8cc7f23766efa2f30673}unix:/run/user/1000/pulse/native tcp:localhost:4713 tcp6:localhost:4713"

Also, on your host, run paprefs, select the “Network Server” (2nd) tab, and make sure the first option “Enable network access to local sound devices” is ticked (you will have to do this every time you log into your X Windows). This will allow your container to send audio over a SSH session (more on that later).

Now – we pick a random port number that isn’t being used, say, 54321. In future when we SSH to the container we will have to tell the container that a connection to 54321 in the container should result in a connection to whatever the output of the xprop command was earlier (e.g. “localhost:4713”). That’s in addition to supporting X protocol over SSH. So you would use a SSH command like:

$ ssh -X -R 54321:localhost:4713 ubuntu@
ubuntu@'s password: ubuntu

# add the following line to /home/ubuntu/.bashrc
export PULSE_SERVER="tcp:localhost:54321"

# required for audio from container
ubuntu@mysteam:~$ sudo apt-get install pulseaudio

# logout from SSH session to container
ubuntu@mysteam:~$ exit

We should have working X11 forwarding and audio.

Now for the tricky part – NVidia and GLX support!

Edit the LXC container configuration, /var/lib/lxc/mysteam/config, to pass through the various devices used by the NVidia driver from the host to the container (thanks to this article for the information). Add the following (to the bottom of the configuration file, or anywhere):

# GPU Passthrough config
lxc.cgroup.devices.allow = c 195:* rwm
lxc.cgroup.devices.allow = c 243:* rwm
lxc.mount.entry = /dev/nvidia0 dev/nvidia0 none bind,optional,create=file
lxc.mount.entry = /dev/nvidiactl dev/nvidiactl none bind,optional,create=file
lxc.mount.entry = /dev/nvidia-uvm dev/nvidia-uvm none bind,optional,create=file
lxc.mount.entry = /dev/nvidia-modeset dev/nvidia-modeset none bind,optional,create=file
lxc.mount.entry = /dev/nvidia-uvm-tools dev/nvidia-uvm-tools none bind,optional,create=file

Copy in your NVidia driver file into the container, and restart the container (to pick up the configuration changes):

$ sudo cp ~/Downloads/ /var/lib/lxc/mysteam/rootfs/home/ubuntu/
$ sudo lxc-stop -n mysteam
$ sudo lxc-start -d -n mysteam

SSH back into the container and we will install the driver and GLX support:

$ ssh -X -R 54321:localhost:4713 ubuntu@
ubuntu@'s password: ubuntu

# Add 386 support, we'll need this when installing NVidia driver, or else Steam will complain with "glXChooseVisual failed" error
ubuntu@mysteam:~$ sudo dpkg --add-architecture i386
ubuntu@mysteam:~$ sudo apt-get update
ubuntu@mysteam:~$ sudo apt-get install libc6:i386

# Add pkg-config to minimise warnings during NVidia driver installation
ubuntu@mysteam:~$ sudo apt-get install pkg-config

# Set executable permissions for NVidia driver and execute
# - ignore warning about not installing a kernel module (we don't want it anyway)
# - ignore warning about being forced to guess X library path (we don't care)
# - select YES to install 32-bit compatibility libraries, if this option isn't presented then go back and install libc6:i386 package (Steam client will throw "glXChooseVisual" error if this step is missed)
# - ignore request to get your X config automatically updated (container is not running X client)
ubuntu@mysteam:~$ sudo chmod 755 /home/ubuntu/
ubuntu@mysteam:~$ sudo /home/ubuntu/ --no-kernel-module

# Test to see if NVidia card is found (only works if NVidia driver on host and container are absolutely identical)
ubuntu@mysteam:~$ nvidia-smi
Sun May 26 08:06:54 2019       
| NVIDIA-SMI 418.56       Driver Version: 418.56       CUDA Version: 10.1     |
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|   0  GeForce GTX 750 Ti  Off  | 00000000:01:00.0  On |                  N/A |
| 30%   38C    P8     1W /  38W |    173MiB /  1993MiB |      0%      Default |
| Processes:                                                       GPU Memory |
|  GPU       PID   Type   Process name                             Usage      |

# install GLX support
ubuntu@mysteam:~$ sudo apt-get install mesa-utils

# test whether GLX support is working
ubuntu@mysteam:~$ glxinfo
name of display: localhost:10.0
display: localhost:10  screen: 0
direct rendering: Yes
server glx vendor string: NVIDIA Corporation
server glx version string: 1.4

# if the following works you will have a moving image of gears on your display
ubuntu@mysteam:~$ glxgears

Honestly, that’s the hardest part done! Now all that is left is to install the Steam client.

Either download the Debian install package from or:

ubuntu@mysteam:~$ sudo apt-get install wget

# get the Debian steam client package, the URL comes from
ubuntu@mysteam:~$ wget

# install dependencies FIRST
# - if you forget this and run the steam install first and get dependency errors then run "apt-get remove steam-launcher" and then retry this command
ubuntu@mysteam:~$ sudo apt-get install python curl python-apt xterm zenity

# install package
ubuntu@mysteam:~$ sudo dpkg -i steam.deb

# run the Steam client! (ignore warnings)
ubuntu@mysteam:~$ steam &
Setting up Steam content in /home/ubuntu/.local/share/Steam
Steam needs to install these additional packages:
        libgl1-mesa-dri:i386, libgl1-mesa-glx:i386
[sudo] password for ubuntu: ubuntu
Updating Steam...
Downloading update (132,000 of 284,881 KB)...

And that’s it! You should have a running Steam client in Ubuntu Linux.

I haven’t figured out to get rid of all running processes when I’m finished with Steam – so I just shut down my container.

Remember, if you get the following from the Steam client, then you’ll need to reinstall NVidia driver with 32-bit compatibility libraries:

[2019-05-24 10:45:16] Verifying installation...
[2019-05-24 10:45:16] Performing checksum verification of executable files
[2019-05-24 10:45:18] Verification complete
glXChooseVisual failed
glXChooseVisual failedMain.cpp (332) : Assertion Failed: Fatal Error: glXChooseVisual failed
Main.cpp (332) : Assertion Failed: Fatal Error: glXChooseVisual failed

AMD GPU Passthru/Passthrough

Tested with glxgears on AMD Ryzen 4500U processor with in-built GPU.

Add the following to the /var/lib/lxc/mysteam/config:

# AMD GPU Passthrough config
# crw-rw----+ 1 root video 226, 0 Dec 20 20:22 /dev/dri/card0
# crw-rw----+ 1 root render 226, 128 Dec 20 20:22 /dev/dri/renderD128
lxc.cgroup.devices.allow = c 226:* rwm
lxc.mount.entry = /dev/dri/card0 dev/dri/card0 none bind,optional,create=file
lxc.mount.entry = /dev/dri/renderD128 dev/dri/renderD128 none bind,optional,create=file

Note that this is using a Linux 5.8 kernel.

$ cat /proc/version
Linux version 5.8.0-33-generic (buildd@lgw01-amd64-010) (gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0, GNU ld (GNU Binutils for Ubuntu) 2.34) #36~20.04.1-Ubuntu SMP Wed Dec 9 17:01:13 UTC 2020