Milan Kragujević

Milan Kragujević

May 5th, 2018 / 5 minutes read

OpenVPN in 4MB - Or how I learned to stop worrying and love the TL-WR840N

How I learned to stop worrying and love the TL-WR840N

I'm a big believer in privacy and don't want my ISP to collect data about my browsing. I have decided to setup an OpenVPN server on a DigitalOcean droplet for $5/mo (Get your own server here with $10 credit). However, for whatever reason, I wanted to set up the VPN on the router level, so that all my devices get it's benefits.

The router I choose to do this is TP-Link's TL-WR840N V5, which only has 4 MB of Flash memory, but has 64 MB of RAM. The 4 MB of flash are a showstopper in most cases for OpenVPN on OpenWRT. The packages openvpn-openssl and libopenssl are too big to fit into the 4MB with the rest of the system, even with the Web UI (LUCI) removed.

A possible solution, that ended up working perfectly, is to download OpenVPN and OpenSSL on boot from the Internet into RAM (tmpfs), extract it and run OpenVPN from the /tmp directory which is stored in RAM.

Warning

Please note that this will only work with WR840N and not with WR740N! I am not responsible for any possible damage that may incur from following this tutorial. The prebuilt image and packages are applicable for WR840N V5 only, and must not be used with other routers. The same applies for the building instructions.

Prerequisites

Obtain a client.ovpn file that contains all the data necessary for your VPN connection. In a future post I will show how to install and setup OpenVPN on an Ubuntu server.

Install OpenWRT on your router, without LUCI but with kmod-tun zlib liblzo nano packages. I used the following commands to build the system image:

sudo apt -y install build-essential subversion libncurses5-dev zlib1g-dev gawk gcc-multilib flex git-core gettext libssl-dev
cd ~
mkdir openwrt && cd openwrt
wget https://milankragujevic.com/uploads/openwrt/mt76x8/openwrt-imagebuilder-ramips-mt76x8.Linux-x86_64.tar.xz
tar -xaf openwrt-imagebuilder-ramips-mt76x8.Linux-x86_64.tar.xz
cd openwrt-imagebuilder-ramips-mt76x8.Linux-x86_64/
make image PROFILE=tl-wr840n-v5 PACKAGES="-ppp -ppp-mod-pppoe -ip6tables -odhcp6c -kmod-ipv6 -kmod-ip6tables nano opkg uhttpd -uhttpd-mod-ubus -libiwinfo-lua -luci-base -luci-app-firewall -luci-mod-admin-full -luci-theme-bootstrap kmod-tun zlib liblzo" CONFIG_IPV6=n
cd ~/openwrt/openwrt-imagebuilder-ramips-mt76x8.Linux-x86_64/bin/targets/ramips/mt76x8/
>> openwrt-ramips-mt76x8-tl-wr840n-v5-squashfs-sysupgrade.bin

Or, if you're lazy and trust me, you can download a prebuilt image that I created for WR840N V5. Note the version number!

Download openwrt-ramips-mt76x8-tl-wr840n-v5-squashfs-sysupgrade.bin

Also obtain libopenssl.ipk and openvpn-openssl.ipk and store them on some server. Please don't leech off of mine, and also I can't guarantee that the URLs will stay the same. Store the IPK files on your VPN server, and install nginx to serve them.

SSH into the router (ssh [email protected]).

Create /etc/openvpn and /tmp/root

mkdir -p /etc/openvpn
mkdir -p /tmp/root

Download client.ovpn

cd /etc/openvpn
wget "http://[yourVpnServerIP]/client.ovpn" -O client.ovpn

Replace [yourVpnServerIP] with the actual IP of your VPN server.

Create the installer script

Create /etc/openvpn/install_openvpn_in_ram and put the following in it:

#!/bin/sh /etc/rc.common

RAM_ROOT=/tmp/root
export PATH=$PATH:$RAM_ROOT/usr/bin:$RAM_ROOT/usr/sbin
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$RAM_ROOT/usr/lib

PACKAGES='libopenssl openvpn-openssl'

start() {
        [ ! -d $RAM_ROOT ] && mkdir $RAM_ROOT
        cd $RAM_ROOT

        for PACKAGE in $PACKAGES
        do
                echo Installing $PACKAGE...
                wget http://[yourVpnServerIP]/$PACKAGE.ipk
                tar xzf $PACKAGE.ipk
                tar xzf data.tar.gz
                find . -maxdepth 1 -type f -exec rm {} \;
        done
}

Replace [yourVpnServerIP] with the actual IP of your VPN server.

Create the starter script

Create /etc/openvpn/openvpn and put the following in it:

#!/bin/sh /etc/rc.common

RAM_ROOT=/tmp/root

export PATH=$PATH:$RAM_ROOT/usr/bin:$RAM_ROOT/usr/sbin
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$RAM_ROOT/usr/lib

start() {
        openvpn --writepid /tmp/openvpn.pid --daemon --cd /etc/openvpn --config client.ovpn
}

stop() {
        PIDOF=$(ps | egrep openvpn | egrep -v grep | awk '{print $1}')
        kill ${PIDOF}
}

Make OpenVPN auto start on boot

Replace the contents of /etc/rc.local with the following:

# Put your custom commands here that should be executed once
# the system init finished. By default this file does nothing.

##  Download and Install OpenVPN in RAM  ##
sleep 60
# Execute install script
/etc/openvpn/install_openvpn_in_ram start

## Start OpenVPN  ##
sleep 300

# OpenVPN start script
/etc/openvpn/openvpn start

exit 0

Make the scripts executable

chmod +x /etc/openvpn/install_openvpn_in_ram
chmod +x /etc/openvpn/openvpn
chmod +x /etc/rc.local

Add network interface tun0 as vpn

Open /etc/config/network and add the following:

config interface 'vpn'
        option ifname 'tun0'
        option proto 'unmanaged'

Add firewall rules to forward traffic through vpn

Open /etc/config/firewall and replace the contents of the file with the following:

config defaults
        option syn_flood        1
        option input            ACCEPT
        option output           ACCEPT
        option forward          REJECT
        option disable_ipv6     1

config zone
        option name             lan
        list   network          'lan'
        option input            ACCEPT
        option output           ACCEPT
        option forward          ACCEPT

config zone
        option name             wan
        list   network          'wan'
        option input            REJECT
        option output           ACCEPT
        option forward          REJECT
        option masq             1
        option mtu_fix          1

config zone
        option name             vpn
        list   network          'vpn'
        option input            REJECT
        option output           ACCEPT
        option forward          REJECT
        option masq             1
        option mtu_fix          1

config forwarding
        option src              lan
        option dest             vpn

config rule
        option name             Allow-DHCP-Renew
        option src              wan
        option proto            udp
        option dest_port        68
        option target           ACCEPT
        option family           ipv4

config rule
        option name             Allow-Ping
        option src              wan
        option proto            icmp
        option icmp_type        echo-request
        option family           ipv4
        option target           ACCEPT

config rule
        option name             Allow-IGMP
        option src              wan
        option proto            igmp
        option family           ipv4
        option target           ACCEPT

config rule
        option name             Allow-IPSec-ESP
        option src              wan
        option dest             lan
        option proto            esp
        option target           ACCEPT

config rule
        option name             Allow-ISAKMP
        option src              wan
        option dest             lan
        option dest_port        500
        option proto            udp
        option target           ACCEPT

config include
        option path /etc/firewall.user

Make sure the configuration is preserved when upgrading

Edit /etc/sysupgrade.conf and add the following:

/etc/openvpn

Reboot the router

Either execute reboot in the shell or unplug the router then plug it back in.

Check your IP

Make sure that your IP is shown as being the IP of your VPN. You can check this using my script here or by searching Google for "what's my ip".