Tunnelled Streaming with SlimServer
I’ve been on the proverbial road for a few weeks in a row lately, and even cable TV gets old after a while. It’s not always easy to fight off boredom, and hotel rooms are a pretty sterile (not in the ‘clean’ sense, unfortunately) and unhomely environment. Things have been markedly better since I’ve had my shiny new iPod, which comes in especially handy on short-to-medium haul flights and in the car. Still, 4GB is somewhat tight considering I have well over ten times as much music sitting at home on my server. So what’s a geek to do?
I’ve already described my living room audio setup based on SlimServer running on a Debian server. SlimServer is essentially a streaming server, to which any number of clients can connect at any given time to read the same stream. The local living room setup works with a local player (based on madplay) continuously reading the stream and playing it back on the server’s sound card, from where the signal is fed into the home theatre amp using a good ole analog cable — a pretty low tech and inexpensive solution that happens to produce a remarkably clear and crisp sound when using high-quality mp3 encoding. The point being that it’s entirely possible to replace that local player with any streaming-capable mp3 player like the ubiquitous Windows Media Player. And sure enough, that’s what I’m doing even as I am typing this post.
Security Considerations
The intended playback machine — my laptop — sitting outside the home network obviously brings some security considerations. Like most DSL routers, mine acts as a firewall by virtue of public IP masquerading. In its current setup only incoming ports 22 and 80 are redirected to the server machine behind it — for SSH remote access and to serve this very website. The obvious solution would be to open a third port for streaming, point it to SlimServer and be done with it. But while I have no problems trusting my up-to-date, patched, Debian-stable Apache and sshd to be exposed to the outside world, I’m not willing to take any chance with SlimServer, which for all I know might be vulnerable to a stupid DoS attack and bring the whole system down with it — my logs show attacks are a daily occurrence on the ssh server, even on an extremely low traffic site like mine. So the next best solution is to take advantage of the SSH protocol’s built-in tunnelling capabilities.
Enabling SSH tunnelling with PuTTY
The standard OpenSSH daemon included in Debian comes built-in with tunnelling capabilities. This means that any SSH client initiating a connection can open a tunnel from a given port on the client machine to a given port on the server machine. In our case, the target server-side port is 9000 — the port SlimServer is running on — on the local machine (from the server’s point of view). The client-side port can be anything, as long as it’s not being used by another application. Once the SSH session is open with these parameters, any packet sent to port 9119 (my arbitrary choice) on my laptop will go through the SSH tunnel, be received by the SSH server back home and redirected to its local port 9000, hence reaching the SlimServer instance. All this without ever directly exposing SlimServer to the outside world.
Accessing the SlimServer web interface
Now that we have provided a way for packets to travel back and forth between the local machine and SlimServer, the next step is accessing the SlimServer web interface. This interface is served directly by SlimServer on port 9000, and is not accessible through the Apache instance running on the standard, world-accessible port 80. From a security point of view, this is a Good Thing, and it means the web interface will also have to be accessed through the tunnel. With the previously configured SSH session open, just point a browser to http://localhost:9119/. PuTTY has been listening on 9119 locally and receives the HTTP query, sending it through the tunnel directly to SlimServer.
Pointing an audio player to the stream
Similarly, once the SSH session is running, pointing an audio player such as the Windows Media Player to http://localhost:9119/stream.mp3 will read the standard mp3 stream provided by SlimServer through the tunnel.
This means that, in addition to requiring an SSH session to be accessible (thus preventing unauthorized access), the entire mp3 stream will be encrypted. While slightly bandwidth-hungry, this comes with the benefit of preventing your friendly network admin/hotel/whoever from knowing exactly what you are fetching from your home server.
Final notes
For this setup to work, an accessible sshd instance is a prerequisite. While this particular piece of software is extremely well written and comes with a very secure default configuration in Debian, it is always a good idea to tighten things up as much as possible when dealing with open ports. I’m not a fan of changing the listening port to something different from the standard 22, although I know some admins and DIY server howtos sometimes advocate it — I simply don’t believe in security through obscurity, and my modest server has suffered enough portscans to convince me of its total lack of usefulness, but as always YMMV.
One thing that’s definitely worth looking into, on the other hand, is disabling remote password authentication in favor of a public key system. PuTTY comes with its own key manager named Pageant, which is both easy to use and packed with great documentation. Taking this extra step makes the SSH server completely airtight as far as brute force login attempts go. The Diceware page is an excellent resource when coming up with a private key passphrase that’s both highly secure and easy to remember — I carry my encrypted key with me on my USB drive everywhere I go, so the loss/theft risk is very real.
Regarding streaming, I’ve noticed what I believe is a conflict between the local audio player running on the server machine (the one that plays audio through the server’s sound card) and any remote clients that attempt to connect to the stream, be it from within or without the local home network. At this point I think the issue comes from the buffering that is happening in remote clients, which is effectively making the playback speed higher than that of the local, real-time player. For now I solve it by temporarily shutting down the local (server-side) player while I’m streaming to a remote machine. Not that big a deal, after all I’m only in one place at any given time, and I have to open an SSH session for the tunnel to work anyway, so typing an extra command is not too much of a hassle.