In this post I’ll describe how I set up a virtual network between different servers.

My goal was to set up a network that:

  • Allowed different servers on different physical networks to be able to access each other on a shared, local network.
  • Allowed traffic from one server to be able to be forwarded to a different server.

Setting up OpenVPN on the server

The openvpn-install.sh script (found in the Nyr/openvpn-install GitHub repository) can be used to quickly get a OpenVPN server up and running:

~$ wget https://git.io/vpn -O openvpn-install.sh
~$ sudo bash openvpn-install.sh

Note: As with all scripts you download from the internet, you should make audit the script to make sure that it’s safe before running it on your system!

The script ask a couple of questions before setting up the server:

  • What IPv4 address should the OpenVPN server use? This is the IP address on the local network that the OpenVPN server will be accepting clients from. Typically this might be of the form 192.168.x.x or 10.x.x.x.
  • What is the public IPv4 address or hostname? This is the IP or hostname that the clients will use to connect to the OpenVPN server. If possible, this should preferably be a DNS hostname, if one is set up for the server.
  • Which protocol do you want for OpenVPN connections? This should generally be UDP, unless the network for some reason requires TCP.
  • What port do you want OpenVPN listening to? The standard port is 1194, but a non-standard port can also be chosen.
  • What DNS do you want to use with the VPN? I just chose 1.1.1.1, but you can chose any DNS you want.

Finally, the script asks for the name of the first client. This generates a file {client_name}.ovpn, which can be used on the client to set it up (described later in this post). Configuration files for additional clients can be generated by running the installation script agian.

Configuring the server

Before using the VPN server, I had to configure it slightly. In the file /etc/openvpn/server/server.conf, I made the following changes:

  • I removed the line push "redirect-gateway def1 bypass-dhcp", since I did not want the VPN to be the primary network for any of the client machines.
  • I added the line client-to-client, because I wanted to enable the client machines to talk directly to each other.

After updating the server configuration file, a restart of the server is necessary to apply the changes:

~$ sudo service openvpn-server@server restart

Setting up OpenVPN on the client

On each of the client machines, OpenVPN can be installed with apt-get:

~$ sudo apt-get install openvpn

The file {client_name}.ovpn, generated by the installation script, must be copied to the client machine.

Then, it must be copied into the /etc/openvpn/ directly, and its file name should be changed to {network_name}.conf, where {network_name} will be the name for the network.

~$ sudo cp my_client.ovpn /etc/openvpn/my_network.conf

Now we just need to start the OpenVPN service:

~$ sudo service openvpn@my_network start

If it works, we should see the new interface tun0:

~$ ip addr
1: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UNKNOWN group default qlen 100
    link/none 
    inet 10.8.0.3/24 brd 10.8.0.255 scope global tun0
       valid_lft forever preferred_lft forever
    inet6 fe80::3caf:4c6b:8011:9224/64 scope link stable-privacy 
       valid_lft forever preferred_lft forever

Forwarding traffic across the network

Now that we have set up the network, let’s forward traffic from one machine to another.

In this case, I want to set up traffic forwarding from client A with IP 10.8.0.2, to client B with IP 10.8.0.3.

On client A, we first need to find the name of the interface we want to forward traffic from:

~$ ip addr
ostfre@vpn-client-2:~$ ip addr
1: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1460 qdisc fq_codel state UP group default qlen 1000
    link/ether 42:01:0a:8e:00:07 brd ff:ff:ff:ff:ff:ff
    inet 10.142.0.7/32 scope global dynamic eth0
       valid_lft 81842sec preferred_lft 81842sec
    inet6 fe80::4001:aff:fe8e:7/64 scope link 
       valid_lft forever preferred_lft forever

In this case, the interface is eth0. We can then enable IP forwarding and create a rule to forward all traffic:

~$ sudo sysctl -w net.ipv4.ip_forward=1
~$ sudo iptables -t nat -A PREROUTING -i eth0 -j DNAT --to-dest 10.8.0.3

However, both of these commands only persist until reboot, so we make them persistent. For the first command, we need to store the following in the file /etc/sysctl.d/60-ip-forward.conf:

net.ipv4.ip_forward = 1

To persist the iptables rule, we can create a new service by storing the following in the file /etc/systemd/system/ip-forwarding-to-vpn.service:

[Unit]
Before=network.target
[Service]
Type=oneshot
ExecStart=/sbin/iptables -t nat -A PREROUTING -i eth0 -j DNAT --to-dest 10.8.0.3
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target

Then we can run this to enable it:

~$ sudo systemctl enable ip-forwarding-to-vpn.service

With these changes, now any traffic on the eth0 interface will be routed to client B.