Over the years, I've worked in numerous computing
environments and have come to appreciate heterogeneous systems. In my mind, all
system administrators should experience how different platforms solve similar
problems, just as all programmers should be exposed to different programming
Of course this means being able to play well with others. Sometimes, that's easier said than done.
A recent project requirement stipulated being able to
connect a public web server with a private database system. Not an uncommon
requirement, but it did place a hurdle immediately in the way. The web
application, developed with the Linux, Apache, MySQL and PHP (LAMP) stack, needed
a method to connect to the private database system securely, which, for fun was
not MySQL but instead Microsoft's SQL Server.
The initial requirement called on connecting to the SQL
Server using Microsoft's virtual private network (VPN) solution, Microsoft
Point-to-Point Encryption (MPPE). Not impossible, since support for MPPE on any
Linux distribution simply requires modifying the Linux kernel and recompiling
the kernel in Linux is usually a non-issue.
However, in this case the web application would be running
on a basic virtual private server (VPS) and a Linux VPS doesn't run its own
kernel. Instead Linux VPSes run on a shared kernel used by all the different
virtualized servers running on the same hardware.
Net result, no modification of the Linux kernel would be possible on the VPS.
One alternative to this hurdle would have been to switch
from a Linux VPS to a Windows VPS. This would have been technically possible
since Apache, MySQL and PHP have viable Windows ports. Alas, the hosting
provider in question didn't yet offer Windows VPSes. They would shortly, but
couldn't guarantee that their Windows VPS solution would be available in time
for this particular project's deadline.
A second alternative could have been to upgrade from a
virtualized server to a dedicated server. But that would have added more computing resources than what was required. From a business perspective, the added monthly cost wasn't justifiable. Not when a third alternative existed.
A Workable Solution
VPN is one of those terms that can refer to something
generic as well as something very specific1.
This distinction setups up alternative number three. The secure network
connection requirement would remain, the implementation could simply change2.
Specifically the secure connection would be implemented via SSH instead of via MPPE.
With SSH an encrypted tunnel through an open port in the
private network's firewall can be established. This tunnel forwards network
traffic from a specified local port to a port on the remote machine, securely.
Most Linux distributions these days install OpenSSH as part
of their base system install. OpenSSH is a free and open version of the SSH
protocol and includes client and server software. For those distributions that
don't install it by default installing OpenSSH is usually a trivial matter via
the distribution's package manager.
Windows, on the other-hand, has no such base installation of
an SSH implementation. There are a number of free software versions for
Windows. For the case at hand, freeSSHD was selected to provide a free, open
source version of the SSH server software.
Configuring freeSSHD to enable tunneling requires the
- Click on the "Tunneling" tab
- Check to enable port forwarding and apply the
- Click on the "Users" tab
- Create or edit a user and enable tunnel access
Once the firewall has been configured to allow SSH traffic
on port 22, establishing the tunnel from the Linux client to the Windows server
is as simple as typing the following at the Linux command-line:
ssh -f -N -L 127.0.0.1:1433:192.168.1.2:1433 email@example.com
In which ssh will create and send to the background a ssh
tunnel (-f option) without executing any remote commands (-N option) that
begins at the localhost port 1433 (127.0.0.1:1433) terminates at the remote
address and port (192.168.1.2:1433) and authenticates using the remote username
at the remote location (the public IP address or domain name for the private
But Wait There's More
There is however a minor problem with this SSH tunnel. As
described, the establishment of the SSH tunnel is an interactive process. The
command needs to be executed and the password for the user provided for
authentication. In most cases a simple shell script, executed by cron would solve
this minor issue. However, for the sake of security OpenSSH doesn't provide a
command-line option for providing passwords.
This authentication step can be managed in one of two ways.
One is the use of a key management program such as ssh-agent. The second, more
common option is to create a passphrase-less key.
The first step in creating a passphrase-less key is to first
generate a private/public key pair>sup>3.
In Linux this is done by issuing the command:
Which generates a private/public key pair based on either
the RSA or DSA encryption algorithm, depending on what is provided in the
When prompted to enter a passphrase for the securing of the
private key simply press enter. To confirm the empty passphrase simply press
The next step, after copying the public key onto the Windows
server, is to enable the use of the public key for authentication. In freeSSHD
the steps are:
- Click on the "Users" tab
- Select a user and click on "Change"
- Select "Public Key" from the "Authorization" drop-down
- Click on "OK" to save changes to users
- Next click on the "Authentication" tab
- Using the browse button, select the directory with the users public key are kept
- Enable public-key authentication by choosing the "Allowed" button under "Public-Key Authentication"
- Click on "OK" to save the changes to authentication
With the passphrase-less keys in place, the last step is to
automate the tunnel itself. In this case, instead of a shell script, I opted to
use program called autossh.
autossh is a program that can start a copy of ssh and
monitor the connection, restarting it when necessary. All autossh needs to know
is what local port to monitor, so our one-time initial startup of ssh tunnel
looks similar to the previous example, but with autossh and the addition of the
autossh -M 1433 -f -N -L 127.0.0.1:1433:192.168.1.2:1433