26 August 2012

How to use a Raspberry Pi as a secure Web gateway from anywhere

UPDATE: The necessary modules for supporting a "real" PPTP VPN have been added to the stock kernel.  While the following methodology offers benefits in many situations, you might want to consider this new post on the topic, or set things up both ways.


Being a geek, I was the first kid on my block to sign up to purchase a Raspberry Pi Model B, a $35 computer-on-a-card that's about the size of a pack of cigarettes.  In fact, since it comes without a case, I'm tempted to buy a pack of cigarettes, toss the coffin-nails and use the wrapper as an enclosure.  Maybe someday.

Anyway, this is a fully-fledged computer centered on an ARM-based processor that's a couple notches down in capability versus the CPU found in an iPhone or Android phone.  Nevertheless it is capable of running a variety of operating systems, and it benchmarks roughly equivalent to a typical i386 or Pentium machine of a few years' vintage.  Against that metric, the power efficiencies alone are amazing.  This thing runs off a cell phone charger.

The Debian-based variant of Linux that the Raspberry Pi folks recommend as their standard OS now enables hardware acceleration which makes most operations nicely speedy.  It works quite well and, being Debian-based, has access to a huge array of free software.  I have a few projects in mind for this little pup and currently have it running the full LAMP webserver stack (Linux, Apache, MySQL, PHP) just for chuckles.  Despite all that, more than 180MB of its 256MB of RAM is unused.

There will be more to come for this device.  First up: sometimes in my overseas travels I find I can't access my US-based services like Netflix.  Connecting via a hotel WiFi network when overseas gives me a non-US IP address which Netflix detects, and since Netflix's licensing agreements with studios and TV networks don't cover overseas customers, it will refuse to serve up content even though I have an account in good standing back home in the U.S.  Blockage of other Internet-based functionalities also sometimes occurs for other reasons-- for example, VoIP traffic is sometimes blocked, either purposefully or through poorly-considered blanket policies which boil down to "We shall allow common things like web browsing and block all else."

How nice it would be, then, to run a VPN or similar private pipe through the Raspi.  The Raspi's IP address would then be the face of my connection to Netflix and everything else.  Theoretically, I could activate that whenever I needed a US connection or found my connection to some service blocked for whatever reason.

Unfortunately, the Raspi's current recommended Linux build contains a stripped-down kernel that does not support certain features needed for establishing a common encrypted PPTP VPN connection.  Specifically, the kernel lacks MPPE support, and the Raspi will spit an error in the first step of procedures like the one documented here.  Some folks have compiled custom kernels--it's not too difficult--but for various reasons I want to keep my kernel stock-standard.  Perhaps someday the stock kernel will include MPPE support-- it seems everything else needed is present in the stock build and its repositories.

But there's a simple alternative which works well and is almost as capable and easy to use, and that is to use the port-forwarding capability of the ssh server built into Linux to set up the Raspi as a proxy for remote machines.

Here's how

  • First, the ssh server must be active on your Raspberry Pi.  Most folks will have enabled this at setup time.  If not, poster "Abishur" gives the details here.
  • Set your Raspi with a static IP address on your LAN.
  • Next, if your home ISP does not give you a static IP address on the Internet, you'll need to set up an account with a dynamic DNS (DDNS) service.  This will give you a URL which will always point to your router.  My D-Link DIR-655 router (a truly excellent router, by the way) earns me a free DDNS account on D-Link's service; there are plenty of alternatives.  In D-Link's case, the url will look like [username].dlinkddns.com.  
  • You'll need to open your router's ssh port and forward it to your Raspi's IP address on your LAN.
  • On your Mac, bring up the System Preferences | Network preference pane.  Click the padlock and authenticate as an administrator if necessary.  In the Location menu at the top of the preference pane, select Edit Locations.  Highlight the connection-location you normally use for attaching to networks when you travel, click the "gear" icon, and select Duplicate Location.  Give this duplicate a name such as "Normal Connection over ssh via Raspberry Pi".  Click Done.  Now, select the duplicate location and click the Advanced button, then the Proxies tab.  Checkmark the SOCKS protocol and specify "localhost" and port 8080 ...actually, the port doesn't much matter (just be sure to specify the same port in the next step), and 8080 is innocuous.   (Click to enlarge):

Click OK and then Apply.

You'll find your Mac will update its connection to whatever WiFi or Ethernet service it was on before, but Internet traffic won't flow quite yet.  Next, open a Terminal window.  If you've been working in a non-privileged standard user account, type "login [administrator account name]" and enter the password at the prompt.  Then--and here you need to be a bit cautious since you're futzing with your Mac's system files--type "sudo nano /etc/ssh_config"

This will start the Nano text editor and load in your Mac's ssh defaults.  Scroll down to just above the "Host *" line and insert the following:

Host webproxy
  HostName [your dynamic dns url]
  User [your username on your Raspberry Pi]
  DynamicForward 8080
  Compression yes

Type ctrl-X and say yes to the prompt to overwrite the current copy of ssh_config.

Close the terminal window.  Setup is now complete.

Using your secure tunnel connection

Now you're set.  On any given day when you find an Internet service blocked:

  1. In the System Preferences | Network preference pane, select the location you created with the ssh connection proxy via your Raspberry Pi.
  2. Open a terminal window, and simply type "ssh webproxy" and provide your Raspberry Pi user account password when prompted.  

You'll now have Internet!

...But don't close that terminal window.  What's happening now is that all TCP traffic to and from your computer is being routed through your encrypted ssh connection, which will be closed if you axe that window.

When you're done: switch back to normal connectivity by selecting your usual location in the System Preferences | Network preference pane.

Note that this approach is almost but not quite as functional as a nice PPTP VPN.  It is, however, pretty much limited to providing remote access just for personal computers.  Connecting via ssh is not well-supported by mobile devices, unfortunately.  For those, a proper VPN setup would be most beneficial.  Perhaps next time.  Also, it seems that while TCP traffic is routed, some other types of traffic may not be (which would seem to be why you can type "ssh webproxy" and log onto your Raspberry Pi when Internet isn't otherwise flowing yet after selecting the ssh proxy'd location in the preference pane.)  So even though TCP traffic is encrypted, don't go trading state secrets over this connection.

In my testing, using this ssh proxy approach has shown a negligible impact on Internet throughput versus my home's normal network connection, which is admittedly fairly entry-level.  If my hotel's Internet connection is good enough to support Netflix streaming in the first place, content streams just fine.  Latency increases a little, but it's pretty terrible to begin with on my home Internet service.  Note that all your remote traffic routes through the ssh port on your router, so if your remote usage would involve time-critical applications like VoIP, it might be a good idea to add that port to the router's Quality of Service (QoS) priority list.

Demo: We're Not In Kansas Anymore, Toto

With my Mac tethered to my iPhone, the handy WhatIsMyIPAddress.com maps my IP address as in Kansas:

By selecting my new ssh proxy "location" in the System Preferences | Network preference pane and typing "ssh webproxy" in a terminal window, now it appears I'm connected via my home ISP in California, where my Raspberry Pi resides... even though I'm still tethered to the iPhone:

One wrinkle...

You should consider the possibility that in your travels, access to the ssh default port of 22 might be blocked as well.  A good plan for that case is to make use of a port unlikely to be blocked and otherwise unused in your setup.  For me, although I'm playing with my Raspi as a tiny web server, it's not serving encrypted (https) pages.  So the https port 443 is not being used and is a great candidate for our pipeline's usage.  To use this:

  • Open port 443 on your router and forward it to your Raspberry Pi.
  • If you have Apache enabled on your Raspberry Pi, comment-out the "SSLEngine on" line in /etc/Apache2/sites-available/default-ssl:

  •  Then add port 443 to the listen-list in /etc/ssh/sshd_config on your Raspberry Pi:

Reboot your Raspi ("sudo reboot") and give it a couple minutes to sort itself out.  Henceforth, on your Mac, you can type "ssh -p 443 webproxy" to route your ssh connection over port 443, which all but the most uncooperative hotspots should leave unimpeded.

Incidentally, most of the above can be useful for figuring out how to do something similar on alternate platforms: a Windows remote client instead of a Mac, for example, or a generic Linux machine or something like a Mac Mini rather than a Raspberry Pi.  Of course, if you can use a fancier machine than a Raspberry Pi (or use an alternate or custom kernel in a Raspberry Pi), you can just set up a nice PPTP VPN on it.  If the ssh proxy approach is any indication, it should work just fine.


  1. Nice Article! Thanks for sharing with us.
    IP Routing

  2. What about for Windows users?

    1. Not knowing whether the SSH web proxy approach can apply to Windows, I'd just direct them to my other post on creating a PPTP VPN on the Raspberry Pi: http://unvexed.blogspot.com/2012/08/how-to-set-up-real-encrypted-vpn.html ...IIRC, Windows has long had PPTP-client capability.

    2. Well written article. For windows, you can yse putty.exe or ssh in the cygwin package.

  3. thanks for sharing.

    1. Thanks also

      IS the data through put enought for Netflix movies ??
      Do yopu neet an upgraded home setup ??
      ie Does your home setup need an upload rate of say 3Mbits/s ??
      OR does the PI only perform the IP check and Netflix data comes in a difference way ??

      Cheers for any info.

    2. Anon,

      o Data throughput is more than enough for Netflix if your home and "hotel" (or whatever) connections are good.

      o You may or may not need an upgraded home setup. I'd say try it out and upgrade if you find your home broadband is too pokey. Most should be fine.

      o 3Mbits/sec would seem more than ample for even DVD-quality playback. See http://support.netflix.com/en/node/306#gsc.tab=0 for Netflix's official recommendations.

      With the VPNs as I've documented them here on this blog, all your traffic will traverse the Raspberry Pi. Twice, in fact.


  4. I smoke and the RPi almost fits in the pack... by a hair. It was sad.

  5. Thank you so much!

    I prefer the SSH way to VPN and this is an excellent tutorial!