Below is a setup for OpenVPN on Ubuntu 14.04. With some modifications, it should work on most flavors of Linux Much of the setup came from https://help.ubuntu.com/14.04/serverguide/openvpn.html with a couple of modifications to work out any bugs I ran across. Keep in mind this is for a routed VPN. A good explanation of routed vs bridged VPNs is here. Usually, you use a routed VPN just to reach the VPN server and not the rest of the local subnet, but it is possible to add routes to the VPN server to also allow your VPN clients to connect to machines behind the VPN server.
Set Up the Certificate Authority
First we’re going to set up your certificate authority. The certificate authority allows your server to generate public and private certificates for other computers. You need this in order to set up encrypted communication between two different computers.
sudo apt-get install openvpn easy-rsa mkdir /etc/openvpn/easy-rsa/ cp -r /usr/share/easy-rsa/* /etc/openvpn/easy-rsa/
Next, edit /etc/openvpn/easy-rsa/vars adjusting the following to your environment:
export KEY_ORG=”Example Company”
Type “sudo su” to become root. You’ll be running everything from here on out as root. This normally is not a very good practice, but I’ve found that much of this errors out if you aren’t root.
cd /etc/openvpn/easy-rsa/ mkdir keys source ./vars ./clean-all ./build-ca
You can accept the defaults at the prompt. If you receive an error concerning STR_COPY:variable has no value:conf_def or something of that nature it means that you’ll have to export a separate variable. Go to whatever line the error mentions (mine was 198). You need to add the line export KEY_ALTNAMES=”<your alternate name here>” to the vars file. You will now need to rerun the commands “source vars” and “./clean-all” followed by “./build-ca”.
Create the Server Certificate
Now we are going to set up the public and private keys for the actual server. This allows the server to set up its end of the encrypted tunnel between itself and any other computer.
./build-key-server <your server name>
Accept the defaults except for the challenge password.
Say yes to signing the certificate and whether the request should be committed
./build-dh cd keys cp <your server name>;.crt <your server name>.key ca.crt dh2048.pem /etc/openvpn/
Create the Client Certificates
Now we are going to generate certificates for use by the client. We generate them on the server and then we’ll copy them over to the client. When you’re finished on the server you should delete any client certificates as the server shouldn’t need them unless you want to maintain a backup copy. This isn’t a best practice for business, but for home use it is acceptable to store a copy of the cert on your server. Just understand that if an attacker compromises your server they now can snoop any message you send.
cd /etc/openvpn/easy-rsa/ source vars ./build-key your_client_name
Accept the defaults, but add a challenge password. Sign the certificate and type y to commit.
Now you should copy the following files to your client.
I just zipped everything up with
zip name of your archive file1_to_zip file2_to_zip file3_to_zip
For now, it doesn’t matter where you put them. Just make sure you know where they are on the client.
Configuring Your Server
Next we’re going to configure your VPN server. Start by typing the below. This will copy over an example configuration we are going to modify.
sudo cp /usr/share/doc/openvpn/examples/sample-config-files/server.conf.gz /etc/openvpn/ sudo gzip -d /etc/openvpn/server.conf.gz
Next open up /etc/openvpn/server.conf in an editor.
Next you will want to modify the below lines to point them to the certificates you generated above. If you’ve been following the tutorial up to this point should be in “/etc/openvpn/easy-rsa/keys/” (on the server) and If not, you’ll just need to change everything to the absolute path of wherever you put them.
cert your_path/your_server_name.crt <— Same name as whatever you choose it the “Set Up Server Certificate Section”
The below is the final line you’ll need to modify in server.conf (same file as above). Take a look in your /etc/openvpn/easy-rsa/ directory. If you don’t see a dh1024.pem in it, but you see a dh2048.pem you need to change the below to have your absolute path and say dh2048.pem instead. So your line may look something like this: “dh /etc/openvpn/easy-rsa/keys/dh2048.pem”.
If everything has gone well up to this point you can do:
sudo service openvpn start
It should start without errors
Try doing an “ifconfig”. If it’s all working you should see a “tun0” interface
Configuring the Client
Start by installing OpenVPN
sudo apt-get install openvpn sudo cp /usr/share/doc/openvpn/examples/sample-config-files/client.conf /etc/openvpn/
If you haven’t already you now copy the client certificate and key files to the client. Now that you have the files on your client computer, move them to the /etc/openvpn directory.
Remember there should be three the server’s ca.crt file and the two client files <name>.crt and <name>.key
Edit the /etc/openvpn/client.conf file.
Change the following lines to the correct path. If you put your files in the /etc/openvpn/ directory you don’t have to adjust the path.
Make sure that your configuration has the “client” command somewhere in it.
Now change the following line:
remote vpnserver.example.com 1194
to the appropriate name/ip and port of your vpn server. Remember you’ll be hitting the external IP of the server not the tun interface. IE this likely will be of the eth0 or wlan0 variety of interface and not tun0.
Once you’ve done that start the service with “sudo service openvpn start”. You should see in your ifconfig that a tun interface appeared. If it hasn’t, I found a couple of times I had to run “sudo ifconfig” in order to see it.
If everything is working you should now be able to ping the tun0 interface of the server. If you’re running on a home network or somewhere with a NAT/firewall don’t forget to configure port forwarding for port 1194 to your VPN server. DON’T FORGET: you’re forwarding UDP port 1194. A common mistake is to set TCP forwarding not UDP. If you can’t than I suggest you take a look at https://help.ubuntu.com/14.04/serverguide/openvpn.html and start troubleshooting. You might also consider enabling logging on the server by commenting out the logging lines in server.conf. (Just do a search for logging and you’ll see them.) If you don’t change the paths, openvpn defaults to dumping the logs to /etc/openvpn. At the end of the tutorial I have some troubleshooting ideas.
Using Routed VPN to Connect to Subnet Behind VPN Server
In order to allow the VPN client to connect to machines behind the VPN server we must add a couple of routes to the server. First you’ll want to enable IP forwarding with:
sudo sysctl -w net.ipv4.ip_forward=1
WARNING!!!: If you reboot you will have to reset this option. If you would like to permanently set the option edit /etc/sysctl.conf and uncomment the line net.ipv4.ip forward=1. Next time you reboot the option should take affect.
This tells Linux to allow interfaces to forward traffic from one interface to another. Now we need to add a route to your VPN server to tell it to route traffic inbound to your local subnet out the adapter associated with the local subnet. Let’s say you have a network that looks like the below:
According to the above diagram <your_vpn_subnet_ip> = 10.8.0.0/24, <local_subnet_ip> = 192.168.0.0/24, <local_subnet_ip_interface>=eth0, and your internal gateway would be 192.168.0.1.
We’re going to use iptables to add the routing rules we need. On your server type the following:
sudo iptables -I FORWARD -i tun0 -o local_subnet_ip_interface -s your_vpn_subnet_ip/mask -d local_subnet_ip/mask -m conntrack --ctstate NEW -j ACCEPT
This tells Linux I’m setting up a rule for forwarding on traffic inbound to tun0, sourced from <your_vpn_subnet>, destined for <your_local_subnet>, you want to allow connection state tracking, you want the rule to apply to new connections, and you want Linux to automatically accept those connections. Next you’ll type:
sudo iptables -I FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
WARNING!!!: Just like forwarding, iptables rules do not persist through reboot. An extensive guide on making the rules persistent is here. A quick and dirty method is to save the rules with iptables-save > <your_file_name> and iptables-restore <your_file_name>.
This tells Linux we’re setting up a forwarding rule, I want to track connection state, I want the rule to apply to related connections (connections that are new, but related to another connection) or established (already established connections), and I want to automatically accept them. You may want to test if this is all working. You can do this by setting up Wireshark, tcpdump, or some other such thing on a box aside from your VPN server, which sits on your local subnet. Now try pinging from your VPN cilent to any computer on the subnet of your VPN server. If your default gateway is not the same as your VPN server, you should see traffic arrive at the box on your subnet, but it won’t know where to return the traffic to. If your VPN server is the same as your subnet’s default gateway, the ping should be successful.
Adding Routes as Needed
Warning: This only applies if your VPN server is NOT the same machine as your local subnet’s default gateway. If it is then this does not apply and you can skip this section.
If your VPN server is not the same box as your default gateway then we now have a routing issue. Traffic from your VPN clients will arrive at your local subnet, your VPN server will forward them to a box on your VPN server’s subnet, but the box won’t know where to return the traffic. You can solve this in one of two ways, add a static route on each box you want to communicate with on your local subnet or add one route on your default gateway. Whatever you choose, the route should point traffic sourced from your VPN subnet (default is 10.8.0.0) to the local subnet IP of your VPN server. Instructions for adding a static route on windows are here and for Linux here.
Some Troubleshooting Ideas
At this point you should be able to ping from your VPN client to your VPN server and any box on your VPN server’s subnet. If you can’t I would take a few of the following approaches. First make sure your client can ping the outermost interface of your VPN server’s network. If you’re using port forwarding with a NAT/Firewall this is the external interface of the router. If that doesn’t work look into a layer 3 connection problem between your box and your router (assuming the router is set to return external pings).
Once you can do that ensure your port forwarding rule from your router to your VPN server works. You can scan using nmap with the command nmap -sU -p 1194 <external_ip>. If that doesn’t at least show as open|filtered then you either have a port forwarding problem or the server isn’t actually listening. Check to make sure openvpn is running on the server and that your forwarding rule works.
If that’s ok then check to see if you can ping from your vpn client to the vpn server’s vpn interface. If that isn’t successful you likely have a configuration issue on one of the sides. A common problem is that your certificates aren’t working. Look into enabling logging on the server by commenting out the logging lines in server.conf. The log will output to /etc/openvpn by default AFTER you restart the openvpn server.
If you can ping the server’s vpn interface, but can’t ping a box on the local subnet of the vpn server, then there’s probably something wrong with your iptables set up. You can look at iptables rules with iptables -L. Make sure those are working. I explain how to double check things are working at this point at the end of the section “Using Routed VPN to Connect to Subnet Behind VPN Server”. Finally make sure your routes are working on either your default gateway or your clients. You can use wireshark or tcpdump to check to see incoming traffic. You can also manually check the routes on Linux or Windows by issuing the command “route”.
Hopefully this made your life at least a bit easier. I couldn’t find any solid tutorials out there and this took me a bit of time to set up. Comment if you need help.