This is a guide to setting up OpenVPN on a server and a client where, in this instance, both are running OpenWRT. What follows has been tested on trunk (currently BB, b39757), but will likely work on the latest stable branch (currently AA, b39408).
Note that all of the 'work' here is accomplished via non-interactive commands (that you should cut-and-paste), andthere are no files to edit.
This how-to has had a BIG rewrite. If required, you can find the old version here: http://wiki.openwrt.org/doc/howto/vpn.openvpn?rev=1390780026
On the OpenVPN server (and on similarly, on clients), installing and (more importantly) configuring an OpenVPN tunnel consists of the following:
- Creating and distributing the PKI certificates and their keys to the server and the clients
- Configuring the network (i.e. devices, interfaces, and firewall)
- Configuring and Starting the VPN listener
The user (i.e. client) wants to access the LAN on the other side of the server without being 'snooped' (e.g. via a public WiFi network), and/or the user wants to access the Internet via the server (e.g. to punch through a company firewall and thereby bypass it's restrictions).
This article will be based upon TUN (routing); for TAP (bridging), you will find information elsewhere in this Wiki.
So to make it easier for you, this How-To assumes:
- the client and the server are (vanilla-build) OpenWRT routers (look elsewhere for help Linux/Windows/etc.; it wont be too hard for clients)
- the client can
pingthe server though its WAN interface, and that they are not in the same subnet
The OpenVPN client (i.e. the system who initiates the negotiation for the VPN tunnel) must be able to
ping (using IPv4) the OpenVPN server (who responds to such requests) via it's WAN interface (and preferably using a public DNS FQDN). In this case, it is assumed that the client, as well as the server (a.k.a. router) are both running OpenWRT (although *nix & Windows clients are also covered).
Before executing Step 1, you should check which specific version of OpenWRT you have. See the notes below for more information.
- On both the client and the server, install the OpenVPN package:
opkg update; opkg install openvpn-openssl ## or: opkg install openvpn
Which package you should install will be indicated by which version of OpenWRT you have (check via:
- on Barrier Breaker: there are three versions of OpenVPN that you can choose from, including:
openvpn-polarssl, which might not work with the following scripts (it should be obvious why you should not use
- on Attitude Adjustment: there is only one version of OpenVPN that you can install,
openvpn(which uses OpenSSL)
Easy-RSA is a simple PKI that was spun off from OpenVPN as a separate project. With OpenVPN, there does exist a means of creating client/server certificates that does not require a PKI (known as static keys), but Easy-RSA is used here as it is a simple enough method, and using a proper PKI is much better practice.
Before executing Step 3, you may (or may not) need to execute Step 2. See notes below for more information.
- On the OpenVPN Server, install the Easy-RSA package:
opkg update; opkg install openvpn-easy-rsa
- If running Attitude Adjustment (specifically, version 2.2.2-2 of the Easy-RSA package), then you must 'tweak' the PKI configuration to prevent problems later on (this step 'comments-out' the relevant code):
sed -i '/KEY_CN/ s:^export:# &:' /etc/easy-rsa/vars ## do not set the KEY_CN environment variable
- Establish the shell variables, and start with a clean slate (you may get warnings about
./clean-all, which you can ignore):
source /etc/easy-rsa/vars clean-all
- Create the Certification Authority, Server, and Client certificates:
pkitool --initca ## equivalent to the 'build-ca' script pkitool --server my-server ## equivalent to the 'build-key-server' script pkitool my-client ## equivalent to the 'build-key' script
- Finally, create the Diffie Hellman parameters (left until last because it can take a long time):
build-dh ## this script will 'take a long time'
If you get an error message
TXT_DB error number 2, then check that the CommonName variable is not set: that is,
set | grep KEY_CN must return no results. The failure is because subsequent certificates have the same identifier as first (the server's). If required, execute
unset KEY_CN, and start again from Step 2.
You can confirm everything is OK so far via:
ls $KEY_DIR; there should be
serial, the Diffie-Hellman files, and three pairs of
.key files (plus some other files).
If required, you can start from scratch (i.e. destroy the old PKI, and create a completely new one) by re-starting this process from Step 3. If you've copied any of the earlier certificates elsewhere, be sure to delete them. Be warned that it would be easy these (new) certificate/key sets with older sets, since they just happen to have the same filenames!
Before executing Step 3, you'll have to find a way achieving Step 2 (discussed only briefly here). See the notes below for more information.
- On the server, copy the server certificate to where OpenVPN needs it to be (
$KEY_DIRis a variable set by
cd $KEY_DIR mkdir -p /etc/openvpn cp ca.crt my-server.* dh*.pem /etc/openvpn/ ## the server files (note: dh*.pem is required)
- Next, you'll need to copy the client certificate from the server to the client (e.g. via a USB stick).
- On the client, copy the server certificate to where OpenVPN needs it to be, example:
cp ca.crt my-client.* /etc/openvpn/ ## the client files (note: dh*.pem is not used)
For security reasons, you need to think long and hard about where you backup your PKI files, and especially the .key files:
ca.keyshould be moved to a place that is not accessible from the Internet (it is only needed when 'doing' CA stuff)
- the other
.keyfiles should be kept 'private', that is, stored only on the 'owning' system
.keyfiles should not be distributed in an insecure manner - it is well known that copying .key files across the Internet is a leading cause of male-pattern baldness!
This is the configuration of the OpenVPN server only.
- Create the VPN interface (note that the tun0 device does not yet exist):
uci set network.vpn=interface uci set network.vpn.ifname=tun0 uci set network.vpn.proto=none uci commit network; /etc/init.d/network reload
- Allow OpenVPN tunnel negotiation (i.e. accept inbound traffic and thereby allow a tunnel to be created):
uci add firewall rule uci set firewall.@rule[-1].name=Allow-Inbound-OpenVPN uci set firewall.@rule[-1].target=ACCEPT uci set firewall.@rule[-1].src=wan uci set firewall.@rule[-1].family=ipv4 uci set firewall.@rule[-1].proto=udp uci set firewall.@rule[-1].dest_port=1194
- Allow OpenVPN tunnel utilization (i.e. allow a tunnel to be used):
uci add firewall zone uci set firewall.@zone[-1].name=vpn uci set firewall.@zone[-1].input=ACCEPT uci set firewall.@zone[-1].forward=REJECT uci set firewall.@zone[-1].output=ACCEPT uci set firewall.@zone[-1].network=vpn
- Allow the client to access the OpenVPN server's LAN via the VPN (optional):
uci add firewall forwarding uci set firewall.@forwarding[-1].src=vpn uci set firewall.@forwarding[-1].dest=lan
- Allow the client to access the OpenVPN server's WAN via the VPN (optional):
uci add firewall forwarding uci set firewall.@forwarding[-1].src=vpn uci set firewall.@forwarding[-1].dest=wan
- Finally, commit the changes:
uci commit firewall; /etc/init.d/firewall reload
When reading the following, make sure you're clear on the difference between an interface, a network, and a zone.
Note that Step 4 and 5 overrule the
REJECT in Step 3. You may want only Step 4, or only Step 5, or maybe both. That is,
- Step 3 will allow the VPN client(s) to access the OpenVPN server itself
- Step 4 will allow the VPN client(s) to access networks via the OpenVPN server's LAN interfaces
- Step 5 will allow the VPN client(s) to access networks via the OpenVPN server's WAN interfaces
uci show network | grep ifname to see the interface of each network (e.g. 3gwan network via usb0 interface). Execute:
uci show firewall | grep zone | grep -E "(net|name)" to see the networks of each zone (e.g. wan/3gwan networks in wan zone).
There shouldn't be much to do. Most clients allow outbound (client-instigated) tunnels.
However, you need to think about which Route tables, and which DNS server to use. More later.
This is essentially the same as for a OpenWRT server.
Before you execute Step 3, you should understand the requirements of your specific use-case (i.e. your network configuration). See the notes below for more information.
- Clear the default OpenVPN configuration, and create a new OpenVPN configuration called 'myvpn' (it could be called anything). Ensure that, in particular, the last three lines (the ca, cert, and key parameters) do not produce an error:
echo > /etc/config/openvpn uci set openvpn.myvpn=openvpn uci set openvpn.myvpn.enabled=1 uci set openvpn.myvpn.dev=tun uci set openvpn.myvpn.persist_tun=1 uci set openvpn.myvpn.persist_key=1 uci set openvpn.myvpn.proto=udp uci set openvpn.myvpn.comp_lzo=yes uci set openvpn.myvpn.verb=3 uci set openvpn.myvpn.log=/tmp/openvpn.log uci set openvpn.myvpn.status=/tmp/openvpn-status.log uci set openvpn.myvpn.ca=/etc/openvpn/ca.crt uci set openvpn.myvpn.cert=`ls /etc/openvpn/my-*.crt` ## NB: these are back-quotes uci set openvpn.myvpn.key=`ls /etc/openvpn/my-*.key` ## NB: these are back-quotes
- To that, add the server-specific parameters. Ensure that, in particular, the last line (the dh parameter) does not produce an error:
uci set openvpn.myvpn.server='10.8.0.0 255.255.255.0' ## NB: these are single quotes uci set openvpn.myvpn.port=1194 uci set openvpn.myvpn.ifconfig_pool_persist=/tmp/openvpn-ipp.txt uci set openvpn.myvpn.keepalive='10 120' ## NB: these are single quotes uci set openvpn.myvpn.dh=`ls /etc/openvpn/dh*.pem` ## NB: these are back-quotes
- And finally, the tricky bit (read below before you execute this command):
uci add_list openvpn.myvpn.push='redirect-gateway def1' ## NB: these are single quotes
- Commit the configuration, enable and start the OpenVPN daemon:
uci commit openvpn; /etc/init.d/openvpn enable
If the OpenVPN Client and Server and on the same subnet, then you must add the local flag. Use instead:
uci add_list openvpn.myvpn.push='redirect-gateway def1 local'
If your OpenVPN Client is not to route all it's traffic via the serevr (and therefor continue to use it's existing default gateway), then you should not use the redirect-gateway option at all.
- Ensure OpenVPN is not running, and confirm that there is no OpenVPN daemon and no TUN:
/etc/init.d/openvpn stop sleep 3 ps | grep openvpn ifconfig | grep tun0
- Start OpenVPN, and confirm that there is an OpenVPN daemon and a TUN:
/etc/init.d/openvpn start sleep 3 ps | grep openvpn ifconfig | grep tun0
- If you need to troubleshoot, a good place to start is the log file:
Before you execute Step 3, you need to know the IP address, or FQDN that the client will use to access the server.
- Clear the default OpenVPN configuration, and create a new openvpn configuration 'myvpn' (as for the server).
- To that, add the client-specific parameters (this is different):
uci set openvpn.myvpn.client=1 uci set openvpn.myvpn.resolv_retry=infinite uci set openvpn.myvpn.nobind=1 uci set openvpn.myvpn.remote_cert_tls=server
- The client also has a tricky bit (read below before you execute this command):
uci set openvpn.myvpn.remote='$VPN_SERVER_PUBLIC_ADDRESS 1194'
- Commit the configuration, enable and start the OpenVPN daemon (as for a server).
You can troubleshoot as for a server.
In your favorite text editor on the client machine that will be connecting, paste (needs testing):
client dev tun proto udp remote XXXXXXXX 1194 resolv-retry infinite nobind persist-key persist-tun ca ca.crt cert my-client.crt key my-client.key comp-lzo
Make sure to try and mirror ALL the server options client-side, whatever client you're using, as some of them (namely lzo compression) can have adverse effects if they're not present in BOTH configurations.
Save the file as
* Make sure you are trying to connect to the VPN server from the outside - i.e. use 3G connection, go to a different building etc. Using another vpn (that routes all your traffic) does not seem to help. If you do not do this, a good configuration might not work at all.
* If unsure how various parameters are parsed to openvpn, you can find out PID with ps and then look up the parameters with
tr '\0' ' ' < /proc/PID/cmdline
(Replace PID with a number)
* Attention: The logfile (if not in system log) doesn't limit its disk space - check periodically that you have enough free disk space for other applications (my log on level 6 needed less than a week to fill the whole disk space of a TP-Link 1043)
|: Please read vpn.overview and see this old articles on this matter: http://wiki.openwrt.org/?do=search&id=vpn and help migrate them. There is also an article in the inbox: vpn.howto|
doc/howto/vpn.openvpn.txt · Last modified: 2014/03/09 09:29 by ptitgnu