Last updated:
Lxc Desktops
This article focuses on configuring an lxc container for use as a desktop. I'll skip the pros and cons for the moment. Except maybe to challange those that fear the security ramifications to consider; how is running a container as a desktop any less secure than doing so bare naked on the host?
Being that as it may. Security is not the driving force for wanting to consolidate my desktop usage to a container. But convevience and portability. I'm less concerned about security breaches on my local network. I just want to maintain a simplified consistant desktop experience across multiple host environments.
Options
There are several options available to us for accessing our container's desktop...
- Vnc: via vncviewer and/or NoVnc (web access). These are good remote solutions. However vnc is outside the scope of the article so I'll be skipping any further discussion of it here.
- Xephyr: I wrote previously that using a Xephyr session was buggy and slow. Since then some upgrades in the X server and such have improved the performance of Xephyr to the point of even allowing GLX 3d graphics support!. Making this a convenient solution while already logged in graphically on the host.
- Native X: Logging in to the container desktop via the host's X server from the console or virtual tty's.
Pre-requisites
The instructions in this article assume the following...
- Container: A complete desktop installation with an xdm login manager.
- Host: A working lxc environment complete with a bridged virtual network and at least an Xorg server. A full desktop system is not required. However for audio to work pulseaudio should be present.
- Video card: The setup here is expecting the standard intel video card. Special consideration for Nvidia or ATI cards are not discussed. If you have one of these cards you will need to install the appropriate modules etc... and configure your system to use them.
Note: If using Slackbuilder as the host you can build a Slackbuilder container with a simple command that will pre-configure the container for you. The hosts pulseaudio default.pa file will still need to be edited manually though.
XIT=1 ve add cname
Where ve is a command that manages containers. XIT tells the lxc-slackbuilder template to install a desktop system. And cname is the name of the container.
The environment variable XIT is used here instead of simply X because apparantly X is already defined somewhere within the official lxc scripts. Re-defining it on the command line caused intallation failure.
XDM
For non Slackbuilder users. Once you have your container up and running its time to edit its xdm-config and Xaccess files. On Slackware they are located in /etc/X11/xdm. On other distributions the location of these files may vary.
For xdm-config comment out the following line with an !...
DisplayManager.requestPort: 0
Change to...
! DisplayManager.requestPort: 0
And for Xaccess uncomment...
#* #any host can get a login window
Change to...
* #any host can get a login window
Now start the xdm server. Additionally consider adding this service to the container bootup scripts.
Pulseaudio
To get audio working we need to edit the default.pa file as we are running pulseaudio on a per user basis not as a system service. On Slackware it will be in /etc/pulse/. Again, on other distros location may vary.
There are two ways to handle the sound.
- Redirect the container users pulseaudio server to use the hosts directly. This is the best solution for connecting to a guest from the host.
- Use RTP unicasting to the host. Good for re-routing audio to a sound server etc...
We're going to use the redirect option for our purposes. Either way both options need the following line added to the container default.pa file.
load-module module-native-protocol-tcp
For the host add...
load-module module-native-protocol-tcp auth-ip-acl=127.0.0.1;10.0.2.0/24
The 10.0.2.0/24 is the default subnet for SlackBuilder's virtual network. Yours may be different. This tells pulseaudio to listen on the loopback and virtual networks for connection requests.
Container User setup
We need to have a user in the container to login to with the standard desktop permissions. ie: audio, video, netdev etc...
Using SlackBuilder this can be done with...
sbuser -a username
xdm looks for the file ~/.xprofile to execute. If one does not exist it just starts an xsession with an xterm terminal. If you don't already have this file create it and add the following...
PULSE_SERVER=vmhost /etc/X11/xinit/xinitrc.Sbuilderbox
This line is specifit to SlackBuilder but the concept should apply across all distros. The PULSE_SERVER variable tells pulseaudio to use the vmhost server. Which in this case is 10.0.2.1. The vmhost hostname is pre-configured on a SlackBuilder system. If using another distro just add the ip address of your bridge dnsmasq server.
SlackBuilder uses a custom configured openbox desktop and is started with the /etc/X11/xinit/xinitrc.Sbuilderbox script. You may be using something else. If so just add it here instead. It is assumed that pulseaudio is being initiated on startup with X11 modules loaded.
Update: I've noticed on Alpine linux that xdm is configured to execute the ~/.xsession file instead. Also it requires an extra bash login bit...
PULSE_SERVER=vmhost /bin/bash -l /etc/X11/xinit/xinitrc.Sbuilderbox
Connecting
At this point we have configured the containers xdm server. Configured puluseaudio for both the container and the host. Added a container user and created an .xprofile/.xsession script to start a desktop. All that remains is to connect to the xdm server from the host.
Xephyr
If you are already logged in to an X session on your host you can connect to the container xdm server via Xephyr like so...Pulseaudio is assumed to be already running on the host
Xephyr -ac -br +xinerama -resizeable -screen $size -query $host :$dsp
-ac disable access controle restrictions
-br create root window with black background -- optional
+xinerama enable XINERAMA extension
-resizeable enable resizing of the Xephyr window
$size is in the form of 1280x720
-query a remote host
$host the container hostname or ip address
$dsp is a display number greater than 0
SlackBuilder comes with some scripts to connect to it's containers for convenience. The one for Xephyr is xephconnect. Here is the output of running it with no arguments...
--> xephconnect ------------------------------------------------- Connect to a remote host xdm server via Xehpyr... execute from an X session. ------------------------------------------------- Usage: xephconnect [options] [arg1] [arg2] [arg3] where... [arg1] is a hostname [arg2] is an X display...0, 1, 2, etc... [arg3] is a screen size...1280x720, 1920x1080, etc... Default values for missing args... [arg2] == 1 [arg3] == 1280x720 If no args at all... xephconnect looks for a host in ~/.config/sbx.conf. The same file that 'startsbx' uses. If the file doesn't exist or is empty then this help message is presented. Options: -h) show this help message
Native X
Be sure to logout of any currently running X session. If your host is starting up in runlevel 5 you need to reconfigure your system to boot up to runlevel 3 and reboot. We need to be logged in to a regular tty virtual console. If you've had to reboot make sure that your container is up and running with xdm started.
Assuming you are now logged in to the console as a regular user with desktop appropriate permissions, issue the following commands...
pulseaudio & X -once -ac -query hostname
Pulseaudio needs to be started on the host first so the container can use it. Then we start X with the -once option so that when the container desktop quits the X server stops and doesn't drop back into the xdm login prompt. -ac and -query are defined in the Xephyr section above. X & Xephyr share a subset of the same options.
The SlackBuilder script to connect to a container via native X is startsbx. Here is the output of running it with no arguments...
--> startsbx -------------------------------------------- Connect to a remote host xdm server via X... execute from a console -------------------------------------------- Usage: startsbx [options] [arg1] where... [arg1] is a hostname If no args at all... startsbx looks for a host in ~/.config/sbx.conf. The same file that 'xephconnect' uses. If the file doesn't exist or is empty then this help message is presented. Options: -h) show this help message
Note: xephconnect & startsbx both look in ~/.config/sbx.conf for a hostname or ip address. If you have a default container that you routinely login to add a one liner in that file. Something like...
hostname
or...
10.0.2.5
Then all you have to to is call the command with no args to connect.
If all goes well you should be presented with the xdm login prompt. Login to the user you configured previouly. You now have a container desktop running with audio and GLX support. You can test if glx is working by running glxgears.
Some applications like games want to access the video card directly. warzone2100 for example requires it. To provide the container access to the the card add the following to the containers config file.
lxc.mount.entry = none dev/shm tmpfs nodev,nosuid,noexec,mode=1777,create=dir 0 0 lxc.mount.entry = /dev/dri dev/dri none bind,optional,create=dir
Note: the shm line may not be absolutly necessary but some applications need it. Firefox comes to mind. May as well add it for good measure.
Since the container desktop is connected to the host's pulseaudio, when quitting, it will stop the hosts pulseaudio process or reset it in the case of a Xephyr connection. So there is no need to stop it manually.
Summing up
It really is simple to configure lxc container as a desktop. So many online tutorials are unecessarily complicated. Quite a few go into bizzar contortions just to get audio working. Others assume we want to start the X server from inside the container, a very messy thing to do and completely unecessary. Some go into using third party management apps that add even more complexity. It took me a while to find this simple solution from many different sources including blog comments that may have had only fragments of the idea. I couldn't find just one source that disscussed everything presented here.
Again, assuming a properly configured host, container and virtual network the extra steps to provide a working desktop are...
- Configure xdm in the container
- Configure pulseaudio in container and host
- Configure a container users ~/.xprofile or ~/.xsession to use the host pulseaudio server and start a desktop session.
- Connect to container xdm from a host user by starting pulseaudio and telling X to query the container.
- Additionally for gaming support. Add video card mount directives to the containers config file.