HowTo: OpenVPN with key and certifcate FILES via WebGUI

Post new topic   Reply to topic    DD-WRT Forum Index -> Advanced Networking
Author Message
DD-WRT Novice

Joined: 27 Dec 2007
Posts: 36

PostPosted: Sat Oct 08, 2011 0:54    Post subject: HowTo: OpenVPN with key and certifcate FILES via WebGUI Reply with quote
For configuring OpenVPN settings and features read the OpenVPN manual.
For generating keys, certificates and CRLs read the OpenSSL manual.
There are a lot of other threads in this forum which deal with OpenVPN and OpenSLL themselves, e.g. here.
Just use the search functions of the forum and the wiki.

Please avoid "thank you" and "works for me" posts to avoid noise in the thread.
You can PM me if wanted (use the PM link at the bottom of this post).
Thanks in advance for reading.

This post will explain how you can avoid wasting NVRAM space when using OpenVPN and how to use DD-Wrt's capabilities to do more advanced and/or dynamic configuration.
Mainly by using the WebGUI (here: DD-Wrt r17201) to include files.

Reasons to use files for OpenVPN:
NVRAM space is normally very limited, so when it is full then no new information can be stored in it.
Typical symptoms for this are settings, keys and certificates that are only partly stored or not at all.
To determine how much space is left in NVRAM go to "Adminstration" -> "Commands" in the WebGUI, enter the following command and hit "Run Commands".
nvram show | grep -e 'size:'

Additionally always copying the contents of the generated files (keys, certificates and CRL) can be annoying.
Especially when using certificate revocation lists (CRLs) a new CRL has to be generated plus copied each time certs are added or revoked.

By using these files directly the NVRAM usage will be reduced tremendously by several KB and updating the CRL is simply copying the new one via SCP/SFTP to the router.

A writeable file system on your DD-Wrt router is needed to store the files.
Either via a JFFS partition in the remaining free space of the router's flash, or a USB stick (also flash), or a USB disk, etc.

Additionally SSH access to the router to copy files and create files/scripts.

I use a USB stick as it provides much more space then the router's flash memory, also this avoids flash memory wear inside the router and a USB stick can be replaced easily and cheaply.
The USB stick is mounted at /jffs as this allows to have startup scripts that are executed by DD-Wrt (see Script Execution in the Wiki).

All pathes in the following paragraphs will use /jffs, so replace it with the path your storage is mounted on.

How to do it: (variant 1: static)
Create a structure on the writeable file system to hold your keys, certificates, CRLs and OpenVPN related files. Adjust the user rights accordingly.
mkdir -p /jffs/etc/ssl/certs   # certificates, CRLs
mkdir -p /jffs/etc/ssl/private   # keys
chmod go= /jffs/etc/ssl/private
mkdir -p /jffs/etc/openvpn   # diffie-hellman, tls-auth, etc.

Copy all files via SCP/SFTP to the new folders. Afterwards adjust the user rights accordingly.
chmod -R go= /jffs/etc/ssl/private

Now the files are available on the router. Including them via the WebGUI under "Services" -> "VPN" is simple.
At first leave all fields for keys, certificates and CRLs empty. This saves NVRAM space. Additionally DD-Wrt will not add option lines for them inside the generated config file /tmp/openvpn/openvpn.conf
So these missing options have to be entered in the field "Additional Config". Its content is appended to the generated config file and therefore these options supersede the ones generated by DD-Wrt.
This also allows to fix some DD-Wrt bugs.
# Additional config starts here
dh /jffs/etc/openvpn/dh1024.pem
ca /jffs/etc/ssl/certs/ca.crt
cert /jffs/etc/ssl/certs/router.server.crt
key /jffs/etc/ssl/private/router.key
tls-auth /jffs/etc/openvpn/ta.key 0
#crl-verify /jffs/etc/ssl/certs/ca.crl   # if a CRL is used, then uncomment
# Workaround for CCD bug from r16790, this is fixed in r17685 and later
client-config-dir /tmp/openvpn/ccd
# Push route to server subnet onto all clients
push "route"

Apply the settings to restart the OpenVPN server with the new configuration.
That's it.

How to do it: (variant 2: dynamically)
Is it necessary to do it dynamically? - No.
Why did you do it? - "Because I can".

If you often test around with DD-Wrt like I do, then changing the mount point of the writeable file system can happen quite often.
When this happens I do not want to change the "Additional Config" every time.
Fortunately a config file can include another config file (nested config files), so a dynamically created config file can be statically included via "Additional Config".
# Additional config starts here
config /tmp/openvpn/openvpn.files.conf
# Workaround for CCD bug from r16790, this is fixed in r17685 and later
client-config-dir /tmp/openvpn/ccd
# Push route to server subnet onto all clients
push "route"

Right now the OpenVPN server will fail to start as the dynamic config file is not present (corresponding message is logged).

To create the dynamic config file a startup script is used, that gets executed when the router boots (see Script Execution in the Wiki).
For this an etc/config directory is created, then the empty script and its execution rights set:
mkdir -p /jffs/etc/config
touch /jffs/etc/config/openvpnserver.startup
chmod +x /jffs/etc/config/openvpnserver.startup

Populate the script with the following code:

# Copyright (C) 2009-2015
# Homepage:
# Discussion thread:

# get the absolute path of this script
SELF_PATH="$(cd -P "$(dirname "${0}")" && pwd -P)"

# extract the mount path (may change in later DD-Wrt revisions)
MOUNT_PATH="$(echo "${SELF_PATH}" | cut -d / -f1-2)"

# create config files with file locations
# (DD-Wrt file names: cert.pem, ca.crt, key.pem, dh.pem, ta.key, ca.crl)

[ ! -d "${CONF_DIR}" ] && mkdir -p "${CONF_DIR}"

cat > "${CONF_DIR}/${CONF_FILE}" << __EOF
dh ${MOUNT_PATH}/etc/openvpn/dh1024.pem
ca ${MOUNT_PATH}/etc/ssl/certs/ca.crt
cert ${MOUNT_PATH}/etc/ssl/certs/router.server.crt
key ${MOUNT_PATH}/etc/ssl/private/router.key
tls-auth ${MOUNT_PATH}/etc/openvpn/ta.key 0

[ ! -s "${MOUNT_PATH}/etc/ssl/certs/ca.crl" ] && echo -n '#' >> "${CONF_DIR}/${CONF_FILE}"
cat >> "${CONF_DIR}/${CONF_FILE}" << __EOF
crl-verify ${MOUNT_PATH}/etc/ssl/certs/ca.crl

[ ! -d "${CCD_DIR}" ] && mkdir -p "${CCD_DIR}"
cp "${MOUNT_PATH}/etc/openvpn/<your vpn name>/ccd"/* "${CCD_DIR}"

openvpn_onwan="$(nvram get openvpn_onwan)"
[ "${openvpn_onwan}" = "0" ] && startservice openvpnserver

Execute it to create the dynamic config file and check its content.
cat /tmp/openvpn/openvpn.files.conf

Reboot the router and test your OpenVPN server.

There are two special cases in the script.
The first is the handling for the CRL file. When a CRL file is stated in the OpenVPN config, then it must contain a CRL.
So if the CRL is empty (or not present), then outcomment this option.
The second speciality is a timing issue when the start type for OpenVPN is "System" in DD-Wrt.
The service is started before the startup script is executed and therefore fails to start.
Hence we check the NVRAM setting for it and just try to start the OpenVPN server again.

Side notes:
By using the WebGUI to configure OpenVPN (here: DD-Wrt r17201) the firewall will be automatically setup correctly, so that the OpenVPN server can be accessed from WAN and that packets are allowed through the VPN tunnel.
No need to create scripts to change the firewall with iptables commands.
This was tested for TUN (routing) interfaces.
Not sure if this is true for TAP (bridging) interfaces too.

When problems occur check the OpenVPN logs always on both sides (client and server). Really read all log messages.
  • Example #1: The message "Need IPv6 code in mroute_extract_addr_from_packet" maybe be cryptic to a non-developer, but everybody should understand that IPv6 is the issue, so disable IPv6 on the client for the OpenVPN adapters.
  • Example #2: A client connects to the server, verifies the server's certificate and then the connection is dropped. Wtf?
    Checking the server log shows "certificate has expired", so revoke the client's old certificate, create a new one and send it to the client.
It's really that simple - most of the time.

When creating a new certificate for an expired one with OpenSSL, then revoke the old one first, otherwise you will get "failed to update database TXT_DB error number N".
This is caused by "unique_subject = yes" inside index.txt.attr for a reason: to make sure there is only one valid certificate per common name, so that old certificates cannot be abused (given that you always use an updated CRL).
But you already knew that by reading the OpenSSL docs, didn't you?
The CRL can be changed on the fly without restarting the OpenVPN server, this is also valid for the files in the CCD, see OpenVPN FAQ (paragraph "Modifying a live server configuration").

Open questions: (not checked, or just not updated here yet)
  • ./.

Last edited by maddes.b on Fri Feb 20, 2015 17:36; edited 5 times in total

Joined: 20 Sep 2006
Posts: 17619
Location: Hesse/Germany

PostPosted: Mon Oct 17, 2011 20:03    Post subject: Reply with quote
this would be nice as wiki instruction...
Forum Guidelines...How to get help
Forum Rules
Throw some buzzwords into the WIKI search Exclamation
I'm NOT rude, just offer pure facts!
Atheros (TP-Link & Clones, etc ) debrick service in EU
Guide on HowTo be Safe, Secure and Protect Your Online Anonymity!
Display posts from previous:    Page 1 of 1
Post new topic   Reply to topic    DD-WRT Forum Index -> Advanced Networking All times are GMT


Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You cannot download files in this forum