How to run Wine (graphics-accelerated) in an LXD container on Ubuntu

Update 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 GUI output on the host’s deskttop. The updated post covers how to run application under Wine as well.

Update #2: Added info about setting the permissions for the gpu device.

Update #1: Added info about adding the gpu configuration device to the container, for hardware acceleration to work (required for some users).

Wine lets you run Windows programs on your GNU/Linux distribution.

When you install Wine, it adds all sort of packages, including 32-bit packages. It looks quite messy, could there be a way to place all those Wine files in a container and keep them there?

This is what we are going to see today. Specifically,

  1. We are going to create an LXD container, called wine-games
  2. We are going to set it up so that it runs graphics-accelerated programs. glxinfo will show the host GPU details.
  3. We are going to install the latest Wine package.
  4. We are going to install and play one of those Windows games.

Creating the LXD container

Let’s create the new container for LXD. If this is the first time you use LXD, have a look at Trying out LXD containers on our Ubuntu.

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

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

Let’s also install our initial testing applications. The first one is xclock, the simplest X11 GUI app. And glxinfo, that shows details about graphics acceleration. We will know that our set up in Wine works, if both xclock and glxinfo work in the container!

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

We execute a login shell in the wine-games container as user ubuntu, the default non-root username in Ubuntu LXD images.

Then, we run apt update in order to update the package list and be able to install the subsequent two packages that provide xclock and glxinfo respectively. Finally, we exit the container.

Setting up for 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.

First, we run (only once) the following command (source),

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

The command adds 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 wine-games LXD container, and restart the container for the change to take effect.

$ lxc config set wine-games raw.idmap "both $UID 1000"
$ lxc restart wine-games

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

Let’s attempt to run xclock in the container.

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

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 default :0 (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 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

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.

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 wine-games mygpu gpu
$ lxc config device set wine-games mygpu uid 1000
$ lxc config device set wine-games mygpu gid 1000

We add the gpu device, and we happen to name it mygpu (any name would suffice). [UPDATED] In addition, we set the uid/gui of the gpu device to 1000 (the default uid/gid of the first non-root account on Ubuntu; adapt accordingly on other distributions). 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 Please leave a comment below if this was your case (mention what LXD version you have been running).

Let’s see what we got now.

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

ubuntu@wine-games:~$ glxinfo 
name of display: :0
display: :0  screen: 0
direct rendering: Yes
server glx vendor string: SGI
server glx version string: 1.4
ubuntu@wine-games:~$ echo "export DISPLAY=:0" >> ~/.profile 
ubuntu@wine-games:~$ 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.

Installing Wine

We install Wine in the container according to the instructions at

$ lxc exec wine-games -- sudo --login --user ubuntu
ubuntu@wine-games:~$ sudo dpkg --add-architecture i386 
ubuntu@wine-games:~$ wget
--2017-05-01 21:30:14--
Resolving (
Connecting to (||:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 3122 (3.0K) [application/pgp-keys]
Saving to: ‘Release.key’

Release.key                100%[=====================================>]   3.05K  --.-KB/s    in 0s      

2017-05-01 21:30:15 (24.9 MB/s) - ‘Release.key’ saved [3122/3122]

ubuntu@wine-games:~$ sudo apt-key add Release.key
ubuntu@wine-games:~$ sudo apt-add-repository
ubuntu@wine-games:~$ sudo apt-get update
Reading package lists... Done
ubuntu@wine-games:~$ sudo apt-get install --install-recommends winehq-devel
Need to get 115 MB of archives.
After this operation, 715 MB of additional disk space will be used.
Do you want to continue? [Y/n] Y

715MB?!? Sure, bring it on. Whatever is installed in the container, stays in the container! 🙂

Let’s run a game in the container

Here is a game that looks good for our test, Season Match 4. Let’s play it.

ubuntu@wine-games:~$ wget
ubuntu@wine-games:~$ wine Season-Match4.exe 
ubuntu@wine-games:~$ cd .wine/drive_c/Program\ Files\ \(x86\)/\ Match\ 4/
ubuntu@wine-games:~/.wine/drive_c/Program Files (x86)/ Match 4$ wine SeasonMatch4.exe

Here is the game, and it works.It runs full screen and it is a bit weird to navigate between windows. The animations though are smooth.

We did not set up sound either in this post, nor did we make nice shortcuts so that we can run these apps with a single click. That’s material for a future tutorial!

Permanent link to this article:


4 pings

Skip to comment form

  1. Very interesting, Simos. Thank you for posting this. I’m new to lxc and containers, so I am trying to learn from people like you, who are much further ahead in knowledge of lxc usage (and probably linux in general!).

    I followed your directions, and I was able to get to the point where I successfully launched ‘xclock’ from the command line- and a small window popped up displaying the clock. However, the shell was blocked from entering any other commands while xclock was running. I stopped xclock with Ctrl-C and got back the command prompt, and I entered ‘glxinfo’, but it gave me the following error messages:

    ubuntu@wine-games:~$ 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: 154 (GLX)
    Minor opcode of failed request: 6 (X_GLXIsDirect)
    Serial number of failed request: 48
    Current serial number in output stream: 47

    I wonder what I might do to fix this so that I get the correct information back, as in your article. I’m able to run xclock, so apparently the GUI is running okay in the container. But it seems to be missing something.

    San Diego, CA

    1. Thanks for the feedback Doug.
      Normally there is an additional command that was required, but was not needed for my case (and perhaps GPU?).
      Could you please run the following on your host:

      $ lxc config device add wine-games gpu gpu

      With this command, you add this special device called gpu (and give the name gpu, that’s why it written twice).
      Once you do that, try glxinfo again and please report back.

    2. Indeed, when you run xclock (or any other GUI program), the shell is blocked from entering any other commands, until that GUI program is terminated (click on the x on its window, or Ctrl-C like you did).

      Since you get an error with glxinfo and specifically an error that says that no hardware acceleration is available, then something fundamental is missing.
      Another user reported that when adding the gpu device, it is required to set the permissions as well. See my update to this blog post that sets the appropriate permissions to the mygpu device.

      Do you have an AMD or Nvidia graphics card? For Intel GPU I did not have to deal with the gpu device, nor set the permissions (hence the ommission).

  2. Thanks for the suggestion! After the command “lxc config device add wine-games gpu gpu”, I ran glxinfo, and got several screens of information. I used the -B option to get a more condensed version:

    : glxinfo -B
    name of display: :0
    display: :0 screen: 0
    direct rendering: Yes
    OpenGL vendor string: NVIDIA Corporation
    OpenGL renderer string: GeForce GTX 970M/PCIe/SSE2
    OpenGL core profile version string: 4.5.0 NVIDIA 375.39
    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 375.39
    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 375.39
    OpenGL ES profile shading language version string: OpenGL ES GLSL ES 3.20

    By the way, I am able to run graphical programs such as Firefox in the container. I may try to install Wine as you suggest in the article. Thanks for your help.

    1. Many thanks Doug for the feedback.

      I have updated the post to include the addition of the gpu device.

    • jacky on May 12, 2017 at 10:43
    • Reply

    It seens that I can’t run vaapi for video decoding:
    ubuntu@lxd-test:~$ vainfo
    libva info: VA-API version 0.39.0
    libva info: va_getDriverName() returns -1
    libva error: va_getDriverName() failed with unknown libva error,driver_name=(null)
    vaInitialize failed with error code -1 (unknown libva error),exit

    1. It worked on this computer,

      ubuntu@guiapps:~$ vainfo
      error: XDG_RUNTIME_DIR not set in the environment.
      libva info: VA-API version 0.39.0
      libva info: va_getDriverName() returns 0
      libva info: Trying to open /usr/lib/x86_64-linux-gnu/dri/
      libva info: Found init function __vaDriverInit_0_39
      libva info: va_openDriver() returns 0
      vainfo: VA-API version: 0.39 (libva 1.7.0)
      vainfo: Driver version: Intel i965 driver for Intel(R) Haswell Desktop – 1.7.0
      vainfo: Supported profile and entrypoints
      VAProfileMPEG2Simple : VAEntrypointVLD

      I used the newer guide at which has some additional steps.

    • helmutzemo98 on December 20, 2017 at 06:12
    • Reply

    I have problem setting up as my host machine has arch linux with wayland setup so there is no .Xauthority file can graphics be setup using wayland support.

    1. I had not tried yet with Ubuntu 17.10 (which has Wayland) and I cannot be of help at the moment.
      Does Wayland come with XWayland? This might help you.

  3. Amazing!!! Now I can install unlicensed windows games and do not worry about my PC security!

      • n1 on September 22, 2019 at 16:57
      • Reply

      That’s a crazy opinion as the GUI app in the container can do almost everything with your host’s X server

      1. This guide shows the easy way of setting up LXD containers to show GUI apps on your host’s X server.
        It is somewhat easy to use Xephyr instead, and have those apps appear in the Xephyr desktop window.

        In addition, those Windows apps are running through Wine on Linux. It is not straightforward to create such a Windows application that manages to escape the Wine emulator and interact directly with the X server.
        If you happen to know of such a proof-of-concept Windows application, I would love to hear about it.

  4. Hey guys, if you are using fish shell you should go to bash because fish does not support $UID, so most of the commands will run wrong!!

  1. […] 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 […]

  2. […] Θέλουμε να εγκαταστήσουμε μια εφαρμογή στο Wine αλλά ΔΕΝ ΘΕΛΟΥΜΕ να εγκατασταθούν όλα αυτά τα πακέτα που φέρνει το Wine. Εγκαθιστούμε το Wine σε περιέκτη LXD. […]

  3. […] with GPU acceleration, but you do not get isolation between the container and the host. I have written several tutorials on […]

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

Leave a Reply

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