How-to: OpenVPN Server in a Synology Docker Container

​I recently purchased Synology NAS, and wanted to run an OpenVPN server in a container for remote access. Yes, the Synology has a built-in OpenVPN server, but I felt that running a containerized version was more prudent. There are resources such as the Reddit Synology forum covering the Kylemanna OpenVPN Docker container, but I also wanted to harden my system a bit more using the ​Configuring a secure OpenVPN 2.4 server with Docker​​​ resource. ​​My guide builds on information found in Reddit and the above hardening guide, and uses the kylemanna/docker-openvpn container.

I've also included a downloadable script that has all of the commands, so you don't need to try and cut and paste from this blog and possibly mess up some of the long commands that wrap around. I've also parameterized the script a bit, so it's a bit cleaner, IMHO. Even with the script, I prefer to copy/paste each command into a DSM SSH session, so I can better monitor progress and handle any errors.

​Prerequisites

​1. Enable SSH on your Synology, if not already enabled. Go to Control panel -> Terminal & SNMP -> Enable SSH service. For slightly better security use a different port number above 2048. 

2. Install the Docker package on your Synology, if not already installed.

3. Search the Docker registry for OpenVPN and select/download the package by Kylemanna (Kylemanna/openvpn).

Synology TUN Configuration

For containers to be able to properly use OpenVPN, we need to configure a generic TUN device ​on the Synology using a shell script. [Thanks to Tom for these steps, which I've reproduced below.] Note, if you have other Docker containers that use OpenVPN and you've already configured a TUN, skip this section. Once is enough! 

1. Create a folder on the Synology to put the script. I suggest /volume1/docker/tun.

2. If not already installed, install the Text Editor package in DSM. Open the Text editor and go to File -> New.

3. Insert the following text:

#!/bin/sh

# Create the necessary file structure for /dev/net/tun
if ( [ ! -c /dev/net/tun ] ); then
  if ( [ ! -d /dev/net ] ); then
    mkdir -m 755 /dev/net
  fi
  mknod /dev/net/tun c 10 200
fi

# Load the tun module if not already loaded
if ( !(lsmod | grep -q "^tun\s") ); then
  insmod /lib/modules/tun.ko
fi

# Load iptables mangle is not already loaded
if ( !(lsmod |grep -q "^iptable_mangle\s") ); then
  insmod /lib/modules/iptable_mangle.ko
fi

4. Select File -> Save As. Navigate to the folder you created (or already have) and save the script there. 

5. Now let's create a scheduled task to run this script upon boot-up. Open Control Panel and select Task Scheduler.

6. Select Create -> Triggered Task -> User Defined Script.

7. Name the task anything you wish (e.g. "TUN Adapter"). Use 'root' for the username, 'boot-up' event, check the 'enabled' box, and locate the tun.sh file path and enter it on the Task Settings tab. Note that it may take a reboot for the script to properly work, so let's take 5 minutes now and reboot the Synology.

​Downloadable Script

​To make life a little bit easier, I combined all of the shell script code below into a single downloadable file. You can get that file here. Just change the variables and a path, and you should be good to go! I still suggest copying/pasting each line into SSH separately so you can monitor for an errors. Some commands do require interaction. 

​S​hell Variable Configuration

First, we need to configure a few variables for the script that we will be running to configure the Docker OpenVPN container. OVPN_DATA and OVPN_PKI are just volume lables, and can be whatever you want. FQDN is the internet facing FQDN of your VPN end point. PROT is either 'udp' or 'tcp', depending on what you want to do. 'PORT' is the associated external facing port, which is not necessarily the same as what the container is configured ​to use. In my case I want TCP on port 443. DEVICE is the name of the OpenVPN file you will install on each client. Each device you deploy the VPN client on should have a unique file (and thus key). Two clients with the same key can't connect simultaneously. For the fastest VPN speeds, use UDP (which by default uses port 1194). However, it may be less compatible than using TCP over a well known port like 443.

​1. Use your favorite SSH client and open a shell into your Synology. Run the following commands:

2. ​sudo bash

3.
OVPN_DATA="ovpn-data"
OVPN_PKI="openvpn-pki"
FQDN="vpn.domain.com"
PROT="tcp"
PORT="443"
DEVICE="YourComputer"

​OpenVPN Container Deployment

This section will deploy and configure the OpenVPN container. Due to the security hardening, we are using two volumes. One for the sensitive PKI information, and the other for the generic OpenVPN files.

​​1. docker volume create --name $OVPN_DATA
2. docker volume create --name $OVPN_PKI

​3. docker run -v $OVPN_PKI:/etc/openvpn --rm -it kylemanna/openvpn ovpn_genconfig -u $PROT://$FQDN:$PORT -z -C 'AES-256-CBC' -e 'tls-version-min 1.2' -T 'TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384:TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384:TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384:TLS-DHE-RSA-WITH-AES-256-GCM-SHA384:TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256:TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256'

Note: ​​The -z enables compression. I've also configured a stronger cipher suite than the default. This should work with current OpenVPN clients, but YMMV. If connections fail, you can remove the -C -e and -T parameters. 

​4. docker run -v $OVPN_PKI:/etc/openvpn --rm -it kylemanna/openvpn ovpn_initpki

​Note: This will ask for a 'common name' for your CA. Required, but can be any name you choose. I picked ca.mydomain.com. After the common name, enter a CA phassphrase that is complex. Enter it a total of ​four times, and write it down. It will be needed ​in the future when you want to issue more client OVPN files.

​Client ​OpenVPN File Generation

​Each DEVICE that you want to allow access to the VPN should have ​its own OVPN configuration file and password. Repeat the following two steps as needed for each ​device that needs a VPN connection. ​Devices can share the same OVPN configuration file, however, the server will only ​allow a single connection per key. So the second device attempting a connection (with another device already connected with the same OVPN file) will get immediately disconnected.

​1. ​​docker run -v $OVPN_PKI:/etc/openvpn --rm -it kylemanna/openvpn easyrsa build-client-full $DEVICE
​Note: ​It will prompt you for a PEM passphrase. This passphrase will be required whenever you launch the OpenVPN client to connect. It protects the OpenVPN PKI keys on your client. So make it complex, but something you can also remember and easily type. Some OpenVPN clients may allow you to save the password. Re-enter the CA passphrase when requested. 

​2. ​docker run -v $OVPN_PKI:/etc/openvpn --rm -it kylemanna/openvpn ovpn_getclient $DEVICE > /volume1/​<path>/$DEVICE.ovpn
​Note: ​Change the <path> to whatever share you want the file to be dropped into on your Synology. You will need to copy this file from the Synology onto the device you want to use the VPN on.

​Copying PKI Files

Now we need to copy the needed PKI files from the openvpn-pki volume to our primary openvpn volume. Do note that step 4 is a multi-line command. Likely easier to copy/paste from the downloadable script above, than copy from here.

1.​ docker run -v $OVPN_PKI:/etc/openvpn --rm kylemanna/openvpn cat /etc/openvpn/pki/crl.pem
2. docker run -v $OVPN_DATA:/etc/openvpn --rm kylemanna/openvpn mkdir /etc/openvpn/pki/
3. docker run -v $OVPN_DATA:/etc/openvpn --rm kylemanna/openvpn mkdir /etc/openvpn/pki/{issued,private}

4. ​​for file in /etc/openvpn/pki/crl.pem /etc/openvpn/pki/ca.crt /etc/openvpn/pki/dh.pem /etc/openvpn/pki/issued/$FQDN.crt /etc/openvpn/pki/private/$FQDN.key /etc/openvpn/pki/ta.key
do
  docker run -v $OVPN_PKI:/etc/openvpn --rm kylemanna/openvpn cat "$file" > $(basename "$file")
  docker run -v $OVPN_DATA:/etc/openvpn --rm -i kylemanna/openvpn sh -c "cat > $file && chmod 600 $file" < $(basename "$file")
  docker run -v $OVPN_DATA:/etc/openvpn --rm -i kylemanna/openvpn sh -c "chmod 600 $file"
done

​Launch OpenVPN Server

This command will launch your OpenVPN server container, and assuming no errors, it will continue to run.

​1. ​docker run -v $OVPN_DATA:/etc/openvpn -d -p 1194:1194/$PROT --cap-add=NET_ADMIN kylemanna/openvpn
Note: ​If you want different ports mapped at the container level, you can change them here. However, I prefer to leave these the default and use my externally facing router to do port translation and forwarding. Also, you might want to configure the 'auto restart' option in the Docker GUI for this container. If the container fails to keep running, review the Docker console logs for details on what went wrong.

​Port Forwarding

​Next up you will need to configure your internet router for port forwarding. This procedure will vary from router to router, so I won't include instructions. But just remember to use the same external port number as you used to generate the OVPN configuration file. Hint: The OVPN file is text, so you can open it up and validate which external port it needs. 

​Summary

As you can see, if you use the downloadable script, configuring an OpenVPN server on a Synology NAS using Docker is pretty straight forward. I've included some security best practices in this guide, to better shore up the security of OpenVPN. ​

As for clients, for Windows I would recommend the official OpenVPN client. Or if you want something more fancy, but paid, use Viscosity. If you use a Mac, then the best bets are Tunnelblick (free) or Viscosity (paid). For iOS, use OpenVPN Connect.

Print Friendly, PDF & Email

Related Posts

Leave a Reply

avatar
  Subscribe  
Notify of
Scroll to Top