Introduction: Raspberry Pi VPN Gateway

Picture of Raspberry Pi VPN Gateway

There are a few different uses for VPN. Either you want to protect your privacy and private data from prying eyes or you need to source from another country. Sourcing from another country can be very useful to get access to services not provided in your country. There are a number of VPN services out there today and most of them offer easy to use software for your computer and apps for your tablet or phone. But if you have other devices not supported by the software that you want to go over the VPN? Then build a gateway that gives you internet access over the VPN.

If you look at your basic network setup you have a "default gateway" which is used for any ip-address not located in your current subnet (very simplified). So if you setup a gateway that can route internet traffic over an established VPN connection any network enabled device can take advantage of the VPN tunnel.

My major use case in my San Francisco apartment is a VPN tunnel to my native Sweden so I can stream Swedish play channels on my media players and smart TV. This is a pretty common use case for most people in need of a VPN tunnel. Since my media players and smart TV's aren't supported by the VPN software I built one out of a Raspberry Pi.

You can pick one up for under $40 on Amazon. I do however recommend that you buy a case and decent power adapter as well. For this instructable you need:

  • Raspberry Pi 2 or 3
  • A case of your liking
  • A decent power adapter
  • A network cable

Step 1: Choosing Your VPN Service

Picture of Choosing Your VPN Service

The important thing when selecting a VPN service is that it meets your requirements. For this use case I needed a VPN service with a Swedish exit point, that is the most important thing since I need the Swedish services to be convinced that I'm in Sweden. Over the years I have used several different supliers and below are the things I take into concideration when selecting the VPN supplier for the specific use case:

Free test

I want a free test period or a small amount of test data to get a feel for the software or app. Also I want to test the performance and overall experience before I pay for it. It's also nice to check that my idea will work before I start paying.

Privacy

If the implementation is for privacy concerns then it's really important what the privacy policy states. It's also important what country the company operates from and what laws are protecting your privacy. The really privacy concerned users should look at a service that states that no traffic logs are stored and allow anonymous payments via Bitcoin for example.

Allowed traffic

There might be limitations on what type of traffic you will be allowed to run. The more serious supliers usually block peer-to-peer traffic. This is not only to avoid legal issues but to be able to maintain performance for all users. There are how ever a lot of good suppliers out there that allows peer-to-peer and still deliver a high quality service. But if that isn't your main recuirment I recommend to select a service that doesn't allow peer-to-peer.

Data cap

Never use a service who keeps a data cap over their paying users. This will just run out at the worst possible time exactly like the data on your phone just before the funny part in a video clip!

Exit countrys

Depending on the use case this has different importance. For a use case like mine, where I need to end up in a specific country, of course that needs to be on the list. I also need to be allowed to select which country I exit in. There are services where you are unable to select exit country, stay away from those. You can end up in a country with bad performance or privacy laws. Even if you don't need a specific country you should still select a service with a few different countrys to show from to be able to find one with good performance.

Type of software and support

This is one of the main reasons why I prefer services with a free test. There are so many providers with bad software that are buggy, insecure or just don't work. For a Raspberry Pi implementation I need a provider that supports OpenVPN.

My selection

For this build I went with Tunnel Bear. A free test up to 500GB is offered so I could test that I could actually stream before I payed anything. They are based in Canada which, next to Sweden, have some of the strongest privacy laws in the world. No data cap on payed service and I'm also allowed to have several devices connected at once. So protection for my phone, tablet and computer while traveling on unsecure wifi is sorted as well. Exit node in Sweden is supported, it's actually provided via Bahnhof which is known for strong privacy in Sweden. For the payed plans they offer OpenVPN support. They do not for the free test but it was enough to run that from my laptop to make sure that the streaming services worked.

Step 2: Install the Raspberry Pi

For implementations like this I use the Raspbian Lite operating system. Since I have no need for the GUI at all. You can get the latest release here.

I use Win32DiskImager to load the .img file on the SD-card for the Raspberry Pi.

Once the Raspberry Pi have booted I look in my routers DHCP list to get the IP-address and then connect over SSH with Putty. Standard username and password are pi/raspberry

Once connected I run the raspi-config tool to change the basic settings.

sudo raspi-config

The most importent things to take care of in this config is:

  • Expand file system
  • Change password

You can also change the hostname of your Raspberry Pi if you like. My DHCP have very long leases and I can also reserve a specific address. If you don't have that ability you have to configure the Raspberry Pi to use a static IP-address. Since other devices will use this as there default gateway it is important that it keeps using the same IP-address. Here is a post I wrote about setting a static IP in Raspbian Jessie.

Then we need to upgrade everything to the latest version:

sudo apt-get update
sudo apt-get upgrade
sudo apt-get dist-upgrade

Step 3: Install OpenVPN

Picture of Install OpenVPN

Now we need to install OpenVPN on the Raspberry Pi.

sudo apt-get install openvpn

When the installation is finished we need to copy the OpenVPN config files and certificates to the box. This will be provided to you by your VPN provider. In my case, using TunnelBear, I found there blog post about Linux Support. On that page there is a link to zip file containing everything we need.

The file contains the certificate files and a .opvn configuration file for each country you can tunnel to. You need all the certificate files and the .opvn configuration file for the country of your choice, in my case Sweden. Unzip the files needed and the use winscp to upload the files to your Raspberry Pi. The same username/password as used for SSH will bring you to /home/pi, just drop the files there.

Then we go back to the SSH terminal and move the files over to the OpenVPN folder. First command is just to make sure we are in the /home/pi folder.

cd /home/pi<br>sudo mv * /etc/openvpn/

Now we need to do some modifications to the files. First we need to rename the configuration file from .ovpn to .conf. Any file ending in .conf in the /etc/openvpn folder will automatically start when the OpenVPN daemon is started. First we need to get into that directory.

cd /etc/openvpn

Then we change the name of the config file. You can name it anything you want as long as it ends in .conf. I prefer to use file names without blank spaces, in this case I'm going with swe.conf.

sudo mv *.ovpn swe.conf

Then we need an authentication file containing the username and password used for the VPN tunnel. Open up a text editor and write the username and password on separate lines. We will call this file auth.txt.

sudo nano auth.txt

The content should be like this example:

username
password

Then use CTRL + O to write to the file and the CTRL + X to exit the nano text editor. Then we need to edit the config file to make sure all paths are correct and add a reference to the newly created auth.txt file.

sudo nano swe.conf

The lines that needs to be changed are the ones referring to other files, they need to be absolute paths. In this example this is what we are looking for:

ca CACertificate.crt
cert UserCertificate.crt
key PrivateKey.key

We change them to absolut paths like this:

ca /etc/openvpn/CACertificate.crt
cert /etc/openvpn/UserCertificate.crt
key /etc/openvpn/PrivateKey.key

Then at the end of the file we add a reference to the auth.txt file, like this:

auth-user-pass /etc/openvpn/auth.txt

Once again we use CTRL + O to save the file and then CTRL + X to exit nano. Now we can restart the OpenVPN daemon and see that the tunnel is working.

sudo service openvpn restart 

If you run the command ifconfig you should see a tun0 adapter in addition to your eth0 and lo adapters if the tunnel is up. You can also run the command this command to check your public IP:

wget http://ipinfo.io/ip -qO -

If you are having issues getting the tunnel up first try rebooting your Raspberry Pi and then double check the configuration for errors.

Step 4: Setup Routing

Now we need to enable IP forwarding. It enables the network traffic to flow in from one of the network interfaces and out the other. Essentially creating a router.

sudo /bin/su -c "echo -e '\n#Enable IP Routing\nnet.ipv4.ip_forward = 1' > /etc/sysctl.conf"

If you run sudo sysctl -p you should see this printed on the screen:

net.ipv4.ip_forward = 1

Now routing is enabled and traffic can go through the Raspberry Pi, over the tunnel and out on the internet.

Step 5: Setup Firewall and NAT

Since we will have several clients on the inside accessing the internet over one public IP address we need to use NAT. It stands for network address translation and will keep track on which client requested what traffic when the information returns over the tunnel. We also need to setup some security around the Raspberry Pi it self and the tunnel.

sudo iptables -t nat -A POSTROUTING -o tun0 -j MASQUERADE

Enabling NAT.

sudo iptables -A FORWARD -i eth0 -o tun0 -j ACCEPT

Allowing any traffic from eth0 (internal) to go over tun0 (tunnel).

sudo iptables -A FORWARD -i tun0 -o eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT

Allowing traffic from tun0 (tunnel) to go back over eth0 (internal). Since we specify the state RELATED,ESTABLISHED it will be limited to connection initiated from the internal network. Blocking external traffic trying to initiate a new connection.

sudo iptables -A INPUT -i lo -j ACCEPT

Allowing the Raspberry Pi's own loopback traffic.

sudo iptables -A INPUT -i eth0 -p icmp -j ACCEPT

Allowing computers on the local network to ping the Raspberry Pi.

sudo iptables -A INPUT -i eth0 -p tcp --dport 22 -j ACCEPT

Allowing SSH from the internal network.

sudo iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

Allowing all traffic initiated by the Raspberry Pi to return. This is the same state principal as earlier.

sudo iptables -P FORWARD DROP
sudo iptables -P INPUT DROP
sudo iptables -L

If traffic doesn't match any of the the rules specified it will be dropped.

sudo apt-get install iptables-persistent
sudo systemctl enable netfilter-persistent

First line installs a peace of code that makes the iptable rules we just created persistent between reboots. The second one saves the rules after you changed them. This time it's enough to run the first one. If you change the rules run the second one to save. Iptable rules are in effect as soon as you add them if you mess up and lose access just reboot and the ones not already saved will revert.

Step 6: Conclusion

Now you can use this tunnel from any device or computer on the same network. Just change the default gateway to whatever IP-address your Raspberry Pi has. In my case both my Kodi media centers (one bedroom and one livingroom) uses this connection so I can stream my Swedish play channels. Of course there are other things you can use this for as well.

Just keep in mind that depending on the VPN supplier you chose and the speed of your internet connection there might be slow performance.

If you have any questions or want me to clarify anything let me know in the comments! For more tech post please visit my blogg Hackviking!

Comments

jturner3010 (author)2017-09-09

Thanks for this. It worked great!

Prior to making these changes on my Raspberry Pi box I had setup a StrongSwan VPN server setup. I have setup my router to forward UDP ports 500 and 4500 to this box, and I was successfully able to connect externally to it.

However now that I am using iptable I am now not unable to connect when I am outside of my network.

What iptable entries can I add that will allow me to be able to forward any ports from my router to this Raspberry Pi box and have this traffic route back successfully through my router instead of through the tun0 interface?

Hackviking (author)jturner30102017-09-18

I'm not sure I understand what you are trying to achieve here. This tutorial is for a VPN router handling several clients sharing a common connection. From your comment it sounds like your trying to use this as a VPN server or proxy which this setup doesn't include.

jturner3010 (author)Hackviking2017-10-08

Hi Hackviking,

What I am trying to accomplish is the following:

- Locally I am able to connect to my RPi via SSH without issue.

- My WiFi router is forwarding port 22 to my RPi. When I turn off my OpenVPN connection I am able to connect externally to my RPi via the port forwarding of my WiFi router. However if I activate the OpenVPN connection, then I am no longer able to connect to my RPi via port 22. I believe the packets are being routed through the OpenVPN (tun0) connection.

So the question becomes, how do I route incoming external IP source addresses back through the interface in which I came (ie. via my WiFi router, instead of through my OpenVPN tunnel)?

Hackviking (author)jturner30102017-10-08

If you can connect to it locally even if you have the tunnel up there has to something else. Because a proper port forward sends the traffic from the routers local IP, so it should behave in the exact same manner as any other local connection. If your trying this by connecting back to your external-ip:22 over the VPN tunnel I can understand why there might be issues, other then that it should work just fine. I suggest the next step to be tracing the packages in iptables on the pi, here is a good place to start: http://adminberlin.de/iptables-debugging/

jturner3010 (author)Hackviking2017-10-09

I am using a Google Wifi router and have enabled port forwarding to port 22 on my rpi box. I have been able to see from the debug logs that the external-ip address is in fact trying to connect to my rpi box on port 22.

Here are some logs when the OpenVPN connection is turned off and the external connection succeeds:

Oct 9 19:40:46 raspi2 kernel: [126900.657820] Dropped in: IN=eth0 OUT= MAC=b8:27:eb:a1:eb:55:70:3a:cb:43:d6:78:08:00:45:00:00:40:4b:b7:40:00:f5:06:f8:33 SRC=209.171.88.135 DST=192.168.86.241 LEN=64 TOS=0x00 PREC=0x00 TTL=245 ID=19383 DF PROTO=TCP SPT=28640 DPT=22 WINDOW=4380 RES=0x00 SYN URGP=0
Oct 9 19:40:46 raspi2 kernel: [126900.694003] Dropped in: IN=eth0 OUT= MAC=b8:27:eb:a1:eb:55:70:3a:cb:43:d6:78:08:00:45:00:00:34:51:b1:40:00:f5:06:f2:45 SRC=209.171.88.135 DST=192.168.86.241 LEN=52 TOS=0x00 PREC=0x00 TTL=245 ID=20913 DF PROTO=TCP SPT=28640 DPT=22 WINDOW=547 RES=0x00 ACK URGP=0
Oct 9 19:40:46 raspi2 kernel: [126900.694744] Dropped in: IN=eth0 OUT= MAC=b8:27:eb:a1:eb:55:70:3a:cb:43:d6:78:08:00:45:00:00:48:51:b2:40:00:f5:06:f2:30 SRC=209.171.88.135 DST=192.168.86.241 LEN=72 TOS=0x00 PREC=0x00 TTL=245 ID=20914 DF PROTO=TCP SPT=28640 DPT=22 WINDOW=547 RES=0x00 ACK PSH URGP=0
Oct 9 19:40:46 raspi2 kernel: [126900.781211] Dropped in: IN=eth0 OUT= MAC=b8:27:eb:a1:eb:55:70:3a:cb:43:d6:78:08:00:45:00:00:34:5c:ce:40:00:f5:06:e7:28 SRC=209.171.88.135 DST=192.168.86.241 LEN=52 TOS=0x00 PREC=0x00 TTL=245 ID=23758 DF PROTO=TCP SPT=28640 DPT=22 WINDOW=552 RES=0x00 ACK URGP=0
Oct 9 19:40:46 raspi2 kernel: [126900.805878] Dropped in: IN=eth0 OUT= MAC=b8:27:eb:a1:eb:55:70:3a:cb:43:d6:78:08:00:45:00:00:34:60:a1:40:00:f5:06:e3:55 SRC=209.171.88.135 DST=192.168.86.241 LEN=52 TOS=0x00 PREC=0x00 TTL=245 ID=24737 DF PROTO=TCP SPT=28640 DPT=22 WINDOW=671 RES=0x00 ACK URGP=0
Oct 9 19:40:47 raspi2 kernel: [126901.868718] Dropped in: IN=eth0 OUT= MAC=b8:27:eb:a1:eb:55:70:3a:cb:43:d6:78:08:00:45:00:00:78:c8:d8:40:00:f5:06:7a:da SRC=209.171.88.135 DST=192.168.86.241 LEN=120 TOS=0x00 PREC=0x00 TTL=245 ID=51416 DF PROTO=TCP SPT=28640 DPT=22 WINDOW=813 RES=0x00 ACK PSH URGP=0

Here are some logs of when the OpenVPN connection is active, and the external connection fails:

Oct 9 19:42:42 raspi2 kernel: [127016.518715] Dropped in: IN=eth0 OUT= MAC=b8:27:eb:a1:eb:55:70:3a:cb:43:d6:78:08:00:45:00:00:40:82:ad:40:00:f5:06:c1:3d SRC=209.171.88.135 DST=192.168.86.241 LEN=64 TOS=0x00 PREC=0x00 TTL=245 ID=33453 DF PROTO=TCP SPT=26350 DPT=22 WINDOW=4380 RES=0x00 SYN URGP=0
Oct 9 19:42:45 raspi2 kernel: [127019.517778] Dropped in: IN=eth0 OUT= MAC=b8:27:eb:a1:eb:55:70:3a:cb:43:d6:78:08:00:45:00:00:40:3f:f9:40:00:f5:06:03:f2 SRC=209.171.88.135 DST=192.168.86.241 LEN=64 TOS=0x00 PREC=0x00 TTL=245 ID=16377 DF PROTO=TCP SPT=26350 DPT=22 WINDOW=4380 RES=0x00 SYN URGP=0
Oct 9 19:42:48 raspi2 kernel: [127022.517702] Dropped in: IN=eth0 OUT= MAC=b8:27:eb:a1:eb:55:70:3a:cb:43:d6:78:08:00:45:00:00:40:d4:d9:40:00:f5:06:6f:11 SRC=209.171.88.135 DST=192.168.86.241 LEN=64 TOS=0x00 PREC=0x00 TTL=245 ID=54489 DF PROTO=TCP SPT=26350 DPT=22 WINDOW=4380 RES=0x00 SYN URGP=0

Any help with re-routing the external-ip back through the path/router in which it came would be greatly appreciated.

Hackviking (author)jturner30102017-10-10

Hi,

From these logs neither should work. Both log sections show dropped packages. So just reading from this there is no way it works at either time. If you have followed my guide SSH is blocked from any network except the local one in this case 192.168.86.0/24 which means that your port forward with source 209.171.88.135 (I presume is the public IP of your router) should and are being blocked. If you can make your router actually NAT the port forward so it comes from it's internal IP (guessing 192.168.86.1) it should work just fine. If not change the SSH rule in the IPTABLES to accept incoming connections from 209.171.88.135 and you should be good to go.

/K

RobinPi (author)2017-10-01

Thanks for the tutorial.

I'd love to to take it one step further and enable the Pi to also act as a wireless access point.

e.g This tutorial covers Part 1:

Router >> Pi connected by Ethernet. Pi generates a VPN tunnel for wired devices.

Part 2 would be:

Turn Raspberry Pi's as a wireless access point with it's own SSID so that mobile, tablet, Chromecast, etc can also connect to the VPN over WiFi.

But not sure how to do this last bit.

Hackviking (author)RobinPi2017-10-08

It's pretty straight forward if you search for tutorials setting up the pi as an access point (AP) and then more or less follow the steps again but against wlan0 instead of eth0.

RobinPi (author)Hackviking2017-10-09

Thanks, I'll have a look :)

POISON4RMS (author)2017-08-18

Hey, so I went through all of the steps, and I was wondering if it's possible to run kodi through this vpn on the machine itself? Or is that automatic?

w0ts0n (author)2017-08-01

Hello!

Replying to CAB_123, I did some digging and it appears that tunnelbear now require OpenVPN 2.4. Which if you are using Jessie (like I am) is painful to get working.


I ran into the same issue.

CAB_123 (author)2017-06-18

Excellent tutorial.

Stuck at the end of step #3.

Open VPN reports

TLS key negotiation failed yo occur within ...

TLS handshake failed

OpenVPN status is active (exited)

Can you help me get past this?

I believe I re-checked all the steps and configs

Hackviking (author)CAB_1232017-06-20

There are a few common issues that can cause this. You can read more here: https://openvpn.net/index.php/open-source/faq/79-client/253-tls-error-tls-key-negotiation-failed-to-occur-within-60-seconds-check-your-network-connectivity.html

evilsync (author)2017-05-30

How about split VPN tunnelling? Web browsing traffic / torrents over VPN and everything else is bypassed?

Hackviking (author)evilsync2017-05-30

Then you would have to make the Pi your main router and have configurations for what traffic should go where. It can be done but is a much more complex setup that I wouldn't do for two reasons.

1. It will take a lot of maintenance and testing to make sure you don't have a DNS leak or similar that will expose your traffic.

2. Depending on your internet connection the Pi isn't powerful enough to give you all the speed.

AdamC289 (author)2017-05-15

Hey, thanks for a great tutorial - got the pi up and running as instructed.

However, my devices connect to the LAN via my router and if i redirect the gateway to the pi i don't receive an IP.

So how would you configure a wireless laptop to go via the pi/vpn/router?

Thanks again.

Hackviking (author)AdamC2892017-05-16

Just give it a fixed IP address in the same subnet and it should work just fine. A more "sexy" approach would be to add a DHCP server to the Pi but that would require some more work.

patsherbrooke (author)2017-04-17

Hi ! Thanks for your tuto !
I've installed OpenVPN with PiVpn on my RPI3 (with Raspbian Pixel) and it works.
I'd like to access to my local wifi printer from anywhere : when I try tp print something, it says that the printer is out of connection.
Note that I can ping it from outside...
Do you have a idea of the way to do it ?
Many thanks.

Hackviking (author)patsherbrooke2017-05-16

Are you sure that the printer is setup with the correct IP when you added it to windows? It might get another IP over the VPN. Try to add it again over the VPN.

Aki92 (author)2017-03-08

Great tutorial and idea for the Raspberry pi. However is this still working for you, I was trying out TunnelBear and they are not compatible with Netflix anymore (are you getting the same issue?) I am currently trying with NordVPN but running in to some issues when sudo openvpn file_name (currently working with the IT team, but maybe you would like to give it a try https://nordvpn.com/tutorials/raspberry-pi/openvpn...
Keep up the great work!

Hackviking (author)Aki922017-03-10

Hi, haven't had any issues so far. Not a daily user my self to be honest. Every now and then the outgoing IP's get blocked but they usually sort it out fairly quickly.

zzzuam (author)2017-01-21

What a great tutorial. Exactly what I needed/wanted. Works great with my Apple TV. Small thing missing in the tutorial; SSH is off by default so you have to know how to enable it on a headless install.

MickC20 (author)2016-11-26

I've set this up and configure Windows 10 succesfully to route internet traffic via the PI, I need to know how to do the same for android but after following suggestions of modifying the Wifi connection and using the PI IP as the gateway the Wifi connection fails and disconnects.

Hackviking (author)MickC202016-11-29

It might be that the android doesn't accept changes to the settings supplied by the DHCP. Try changing the config that the DHCP assigns to the clients.

MickC20 (author)Hackviking2016-11-29

Thanks for the reply, no matter what I did it wouldn't work, I think I messed up somewhere along the way, I changed my router other to a 192.168.2.0 network from the 10.0.0.0 it was, wiped the PI, then set it up again, it now works flawlessly along with dnsmasq serving DNS, I do have a couple of ROKU's which don't have manual configuration though so I guess I'll have to use the PI to handle DHCP instead of the router?

Hackviking (author)MickC202016-11-29

If your router doesn't allow you to set specifics then you have to use a secondary DHCP.

FranM38 (author)2016-11-04

could you possibly help me get started

Hackviking (author)FranM382016-11-29

Were are you stuck?

ThomasK26 (author)2016-07-22

Excellent tutorial, works very well!

Hackviking (author)ThomasK262016-07-22

Thank you!

DIY Hacks and How Tos (author)2016-06-13

Great use for a Raspberry Pi.