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

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

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

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 | 10.0.185.63 (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: 
root:1000:1
$

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

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 https://wiki.winehq.org/Ubuntu.

$ lxc exec wine-games -- sudo --login --user ubuntu
ubuntu@wine-games:~$ sudo dpkg --add-architecture i386 
ubuntu@wine-games:~$ wget https://dl.winehq.org/wine-builds/Release.key
--2017-05-01 21:30:14--  https://dl.winehq.org/wine-builds/Release.key
Resolving dl.winehq.org (dl.winehq.org)... 151.101.112.69
Connecting to dl.winehq.org (dl.winehq.org)|151.101.112.69|: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
OK
ubuntu@wine-games:~$ sudo apt-add-repository https://dl.winehq.org/wine-builds/ubuntu/
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
...
ubuntu@wine-games:~$

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 http://cdn.gametop.com/free-games-download/Season-Match4.exe
ubuntu@wine-games:~$ wine Season-Match4.exe 
...
ubuntu@wine-games:~$ cd .wine/drive_c/Program\ Files\ \(x86\)/GameTop.com/Season\ Match\ 4/
ubuntu@wine-games:~/.wine/drive_c/Program Files (x86)/GameTop.com/Season 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!

12 comments

  • Doug Brunelle

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

    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.

    Regards,
    Doug
    San Diego, CA

  • Simos Xenitellis

    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.

  • Doug Brunelle

    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.

  • jacky

    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

  • Simos Xenitellis

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

Leave a Reply

%d bloggers like this: