Running Windows Applications in Linux with Server 2012 R2 and RemoteApp
Over the last half year, I've been slowly making the transition to Linux. A native Unix environment has become more and more relevant to my daily workflow, and I was not a fan of using hacky Windows ports of Unix utilities and dealing with closed-source proprietary software. Linux offered me the ability to natively run tools and software relevant to my work and the freedom to switch between a refined graphic user interface (I use Ubuntu) and the power and flexibility of a terminal whenever I saw fit. It's also free (and supported by an extensive OSS community).
There were still a handful of Windows applications that, though less relevant now than they were before (think word processing: half of the documents I write now are in LaTeX), would be really nice to have in a Linux environment. I've dual booted Windows 8 and Ubuntu for the last year or so, but found myself only booting into Windows to use a select few programs. This was an inefficient workflow, and I wanted to completely wipe Windows from my drive and have a semi-native way of running a small handful of Windows applications that I needed from time to time.
The solution? Loading Windows Server 2012 R2 onto a VM on my Ubuntu server, then installing whatever applications I needed locally on the server and accessing them via RemoteApp on either Windows or Linux clients. The applications themselves run on the server, but the GUI rendering occurs on the client, lending to a generally seamless client experience (provided low enough network latency on both ends).
This solution was nice for a number of reasons.
All CPU-intensive tasks launched by the application occur on the server, saving energy, computation, and memory resources on the client. This was ideal in my use case: the typical client (my laptop) has limited memory and a slowly dying battery; any opportunity to offload computations to the much faster server was a good opportunity.
These programs (think Microsoft Office and the Adobe suite) require a significant amount of disk space to install. SSDs still have comparatively limited storage space, so the ability to use these applications with zero additional disk usage on the client was a huge plus.
Microsoft's RDP protocol is fast. RDP does a fantastic job at separating the role of core CPU tasks required for the application to run (which occur exclusively on the server) and the role of rendering the application's graphics for presentation (which occurs exclusively on the client). This is both faster and more flexible than, for example, VNC, which directly transmits graphics rendered on the server over the network to the client (ever check the bandwidth usage of VNC when transmitting best quality?).
But it had a few pitfalls as well.
The ability to use these RemoteApp applications required the client to be connected to the Internet. This was acceptable to me--I reasoned that only on rare ocassions do I need to do serious work and not have some kind of network connection.
The seamlessness of the experience depends entirely on the quality of the network connection. Latency between the client and my Los Angeles-based server is over 500 ms? Forget it--RDP is fast but when your network sucks, everything takes a hit.
The client filesystem needs to be forwarded (over the network) to the server in order to work on local files. This is not necessarily difficult to do (most Windows and Linux RDP clients support some variant of local drive redirection), but, as one might imagine, working on files in real-time over a network (much less over the Internet) can be painfully slow.
This was a compromise I was willing to make. I needed an exclusively Linux client environment, but also needed reasonably smooth integration of a few select Windows applications. Generally, I'll be in places with a decent network connection, so I went with this solution.
I started with a fresh install of Windows Server 2012 R2. In order to use RemoteApp on the server, the server needs to be joined to a domain (or itself be the domain controller) and have the Remote Desktop Services role installed and configured.
Here's how I set things up on the server and clients:
After the server was promoted to a domain controller, I installed the RDS role on the same server. In Add Roles and Features in Server Manager, go to Remote Desktop Services Installation. Quick Start was sufficient to my purposes, and installation finished without incident.
At this point, if you go to the RemoteApp configuration panel of the Remote Desktop Services pane in Server Manager, you have the option to "Publish New RemoteApp Programs" as one of the action items under Tasks. In my case, all of the Microsoft Office and Adobe suite was available for me to publish.
My Linux RDP client was rdesktop, which didn't have support for CredSSL. To remedy this, I went to Computer > Properties > Remote Settings, made sure that remote access was enabled, and unchecked the box requiring clients to use NLA.
Lastly, port 3389 (RDP) needs to be open in the firewall so that clients can connect. In Windows Firewall Advanced Settings, add both incoming and outgoing rules to allow TCP/UDP port 3389. If you're behind a NAT, you might need to port forward 3389 to expose it to the Internet (alternatively, you could tunnel the port through SSH, which would be more secure but also add additional latency and overhead).
Configuration on the client is generally fairly straightforward. I'm a fan of rdesktop, a native Linux RDP client. It's open sourced on GitHub, where you'll find installation instructions (standard configure, make, and install).
The command to load a RemoteApp program (with some additional parameters) is
HOSTNAME is the name of the Server 2012 R2 host. In my case, it would be solara-vm.ad.kevinlin.info.
USERNAME is the username of the user on the server who has access to the RemoteApp programs.
ADNAME is the name of your Active Directory tree, which you set when configuring the ADDS role on the server.
APPLICATION_NAME is the alias for the RemoteApp program you want to execute. In the RemoteApp configuration panel of Server Manager, you can find the alias listed next to each published RemoteApp program. Generally, it's the name of the program executable.
WIDTH and HEIGHT correspond to the width and height of the window rdesktop will initialize for the RemoteApp program. You might, for example, pass -g 1920x1080.
SHARE_NAME is the name of the share that will be available on the server that redirects to a local directory on the client. You could, for example, call this clientfs.
LOCAL_PATH is the path on your local filesystem you would like to expose to the server. For example, if you passed -r disk:clientfs=/home, when browsing files while in the RemoteApp program, you would have access to a share called clientfs that redirects to the /home directory on the client machine.
-p - will interactively prompt you for the password for ADNAME\USERNAME.
This can be simplified significantly with a bash alias in your ~/.bashrc file: