Routing all traffic through an OpenVPN client on a CentOS 7 NAT
Background
I don't usually write about networking but I couldn't find a concise guide for this online so this is for my own future reference as much as for anyone else who may find this useful.
I previously had the OpenVPN client running on my router, but the router's CPU limited my overall connection speed so I decided to place a NUC (Tiny form factor PC) with dual network ports between the modem and my router for the purposes of running a VPN client and a few web facing services. I'm using some hardware I already owned which has and a comparatively beefy CPU (Intel i7 5557u) that is is overkill for this purpose but will allow the VPN to run without being CPU limited.
The network structure will look like this:
Why CentOS?
I wanted something to run a VPN and a web server as well as a few other web facing services and not have to worry about. With CentOS I can leave it running without having to worry about maintenance (Thanks, yum-cron!).
Why not put the VPN behind the router?
Firstly, it's more difficult to configure all outbound traffic to be forwarded to through the VPN. Secondly, having this as part of my local network is not ideal, if one of the services running on the server was compromised then someone could probe any device on the network. By putting the web facing services on a PC on its own network, anyone who gained access to the server would still have to get through the main router to access other machines on the network.
Prerequisites
- A separate modem and router (or two routers), if your modem is also your router you'll need access to iptables on the router to forward the traffic to the VPN PC and back, something I won't cover here as you'll need a router more configurable than most off the consumer products.
- A single board computer, NUC or PC with a semi-decent CPU and two network adapters. This can be done with wireless or preferably two ethernet ports
The goal here is that the modem connects to the VPN PC, and the VPN PC connects to the router.
Preliminary setup
- Install CentOS 7
- Connect the modem to one ethernet port
- Connect the WAN port on your router to the second ethernet port on the VPN PC
Getting Started
On the PC that will be running the OpenVPN client, run the command ip addr
You'll see something like this:
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: enp2s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:e0:4c:68:31:a8 brd ff:ff:ff:ff:ff:ff
3: enp3s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:e0:4c:68:31:a9 brd ff:ff:ff:ff:ff:ff
inet 192.168.0.28/24 brd 192.168.0.255 scope global noprefixroute dynamic enp3s0
Each of your adapters is listed (enp2s0
and enp3s0
for me). One of them should have been given an IP by the modem. For me it's enp3s0
, this is your WAN port.
The second port connects the PC running the OpenVPN client to the router, your LAN port (for me enp2s0
).
You will need to remember which is which and keep the correct cable plugged in to the correct port.
Choose your IP subnets
You will be running three distinct networks. Make a note of the IP given by your modem. In my example above it is 192.168.0.28
. Plug a device into your router and check the IP (if the IP is in the same range as the modem e.g. both are 192.168.0.*) adjust your router to pick a different subnet.
Finally, choose an a different subnet for your new network. In my configuration the following subnets will exist once finished:
192.168.0.*
- Configured from the modem, the VPN PC will get an IP on this network192.168.1.*
- Configured from the router192.168.2.*
- Configured by the VPN PC, choose any number between 0-255 that isn't already taken by the modem or router. The router will be given an IP on this network.
LAN Adapter configuration
Edit the file /etc/sysconfig/network-scripts/ifcfg-enp2s0
(substitute your own adapter name). This is the adapter that connects the PC to the router, not the modem.
Add the following (or amend the values if the setting is already there):
BOOTPROTO=static
IPADDR=192.168.2.1
NETMASK=255.255.255.0
ZONE=internal
NM_CONTROLLED=no
ONBOOT=yes
Keep the rest of the settings as they are and make sure to set IPADDR to an IP between 1 and 254 of your chosen subnet. Note: .0 does not work!
DNS
You'll need to set up a dns server the simplest is dnsmasq
. The default settings are fine, and you'll need to allow connections to it.
sudo yum install dnsmasq
sudo systemctl enable dnsmasq
sudo systemctl start dnsmasq
sudo firewall-cmd --zone=public --add-service=dns --permanent
sudo firewall-cmd --reload
dhcpd
To manage the subnet for the LAN install DHCPD and configure it to run on startup:
yum install dhcp
systemctl enable dhcpd.service
Create /etc/dhcp/dhcpd.conf
and paste in the following:
subnet 192.168.2.0 netmask 255.255.255.0 {
range 192.168.2.1 192.168.2.254;
option domain-name-servers 192.168.2.1;
option routers 192.168.2.1;
}
Finally, start dhcpd:
systemctl start dhcpd.service
At this point, you can log in to your router and check that it has been assigned an IP address on the 192.168.2.*
subnet. You won't be able to access the internet from devices attached to the router yet though.
NAT
The next stage is enabling NAT so that devices connecting from the LAN can access the WAN.
Firstly, enable IP forwarding in the kernel:
sysctl -w net.ipv4.ip_forward=1
Then configure masquerading in the firewall and forward all traffic from the LAN adapter:
firewall-cmd --zone=public --add-masquerade --permanent
firewall-cmd --permanent --direct --passthrough ipv4 -I FORWARD -i enp2s0 -j ACCEPT
firewall-cmd --reload
Remember to substitute your own adapter name. At this point the NAT is configured and any device connected to the router should have internet access.
OpenVPN
Set up the epel repository if you haven't already and install openvpn:
wget http://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
sudo rpm -ivh epel-release-latest-7.noarch.rpm
sudo yum install openvpn
There's not much configuration needed here, get your .opvn configuration file and run:
openvpn --config /path/to/config.ovpn
If you want to set a username and password, store it in a file with the username on line 1 and password on line 2, create it as root and chmod to 600 then:
openvpn --config /path/to/config.ovpn --auth-user-pass /path/to/auth/details/file
You also have to add the tunnel to the public zone:
firewall-cmd --zone=public --add-interface=tun0 --permanent
firewall-cmd --reload
That's it, go to whatismyip.com and check that it's connecting through your VPN.
To get the VPN to connect on startup, add a service file /etc/systemd/system/vpn.service
[Unit]
Description=Connect to VPN
[Service]
Type=oneshot
ExecStart=/usr/sbin/openvpn --config /path/to/config.ovpn --auth-user-pass /path/to/authentication/file
[Install]
WantedBy=multi-user.target
You can then stop/start the VPN using systemctl start vpn
and systemctl stop vpn
. To start the VPN on boot run systemctl enable vpn