Netflix finally arrived in Germany, but guess what? It's library is heavily limited in comparison to the US one and if you like TV series as much as I do, you don't want to wait until they eventually release it year(s) later for us german users.

Maybe you've heard recently of Anonabox — a small device with two ethernet ports that you can plug in front of your router and everything behind the device is routed through Tor (side note: turned out to be a scam and got pulled from Kickstarter in the end). However, it made me come up with an idea: Instead of having a Tor-box, I want a VPN-box that is connected to my PrivateInternetAccess VPN. If I'm in need of a VPN connection I just switch the WiFi network and I'm good to go. This way I can easily watch US content from Netflix as well as unblock location restricted content like YouTube, even with my iPhone or Xbox.

Another purpose might be to use it as an anonymizer if you care about your privacy and anonymity while browsing the web.

All you need for this is a Raspberry Pi, a WiFi Stick and a 8 or 16 GB SD card. Let's start with the general assumptions:

Assumptions

General

  • You have a Raspberry Pi and you want to use it as a VPN gateway
  • The gateway should be accessible within a dedicated VPN-only WiFi SSID
  • The Pi is connected via Ethernet to your home network
  • The WiFi stick is a RTL8188CUS 802.11n WLAN Adapter
    (Not sure if these are really RTL8188CUS sticks though)
  • You use a Mac OS X based computer to prepare the SD card

Technical

  • Our home network uses IP range: 192.169.1.0/24
  • The VPN network is going to use the IP range: 192.168.101.0/24
  • We're going to use PrivateInternetAccess as VPN provider
  • We're going to use OpenVPN as VPN client
  • We'll use raspbian as distribution

Guide

Prepare SD card

Mount your SD card and download and unzip the latest raspbian image:

cd /tmp  
curl -L "http://downloads.raspberrypi.org/raspbian_latest" -o /tmp/raspbian_latest.zip
unzip raspbian_latest.zip

Clone @RayViljoen's Raspberry PI SD Installer for OS X and execute it to transfer the raspbian:

git clone https://github.com/RayViljoen/Raspberry-PI-SD-Installer-OS-X.git
cd Raspberry-PI-SD-Installer-OS-X  
sudo ./install /tmp/2014-09-09-wheezy-raspbian.img

In the prompt, select the number of the disk drive (I had to select 5) of your SD card and wait till it finished writing the image to the SD card. Finally, unplug the SD card when the process is done

Configure the Pi as access point

Intermediate assumptions:

  • You plugged in the WiFi stick
  • You booted the Pi from the SD card
  • You did the base configuration of raspbian
    (change password, timezone, localization, etc.)
  • apt-get repositories and packages are up to date
    (sudo apt-get update && sudo apt-get upgrade -y)
  • ifconfig shows an wlan0 interface
  • You can access the internet using ethernet (curl icanhazip.com returns the external IP)

Install and configure hostapd and the DHCP server

To create a WiFi network, we need hostapd to manage the authentications and isc-dhcp-server to act as DHCP server:

sudo apt-get install hostapd isc-dhcp-server

Now we need to adjust the DHCP configuration:

sudo vi /etc/dhcp/dhcpd.conf
[...]
#option domain-name "example.org";
#option domain-name-servers ns1.example.org, ns2.example.org;
[...]
# If this DHCP server is the official DHCP server for the local
# network, the authoritative directive should be uncommented.
authoritative;
[... go to end of file ...]
subnet 192.168.101.0 netmask 255.255.255.0 {
    range 192.168.101.10 192.168.101.50;
    option broadcast-address 192.168.101.255;
    option routers 192.168.101.1;
    default-lease-time 600;
    max-lease-time 7200;
    option domain-name "local";
    option domain-name-servers 8.8.8.8, 8.8.4.4;
}

And make sure to use the proper interface:

sudo vi /etc/default/isc-dhcp-server
[...]
INTERFACES="wlan0"

Setup network interface

Let's adjust the network interface and use a static IP:

sudo vi /etc/network/interfaces
[...]
allow-hotplug wlan0
iface wlan0 inet static
  address 192.168.101.1
  netmask 255.255.255.0
[...]
#iface wlan0 inet manual
#wpa-roam /etc/wpa_supplicant/wpa_supplicant.conf
#iface default inet dhcp

Restart your network interface to activate the changes:

ifdown wlan0 && ifup wlan0

Configure hostapd

In the next step, we're going to adjust the hostapd configuration. Make sure you replace [Your_WiFi_SSID] as well as [Your_WiFi_Pass]:

sudo vi /etc/hostapd/hostapd.conf
interface=wlan0
driver=rtl871xdrv
ssid=[Your_WiFi_SSID]
hw_mode=g
channel=6
macaddr_acl=0
auth_algs=1
ignore_broadcast_ssid=0
wpa=2
wpa_passphrase=[Your_WiFi_Pass]
wpa_key_mgmt=WPA-PSK
wpa_pairwise=TKIP
rsn_pairwise=CCMP

And assure to adjust the configuration defaults:

sudo vi /etc/default/hostapd
[...]
DAEMON_CONF="/etc/hostapd/hostapd.conf"
[...]

Recompile hostapd to work with RTL8188CUS

To use our RTL8188CUS we need to recompile hostapd with the according chipset. Download and extract the latest drivers:

cd /tmp   
sudo wget "ftp://WebUser:[email protected]/cn/wlan/RTL8188C_8192C_USB_linux_v4.0.2_9000.20130911.zip"
sudo unzip RTL8188C_8192C_USB_linux_v4.0.2_9000.20130911.zip
cd RTL8188C_8192C_USB_linux_v4.0.2_9000.20130911/wpa_supplicant_hostapd  
sudo tar -xvf wpa_supplicant_hostapd-0.8_rtw_r7475.20130812.tar.gz

Compile and move them into your $PATH variable:

cd wpa_supplicant_hostapd-0.8_rtw_r7475.20130812/hostapd
sudo make && sudo make install
sudo mv hostapd /usr/sbin/hostapd  
sudo chown root:root /usr/sbin/hostapd  
sudo chmod 755 /usr/sbin/hostapd

Configure OpenVPN

To connect to PIA, we're going to use the OpenVPN client. Install and download the default configuration profiles provided by PrivateInternetAccess:

sudo apt-get install openvpn unzip
sudo mkdir -p /etc/openvpn/PIA/disabled  
cd /etc/openvpn/PIA  
wget https://www.privateinternetaccess.com/openvpn/openvpn.zip  
sudo unzip openvpn.zip && rm openvpn.zip

and rename the profiles, so you can take advantage of the autostart option later:

sudo rename 's/ovpn/conf/' /etc/openvpn/PIA/*.ovpn  
sudo rename 's/ /_/g' /etc/openvpn/PIA/*.conf

Create an authentication file that will hold your PIA username and password. Make sure you replace <PIAopenVPNuser> and <PIAopenVPNpass>, matching your credentials:

sudo echo "<PIAopenVPNuser>" >> /etc/openvpn/PIA/auth.txt  
sudo echo "<PIAopenVPNpass>" >> /etc/openvpn/PIA/auth.txt

Since relative paths do no good to our setup, we replace them with absolute ones:

sed -i 's/auth-user-pass/auth-user-pass \/etc\/openvpn\/PIA\/auth.txt/g' *.conf
sed -i 's/ca ca.crt/ca \/etc\/openvpn\/PIA\/ca.crt/g' *.conf  
sed -i 's/crl-verify crl.pem/crl-verify \/etc\/openvpn\/PIA\/crl.pem/g' *.conf

Last but not least, you can move all unwanted configurations, that you don't want to connect to in future in the disabled/ folder:

sudo mv CA_North_York.conf disabled/  
sudo mv CA_Toronto.conf disabled/  
sudo mv France.conf disabled/  
sudo mv Germany.conf disabled/  
sudo mv Hong_Kong.conf disabled/  
sudo mv Netherlands.conf disabled/  
sudo mv Romania.conf disabled/  
sudo mv Sweden.conf disabled/  
sudo mv Switzerland.conf disabled/  
sudo mv UK_London.conf disabled/  
sudo mv UK_Southampton.conf disabled/

Gimmick: Choose random VPNs from "profile pool"

Because I don't want to use the same VPN server/location over and over again, I rather want to randomly choose one location profile from the "profile pool" in /etc/openvpn/PIA/. As soon as I restart the VPN, it will choose a different one than before. This way I simply can reboot the Pi to obtain a new location/IP address.

vi /etc/default/openvpn
CONFIG_DIR=/etc/openvpn/PIA
[...]
test -d $CONFIG_DIR || exit 0

# Helper array and selector variable to pick random element
returnRandomVPN (){
    CHOSEN=`find $CONFIG_DIR -maxdepth 1 -type f | shuf -n1 | grep conf`
    CHOSEN=`basename $CHOSEN .conf`
    # If empty, choose new one
    if [ ! "$CHOSEN" ]; then
        returnRandomVPN
    else
        echo $CHOSEN
    fi
}

# Source defaults file; edit that file to configure this script.
AUTOSTART=`returnRandomVPN`
[...]

To test the "randomizer", just stop and start the OpenVPN client a couple of times:

[ ok ] Starting virtual private network daemon: US_Florida.
[ ok ] Stopping virtual private network daemon: US_Florida.
service openvpn start && service openvpn stop
[ ok ] Starting virtual private network daemon: US_West.
[ ok ] Stopping virtual private network daemon: US_West.
service openvpn start && service openvpn stop
[ ok ] Starting virtual private network daemon: US_Seattle.
[ ok ] Stopping virtual private network daemon: US_Seattle.

NAT & Netfilter/iptables adjustments

Enable IPv4 forwarding:

sudo echo 1 > /proc/sys/net/ipv4/ip_forward  
sudo vi /etc/sysctl.conf
[...]
net.ipv4.ip_forward = 1
[...]

And adopt the following iptables rules to make sure your traffic is routed via the VPN:

sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE -m comment --comment "Use VPN IP for eth0"  
sudo iptables -t nat -A POSTROUTING -o tun0 -j MASQUERADE -m comment --comment "Use VPN IP for tun0"  
sudo iptables -A FORWARD -s 192.168.101.0/24 -i wlan0 -o eth0 -m conntrack --ctstate NEW -j REJECT -m comment --comment "Block traffic from clients to eth0"  
sudo iptables -A FORWARD -s 192.168.101.0/24 -i wlan0 -o tun0 -m conntrack --ctstate NEW -j ACCEPT -m comment --comment "Allow only traffic from clients to tun0"

For a persistent configuration that survives reboot, we got to do some extra steps:

sudo iptables-save > /etc/iptables.ipv4.nat
sudo echo "up iptables-restore < /etc/iptables.ipv4.nat" >> /etc/network/interfaces

Now reboot your Pi and make sure the iptables rules are loaded again:

reboot
sudo iptables -vL && iptables -vL -t nat
[...]

Chain FORWARD (policy ACCEPT 2758 packets, 1347K bytes)
 pkts bytes target     prot opt in     out     source               destination
    0     0 REJECT     all  --  wlan0  eth0    192.168.101.0/24      anywhere             ctstate NEW /* Block traffic from clients to eth0 */ reject-with icmp-port-unreachable
  117  8618 ACCEPT     all  --  wlan0  tun0    192.168.101.0/24      anywhere             ctstate NEW /* Allow only traffic from clients to tun0 */

[...]

Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination
  116  8536 MASQUERADE  all  --  any    tun0    anywhere             anywhere             /* Use VPN IP for tun0 */
    8   568 MASQUERADE  all  --  any    eth0    anywhere             anywhere             /* Use VPN IP for eth0 */

Start/stop services

To ensure your VPN, hostapd and DHCP server is started as soon as you power on the Pi:

sudo update-rc.d hostapd enable
sudo update-rc.d isc-dhcp-server enable
sudo update-rc.d openvpn enable

Tests

To test the whole setup, reboot the Pi, SSH into it and make sure the services run correctly:

sudo service hostapd status
[ ok ] hostapd is running.
sudo service isc-dhcp-server status
Status of ISC DHCP server: dhcpd is running.
sudo service openvpn status
[FAIL] VPN 'US_California' (non autostarted) is not running ... failed!
[FAIL] VPN 'US_East' (non autostarted) is not running ... failed!
[FAIL] VPN 'US_Florida' (non autostarted) is not running ... failed!
[ ok ] VPN 'US_Midwest' (non autostarted) is running.
[FAIL] VPN 'US_Seattle' (non autostarted) is not running ... failed!
[FAIL] VPN 'US_Texas' is not running ... failed!
[FAIL] VPN 'US_West' (non autostarted) is not running ... failed!
  • Check the outgoing IP for eth0. Make sure it's one of your VPN provider and not your "real" one:

    curl icanhazip.com
    
  • Connect to the new VPN WiFi of the Pi, open http://ipleak.net and check if there are leaking DNS requests

  • Reboot the Pi (either sudo reboot or power cycle) and check if you get a new IP from a new VPN location

Sources

Let me know in the comment section below in case you have any issues suggestions or general feedback.