Network Access to Unity Desktop via RDP in Ubuntu 16.04 VM Hosted by Hyper-V

Richard Moyse
14 min readSep 20, 2018

Objective

Warning

Install

XRDP

Audio Support

Drive Redirection

Update

Motivation

^

Objective

Configure a Ubuntu 16.04 Unity Desktop VM that’s hosted by Hyper-V to expose a xrdp session that’s accessible by a workstation using a rdp client when the workstation and Hyper-V host are members of the same LAN. The solution repurposes Azure xrdp enhancements that originally configured xrdp to provide rdp via a Hyper-V socket, to instead offer the xrdp session via an IP port.

Although not tested, this solution should also apply to a physical installation of Ubuntu.

^

Warning

  • Once complete, the VM’s kernel will be upgraded to at least4.15.0–1013-azure”. Support for kernel version 4.15.+ began with Ubuntu’s 16.04.5 release on August 2, 2018. Due to the kernel’s “freshness”, incompatibilities may surface in the ecosystem reliant on it.
  • Applying updates to a VM’s applications or kernel may “break” this particular solution.
  • According to the posts associated with this open issue #28, this solution is inadequate for HiDPI mode displays. There are also reports that it’s not responsive for less pixel dense screens running 1080p. IMO viewing in 1920x1080 with full color (32bit) support is certainly workable especially if you’re focused on using the command line when the client workstation is a member on the same LAN running as the Hyper-V host. Moreover, performance can be improved by reducing color support to, for example, to 16bits instead of the default 32bit value.

^

Install

XRDP

The bulk of the install instructions appear beneath the “Tutorial” header found on this page provided by Craig Wilhite. These instructions assume you’ve access to Hyper-V, can use its “Connect…” feature to interact with the VM’s Ubuntu Desktop GUI, and its network adapter directly connects to a network addressable from the workstation running a rdp client.

The install relies on two bash scripts: install.sh and config-user.sh. install.sh updates the Ubuntu kernel and adds xrdp support. config-user.sh establishes a secure logon to the linux xrdp session for the user credentials employed to run this script. Craig Wilhite’s install instructions have been copied below for your convenience. Commands below that begin with a $ are issued from a terminal session running within the VM.

  • Install git if necessary. git isn’t typically included in Ubuntu’s Desktop distribution. If uncertain as to its existence within the VM, run the install anyway. If git doesn’t exist, it will be added, otherwise, it will potentially be upgraded to the most recent security patched version.
$ sudo apt update
$ sudo apt install -y git
  • Copy Azure’s experimental xrdp install and configuration scripts.

    Note: the repository contains separate scripts for Ubuntu 16.04 and 18.04 distributions. The instructions in this document apply to the 16.04 release, however, they’ll probably work for 18.04.
$ git clone https://github.com/Microsoft/linux-vm-tools.git ~/linux-vm-tools
  • Make the scripts executable and run the installer:
$ cd ~/linux-vm-tools/ubuntu/16.04/
$ sudo chmod +x install.sh
$ sudo chmod +x config-user.sh
$ sudo ./install.sh
  • As install.sh terminates, it produces a message directing the user to restart the VM. Issue the following to restart the VM.
$ sudo shutdown -r 0
  • Once the VM reboots, login as the same user and run install.sh again. It must run twice in order to complete the install.
$ cd ~/linux-vm-tools/ubuntu/16.04/
$ sudo ./install.sh
  • Configure and start a xrdp session for the current username so it’s available to a remote client and protected via a login prompt. Note: the current username can be different from the one used to install xrdp support, however, it must have sudo privileges. The command below configures xrdp for the same user that performed the install.
$ sudo ./config-user.sh
  • At this juncture, xrdp should be installed but cannot be accessed. You can choose to enable Hyper-V’s enhanced session mode or keep it disabled.

    Enhanced session mode allows Hyper-V’s VM “Connect…” feature to interact with the VM via a socket using the rdp protocol. rdp supports advanced features like “cut & paste” between the Hyper-V host and VM, setting the VM’s display resolution, and sharing host drives with the VM. Although you can enable enhanced session mode for the VM, changes performed by later steps in these instructions affecting xrdp’s config file will redirect the rdp protocol through the standard rdp IP port instead of the intended HvSocket. These changes expose the xrdp session to connections from any device that can access the Ubuntu VM hosted by Hyper-V via a network. After configuring redirection, the Hyper-V socket no longer streams rdp and Hyper-V returns to using the original feature and performance poor connection implementation instead of rdp.

    Since streaming rdp over an IP port excludes providing it via the Hyper-V socket (and vice versa) and Hyper-V reverts its behavior to use its non-rdp connection method, enhanced session mode can be enabled without introducing obvious anomalies. This permits future Hyper-V “Connect…” requests to use rdp when changes to the Ubuntu VM’s xrdp configuration file encode rdp streaming to occur through Hyper-V’s socket.

    If you decide to enable enhanced session mode, shutdown the Ubuntu VM then start an administrative session of powershell on the host running Hyper-V to execute the Set-VM command.
$ sudo shutdown -h 0
> Set-VM -VMName <your_vm_name> -EnhancedSessionTransportType HvSocket
Use Hyper-V to “Start” and “Connect…” to the Ubuntu VM.
  • Craig Wilhite’s instructions are now complete. The install process above purposely associates xrdp to a Hyper-V socket via a setting in the xrdp.ini. However, if like me, you wish to remotely access the xrdp session from some other LAN device that can connect to the VM using an IP port then xrdp’s configuration file xrdp.ini must be altered to listen on an IP port.
$ sudo nano /etc/xrdp/xrdp.ini
Use the editor to replace: “use_vsock=true” with “use_vsock=false”.
Save the file to replace its contents
exit nano.
  • Assuming you haven’t changed the xrdp.ini IP port setting and ufw is managing the VM’s firewall, allow rdp packets to flow through it.
 $ sudo ufw allow 3389
  • Reboot the Ubuntu VM to enable the network access to the xrdp session.
$ sudo shutdown -r 0
  • You should consider creating a “Checkpoint” for this VM using Hyper-V. It would permit rapid recovery from some later misstep.
  • At this point, a connection started by a remote client, such as Windows 7, running the “Remote Desktop Connection” wizard should successfully connect to the VM’s Unity xrdp session.
Remote Desktop Connection instructions
  • Since this installation process will likely upgrade the Ubuntu kernel, orphaned dependencies required by a prior version can be removed.
$ sudo apt autoremove -y
  • Remove the scripts used to install xrdp and configure its support.
$ rm -fr ~/linux-vm-tools

^

Audio Support

How about forwarding sound via rdp from the Ubuntu VM to the client workstation? Once again the instructions below generously borrow, in this instance, from a how-to provided by neutrionlabs. This how-to explains the tasks needed to extend pulseaudio through the compilation of a custom sink. A sink is a binary module encoded to consume an audio stream then manipulate and direct this stream to a particular output “device”. In this case, the output “device” is the audio channel defined within the rdp protocol.

Note: building the custom sink depends on certain xrdp components installed while executing the above XRDP instructions. Therefore, successfully completing the xrdp install above must occur before performing the instructions below.

  • Determine the originating distribution library location of the pulseaudio source code used to create the pulseaudio daemon running within the Ubuntu VM.

    Identifying the location of a desired package is relatively easy, as Ubuntu imposes a sensible correspondence between its source code and resulting binary package for each component that constitutes a release. Both the source and binary packages share the same repository URL and component names. The only difference being the archive type: deb, assigned to binary packages vs deb-src, that differentiates source code repositories. Given this understanding and the ability of apt show <packageName> to provide the originating distribution library for an installed binary package, the repository library for its source code can be determined.

    Note: a prior installation of a custom built version of pulseaudio will likely invalidate these instructions, especially if the custom built version deviates from the one provided by Ubuntu 16.04 (pulseaudio 8.0).
$ apt show pulseaudio | grep APT-Sources:
Yields something similar to: “APT-Sources: http://us.archive.ubuntu.com/ubuntu xenial-updates/main amd64 Packages”.
  • Change apt’s typical behavior to support source code download for pulseaudio.

    Ubuntu Desktop distributions are OEM configured to only download binary packages. However, it includes the corresponding source code distribution library within /etc/apt/sources.list. The source code entries within this file are ignored because they appear as comments. Removing the comment character: “#” that prefixes the correct source code distribution library will enable apt to download a package’s source code.
$ sudo nano /etc/apt/sources.listFind the distribution library entry whose repository URL and component names most closely approximate the ones displayed APT-Sources: above, and begins with “# deb-src”.Remove the comment character and save the file. For example, given the “APT-Sources:” value above, delete the comment character from “# deb-src http://us.archive.ubuntu.com/ubuntu/ xenial-updates main restricted”.Exit nano.
  • Download pulseaudio source code within the Ubuntu VM, to a directory local to the VM.
$ mkdir ~/pulseaudio
$ cd ~/pulseaudio
$ sudo apt update
$ apt source pulseaudio
After the download completes, a directory named /~pulseaudio/pulseaudio-8.0 should exist.
$ sudo apt build-dep -y pulseaudio
$ sudo apt install build-essential dpkg-dev
$ sudo apt install libpulse-dev
$ cd pulseaudio-8.0
$ ./configure
  • Download neutrionlabs xrdp sink source code from github.
$ cd ..
Should be located in ~/pulseaudio directory.
$ git clone
https://github.com/neutrinolabs/pulseaudio-module-xrdp.git
  • Compile xrdp sink and source pulseaudio modules.
$ cd pulseaudio-module-xrdp
$ ./bootstrap
$ ./configure PULSE_DIR=~/pulseaudio/pulseaudio-8.0
$ make
  • Move the binary xrdp sink module to the appropriate pulseaudio directory that contains all pulseaudio’s extension modules.
$ sudo make install
  • A side effect of make install copies not only the module-xrdp-sink.so but also module-xrdp-source.so, module-xrdp-sink.la, and module-xrdp-source.la. Unfortunately, including the .la file type “confuses” pulseaudio when it loads these modules resulting in silence. So remove them.
$ sudo rm $(pkg-config --variable=modlibexecdir libpulse)/module-xrdp*.la
$ ls $(pkg-config --variable=modlibexecdir libpulse) | grep module-xrdp*
The output should report both module-xrdp-sink.so and module-xrdp-source.so, nothing more.
  • Backup the existing pulseaudio daemon configuration, replace its settings to redirect sound to only the xrdp sink module.

    Note: only root (sudo su) can write the daemon configuration file.

    Note: do not apply these instructions to a physical (non-VM) Ubuntu installation. If they are applied, sound will probably not be heard when directly using the physical Ubuntu instance. Time constraints prevent exploring this configuration. I’m willing to incorporate instructions to this document, source by others, detailing how this can be accomplished.
$ sudo cp -a /etc/pulse/default.pa /etc/pulse/default.pa.original
$ sudo su
$ echo '.nofail' >/etc/pulse/default.pa
$ echo '.fail' >>/etc/pulse/default.pa
$ echo 'load-module module-augment-properties' >>/etc/pulse/default.pa
$ echo 'load-module module-xrdp-sink' >>/etc/pulse/default.pa
$ echo 'load-module module-native-protocol-unix' >>/etc/pulse/default.pa
  • Optionally set group permissions to allow the VM’s username, that’s accessible via the rdp session, to manage and use pulseaudio. Since pulseaudio isn’t running as a system wide daemon (see “Unix Groups and Users), these group permissions: pulse, pulse-access, and audio, are unnecessary. However, they’ve been included for those implementing greater security and/or allowing multiple users to simultaneously access the VM and reduce resources consumed by pulseaudio by starting a system wide pulseaudio daemon.
$ usermod -a -G pulse <specify VM username>
$ usermod -a -G pulse-access <specify VM username>
$ usermod -a -G audio
  • Completely shutdown the VM. Do not restart it. Not all audio device bindings are “forgotten” during a restart, therefore, attempting to play an audio or audio-video link after one results in the blissful silence you wish you could enjoy when attempting to sleep at night.
$ shutdown -h 0
  • After using Hyper-V’s “Start” menu command to boot the VM access it via a rdp client, like Windows 7 Remote Desktop Connection. The default connection behavior controlled by the option “Local Resources | Remote audio | Settings | Play on this computer” should be enabled.
    Remote Desktop Connection instructions
  • Verify that the xrdp sink module is the only sink defined for the VM
$ pactl list sinks
Should return something similar to:
Sink #0
State: IDLE
Name: xrdp-sink
Description: xrdp sink
...
  • Once logged into the xrdp session, a browser, such as FireFox or Chrome, must be used to prime pulseaudio. Therefore, immediately visit an audio or audio-video link via a browser to ensure that other sound applications will “work”.

    Although before starting a browser, “ps aux|grep pulseaudio” displays two process instances with the pulseaudio name and executing “pulseaudio - -check” issues a return code of 0 and emits no messages, these processes aren’t fully “prepared” to play audio. For example, attempting to use Ubuntu’s “Sound” setting application before listening to an audio or audio-video stream served through a browser will cause “Sound” to hang/freeze when running its speaker tests. This anomalous behavior will typically timeout and “Sound” will become responsive again but under certain circumstances, pulseaudio will abort. After encountering this problem, the VM must be completely shudown (shutdown -h 0) then started. If not shutdown, other anomalous behavior will surface, like firefox failing to stream a video because pulseaudio becomes unresponsive.

    If the audio stream played by a browser fails to produce sound examine the:
  • sound settings for both the VM and client workstation to ensure speakers aren’t muted and their volume setting is high enough to produce sound.
  • rdp connection option enabling sound to be forwarded from the VM to the client workstation.
  • file that configures lightdm: /etc/lightdm/lightdm.conf, for the setting “autologin-user=”. If this setting exists, delete it from the file and restart the VM. At some point you may have enabled an automatic login for the particular username associated with the xrdp session. This automatic login creates a Unity session when the VM boots. Starting the Unity session before connecting to the VM via rdp results in some conflict that prevents the xrdp session from forwarding the audio stream.
  • Once satisfied with the operation of rdp audio playback, the artifacts used to build the pulseaudio modules can be eliminated from the VM’s image. The following assumes the current username is the same one used to install pulseaudio’s source code.
$ rm -rf ~/pulseaudio
  • Remove all the build dependencies that were uniquely downloaded to satisfy pulseaudio’s compilation. There’s no prescribed inverse command for apt build-dep pulseaudio, however, in typical *nix fashion, Mike Beach offers this one. His solution relies on installing aptitude. To avoid installing yet another package, aptitude was replaced by apt-mark.

    Note: I’m not an expert in apt and am concerned that executing the commands below may inadvertently eliminate a manually installed package that happens to also be a build dependency for pulseaudio. For example, a user installs package Q. Package Q happens to also be a build dependency for pulseaudio. Running the command below marks Q as automatically installed. Q would then be deleted by running the apt autoremove command and any script or program that relied on Q would now fail. That said, it’s probably rare that this situation exists.
$ sudo apt-mark auto $(apt-cache showsrc pulseaudio | grep Build-Depends | perl -p -e 's/(?:[[(].+?[])]|Build-Depends:|,||)//g')
$ sudo apt autoremove -y
$ sudo apt remove -y libpulse-dev
  • If you wish, remove git.
$ sudo apt remove -y git

^

Drive Redirection

Drive redirection works, however, there’s a glitch, documented by github issue #6, that requires disabling the rpd printer sharing option before starting the connection from the client workstation, in order to view the selected drive(s) in the “shared-drives” mount displayed by nautilus.

^

Update

October 1, 2018

Polkit Warnings appearing in September 13, 2018-October 1 document versions have been removed. A similar xrdp solution published by Griffon and explained by this blog post eliminates the issue. A github pull request has been encoded to repair install.sh. Until the update has been applied, the step referencing the original Microsoft version has been altered to refer to a corrected version maintained by my github account.

For those that applied the version of the instructions containing these warnings:

After completing the upgrade, the policy kit framework daemon: polkitd periodically crashes due to a “segmentation fault”. During the initial faults, RAM was fully allocated mainly due to firefox’s consumption and the VM’s 4GB maximum RAM allocation. Increasing RAM statically allocated by Hyper-V from 4GB to 8GB reduces the problem’s frequency but doesn’t eliminate it.A policy kit failure can also cause aptd to fail.

perform the following:

  • Determine if the polkit rule syntax version is 0.105 or older:
$ pkaction --version
  • When the above reports a version of 0.105 or less, the policy rules originally installed by the prior version of install.sh must be remove. The rule syntax employed by the prior version of install.sh targeted version 0.106 and above. Once this file is deleted, add the appropriate polkit rules whose syntax complies with what’s expected by 0.105.
$ sudo su
$ rm /etc/polkit-1/localauthority.d.conf/02-allow-color.d.conf
$ echo '[Allow Colord all Users]' > /etc/polkit-1/localauthority/50-local.d/45-allow-colord.pkla
$ echo 'Identity=unix-user:*' >> /etc/polkit-1/localauthority/50-local.d/45-allow-colord.pkla
$ echo 'Action=org.freedesktop.color-manager.create-device;org.freedesktop.color-manager.create-profile;org.freedesktop.color-manager.delete-device;org.freedesktop.color-manager.delete-profile;org.freedesktop.color-manager.modify-device;org.freedesktop.color-manager.modify-profile' >> /etc/polkit-1/localauthority/50-local.d/45-allow-colord.pkla
$ echo 'ResultAny=no' >> /etc/polkit-1/localauthority/50-local.d/45-allow-colord.pkla
$ echo 'ResultInactive=no' >> /etc/polkit-1/localauthority/50-local.d/45-allow-colord.pkla
$ echo 'ResultActive=yes' >> /etc/polkit-1/localauthority/50-local.d/45-allow-colord.pkla
$ exit
  • Although unlikely, if the reported polkit version is 0.106 or greater, action must still be taken due to an incorrect permission assignment in the solution installed by the prior version of install.sh. This older version added a duplicate action expression for modifying a “profile” instead of altering this action expression to modify a “device”.
$ sudo nano /etc/polkit-1/localauthority.conf.d/02-allow-colord.confChange the first instance of "org.freedesktop.color-manager.modify-profile" to "org.freedesktop.color-manager.modify-device"Exit nano.

October 19, 2018

Pull request was accepted. Changed git clone:

git clone https://github.com/WhisperingChaos/linux-vm-tools.git ~/linux-vm-tools

to reference Microsoft account:

git clone https://github.com/Microsoft/linux-vm-tools.git ~/linux-vm-tools

^

Motivation

This XRDP solution is more responsive when compared to a VNC one reliant on vino which motivated me to repurpose the solution documented by Craig Wilhite.

As a consultant, I’ve used KVM and Ubuntu’s Desktop to provide no cost development environments isolated and tailored with the tools required to deliver a particular client’s deliverable. Through qemu-img’s ability to derive a new virtual drive from an existing base image, I can quickly deploy a new VM with basic services, including VNC support, in about 15 minutes.

Not too long ago, with the packaging of Hyper-V in Windows 10 and motivated by a spouse whose work required specific Windows based development environments, we invested in a brand new rig, whose performance specs, especially SSD I/O, far exceed the current dedicated KVM platform. After configuring a couple Windows 10 VMs using Hyper-V and experiencing their near native luxuriant performance, I decided to transition a Ubuntu VM, purposed to provide secure web browsing, from the KVM platform to this one managed by Hyper-V.

However, instead of migrating the existing KVM Ubuntu image, the transition involved installing Ubuntu Desktop 16.04 from a live CD and then configuring vino, Ubuntu’s default VNC server which supports its Unity GUI. I can’t offer an informed opinion regarding Desktop GUI’s, as I mostly reside in the command line but since it’s fairly easy to configure vino for LAN access via a VNC client workstation, without having to install other components, I typically tread this path of maximum laziness.

Unfortunately, after installing Ubuntu and successfully configuring vino, remotely connecting to the VM’s desktop over a LAN using RealVNC viewer resulted in sluggish browser page rendering and nearly a two second delay in echoing each typed character to the browser’s address bar. After tuning VNC performance through compressing its stream, changing the desktop background color to solid black, and reducing its color to its minimum level, the annoying cursor lag persisted. This pain point motivated me to reviewed other solutions promoting xrdp but they usually incorporated a desktop windowing manager other than Unity, until I discovered and adapted the collaborative effort by Canonical, Microsoft, and XRDP.org.

--

--

Richard Moyse

What writes code that’s unseen, applies insight remarkably keen, demonstrates computational prowess that’s unsurpassed, conjures algorithms that delight, last?