Raspberry Pi OpenVPN Server Behind Ubuntu Server Router

If you’re reading this tutorial, I’m going to assume you have a very specific goal in mind: get OpenVPN running on a Raspberry Pi behind an Ubuntu Server router using iptables as your firewall.

Other than firewall rules, the OpenVPN documentation is relatively comprehensive and you should look there for specific configuration options and general OpenVPN setup. It’s not particularly difficult to get OpenVPN installed with easy-rsa and configured with sane options following that guide.

This tutorial emphasizes the routing rules required on both the OpenVPN server and the Ubuntu Server router in order to make the VPN server reachable from the public internet so you can connect to it remotely, have your VPN -> LAN traffic routed properly, and have your LAN -> VPN traffic routed properly.

Think of this as a guide to the configuration required outside of OpenVPN itself to get it working behind your router, e.g. when it’s not installed directly on your router.

I’m currently running Raspbian Jessie on my Pis and for the sake of simplicity, you should run Jessie or later as well. Versions of Raspbian earlier than Jessie don’t include OpenVPN in the repositories so it ends up requiring some jankiness like adding backports from the Jessie repositories. It’s just not very clean.

You can find my comprehensive OpenVPN server and client configuration files in this repository.

Assumptions

  1. You’re running Raspbian Jessie or later, though this isn’t strictly necessary as long as you have OpenVPN installed and configured.
  2. You’re running Ubuntu Server with iptables as your firewall. The concepts here are easily generalizable to other firewall systems and routers but my examples will be specific to iptables.
  3. You’re wanting to run OpenVPN behind your router, not on it.

Setup

In the following instructions, $EXTIF should be defined as (or statically replaced with) your external network interface card name. On Ubuntu Server, this is often eth0 or em0. Similarly, $INTIF should be defined as (or statically replaced with) your internal network interface card name. On Ubuntu Server, this is often eth1 or em1. Your mileage may vary.

The last thing to note is that my router has an internal IP address of 10.2.3.1, my LAN subnet is 10.2.3.0/24, and my OpenVPN Pi has an IP address of 10.2.3.6. You’ll want to swap out my values for values appropriate for your network.

The router’s iptables rules

First, we need to set up some NAT rules. Our NAT requirements are twofold: 1) we need to translate packets incoming on our router’s public/external network interface card on port 1194 so that the destination IP address is rewritten to that of our OpenVPN server, and 2) any packets originating from LAN machines bound for the VPN subnet (10.3.3.0/24) need to have their destination IP rewritten to that of the VPN server.

The rules themselves, respectively:

iptables -t nat -A PREROUTING -i $EXTIF -p udp --dport 1194 -j DNAT --to 10.2.3.6:1194
iptables -t nat -A PREROUTING -i $INTIF -d 10.3.3.0/24 -j DNAT --to 10.2.3.6

Don’t forget to swap out $EXTIF and 10.2.3.6 with your own values. Change 1194 only if your OpenVPN configuration uses something else. 1194 is default for OpenVPN.

Second, we’re going to need to forward port 1194 to our OpenVPN server. Since our PREROUTING rule has rewritten the destination IP address of all packets inbound on port 1194 by the time these rules are applied to the traffic, we need to define our FORWARD ACCEPT rules for our OpenVPN’s IP address, not our router’s public IP address:

iptables -A FORWARD -i $INTIF -d 10.2.3.6 -j ACCEPT
iptables -A FORWARD -i $EXTIF -p udp -d 10.2.3.6 --dport 1194 -j ACCEPT

Again, swap out $INTIF, $EXTIF, and 10.2.3.6 with your own values. OpenVPN uses UDP by default. If you have changed your server/client configurations to use TCP instead, adjust the protocol flag accordingly.

If your Ubuntu Server router is already functional, I’m going to assume you have masquerading and IPv4 forwarding properly configured. For the sake of being explicit, make sure your iptables configuration includes:

iptables -t nat -A POSTROUTING -o $EXTIF -j MASQUERADE

Where $EXTIF is replaced with your external network interface card name (probably eth0 or em0 on Ubuntu Server).

To enable IPv4 forwarding (which is a basic requirement of having a functioning Ubuntu Server router to begin with), ensure that the following line is uncommented and set to 1 in your /etc/sysctl.conf file:

net.ipv4.ip_forward=1

That should be everything required to get your Ubuntu Server router forwarding traffic to your OpenVPN server as far as iptables and firewalling is concerned.

The Raspberry Pi’s iptables rule

This part is a lot shorter than the router iptables configuration. For the Pi running the OpenVPN server, we’re going to need to set up 2 things for it to successfully ferry between the OpenVPN clients and the LAN machines.

First, ensure that the following line is uncommented and set to 1 in your /etc/sysctl.conf file:

net.ipv4.ip_forward=1

Second, ensure that your Pi’s iptables is configured to masquerade traffic between the two networks:

iptables -t nat -A POSTROUTING -j MASQUERADE

It’s also important that your OpenVPN server config pushes the correct route. The OpenVPN server should be configured to push a route to your LAN subnet. In my case, my VPN subnet is 10.3.3.0/24 and my LAN subnet is 10.2.3.0/24 so my server config includes the following directive:

push "route 10.2.3.0 255.255.255.0"

And that’s it! With a functional OpenVPN server, these rules between your Raspberry Pi and your Ubuntu Server router will allow clients to connect to the VPN server from the internet, allow VPN clients to connect to machines on the LAN, and allow machines on the LAN to connect to machines on the VPN.

Happy hacking!