Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / programming / Internet

Configuring VPN Client on OpenWRT Router

4.88/5 (8 votes)
16 Jul 2023CPOL7 min read 46.9K   331  
Steps to enable VPN client on an OpenWRT router using openvpn and mwan3
This article is a series of shell commands to enable VPN client on an OpenWRT router using openvpn and mwan3 packages, enabling VPN access on all LAN and WiFi connected devices automatically with a single tunnel. Some flash and initial configuration instructions are also in here. Warning - Works only with version 19.XX of OpenWRT.

Warning - Works only with version 19.XX of OpenWRT. Something in higher versions of mwan3 broke this implementation.

When a device connects to VPN using an app, it opens an encrypted tunnel to the VPN server, shown as the green line in illustration below. Any spies logging traffic cannot look inside the tunnel, making the communications secure. Red lines represent regular traffic which can be logged.

Image 1

After configuring an OpenWRT router as described in this article, all LAN and WiFi connected devices will access the internet through one VPN tunnel opened by the router. This will be more efficient than individual devices connecting to VPN directly, as all VPN related processing is done on this dedicated device instead of on each connected device separately. This is illustrated in the diagram below.

Image 2

Introduction

OpenWRT is a secure open source Linux based firmware compatible with many routers. It is easy to use and configure for many different applications. It has a lot of useful libraries in package manager opkg, of which we will use openvpn and mwan3 packages to create a multi-wan VPN router. VPN service providers usually provide OpenVPN configuration files for their servers. These *.ovpn files can be used to create a tunnel, which appears as ‘/dev/tun0’ in the OpenWRT device.

Once a working tunnel is setup, multi-wan (mwan3) and a new network can be configured to enable VPN for all LAN and WiFi connected devices. Read about mwan3 here. mwan3 allows for seamless switching between network interfaces, so that when the vpn connection fails or during command restarts, the network switches back to regular internet, so that our videos will keep playing, and will switch back the VPN network when it becomes available again.

In the following sections, the uci commands can be copy pasted into the OpenWRT shell, and some changes in the configuration pages using luci, and the router will be fully configured by the time you reach the last section.

Flashing OpenWRT

If your router does not have OpenWRT firmware, check if it is compatible with OpenWRT here. Find your firmware using this handy tool, and flash your router. This can be considered the hardest step in this article, and I suggest having an unbrick manual in hand. The configuration below was written for OpenWRT version 19.07.3, and should work fine on more recent versions. After the flash, connect your PC to one of the LAN ports, internet to WAN port of the router and reboot. ssh into the router with ssh root@openwrt.lan to enter the commands you will encounter in the following steps. You can access luci at http://openwrt.lan/cgi-bin/luci/.

Image 3

Initial Configuration

The configuration after a fresh flash will contain network, dhcp and firewall settings for wan and lan interfaces by default. There are two firewall zones wan and lan. Usually, I change the lan interface address to 192.168.2.1, instead of the default 192.168.1.1, and this can be done using the below uci commands. You can follow additional instructions here.

uci set network.lan.proto='static'
uci set network.lan.ipaddr='192.168.2.1'
uci set network.lan.netmask='255.255.255.0'
uci commit network
/etc/init.d/network restart

The last command restarts the network, and then luci interface can be accessed at http://192.168.2.1 along with at http://openwrt.lan.

Image 4

Enable WiFi

To enable WiFi, a new interface wif24 has to be created and the WiFi device has to be attached to this new interface. Run the following commands to setup the wifi24 network interface.

uci set network.wifi24='interface'
uci set network.wifi24.proto='static'
uci set network.wifi24.ipaddr='192.168.3.1'
uci set network.wifi24.netmask='255.255.255.0'

uci set dhcp.wifi24='dhcp'
uci set dhcp.wifi24.interface='wifi24'

Add the new interface to lan firewall zone.

uci add_list firewall.@zone[0].network='wifi24'

uci commit dhcp
uci commit network
uci commit firewall

/etc/init.d/firewall restart
/etc/init.d/network restart

At this point, we have created a network, but network device is not present.

Image 5

This new interface can be associated it with a radio in luci at http://openwrt.lan/cgi-bin/luci/admin/network/wireless.

Image 6

The luci interface status should look like the below at this point, after saving the configuration.

Image 7

Test internet in LAN and WiFi connected devices before proceeding to the next step. Download a backup if you wish, using this page http://openwrt.lan/cgi-bin/luci/admin/system/flash so that you can quickly come back to this initial state.

Install Packages

Install the required packages from opkg:

opkg update
opkg install openvpn-openssl openvpn-easy-rsa luci-app-openvpn curl mwan3 luci-app-mwan3

This above command installs openvpn, mwan3 packages.

Create VPN Network Interface

A new network interface ovpn which will interface a tunnel device tun0 can be created by using the following commands.

uci set network.ovpn='interface'
uci set network.ovpn.proto='none'
uci set network.ovpn.ifname='tun0'

uci commit network

Add ovpn interface to wan firewall zone.

uci show firewall.@zone[1]
uci add_list firewall.@zone[1].network='ovpn'

uci commit firewall

/etc/init.d/firewall restart
/etc/init.d/network restart

Now that the network interface is setup, let us continue with configuring mwan3. We will open tunnel tun0 after configuring mwan3. Meanwhile, 'Network device is not present' will show up in luci interface page due to non-existent tun0.

Image 8

Configure multi-wan (mwan3)

The default mwan3 configuration contains some dummy configuration, hence will be emptying the file before configuration.

rm /etc/config/mwan3
touch /etc/config/mwan3

Enter the following uci commands to create multi-wan that uses both wan and ovpn networks.

uci set mwan3.globals='globals'
uci set mwan3.globals.mmx_mask='0x3F00'
uci set mwan3.globals.rtmon_interval='5'

uci set mwan3.ovpn='interface'
uci set mwan3.ovpn.enabled='1'
uci set mwan3.ovpn.family='ipv4'
uci set mwan3.ovpn.initial_state='offline'
uci add_list mwan3.ovpn.track_ip='8.8.8.8'
uci add_list mwan3.ovpn.track_ip='8.8.4.4'
uci set mwan3.ovpn.track_method='ping'
uci set mwan3.ovpn.reliability='2'
uci set mwan3.ovpn.count='1'
uci set mwan3.ovpn.size='56'
uci set mwan3.ovpn.max_ttl='60'
uci set mwan3.ovpn.check_quality='0'
uci set mwan3.ovpn.failure_interval='5'
uci set mwan3.ovpn.recovery_interval='5'
uci set mwan3.ovpn.timeout='5'
uci set mwan3.ovpn.interval='5'
uci set mwan3.ovpn.down='3'
uci set mwan3.ovpn.up='3'

uci set mwan3.wan=interface
uci set mwan3.wan.enabled='1'
uci add_list mwan3.wan.track_ip='8.8.8.8'
uci add_list mwan3.wan.track_ip='8.8.4.4'
uci set mwan3.wan.family='ipv4'
uci set mwan3.wan.reliability='2'
uci set mwan3.wan.count='1'
uci set mwan3.wan.timeout='2'
uci set mwan3.wan.failure_latency='1000'
uci set mwan3.wan.recovery_latency='500'
uci set mwan3.wan.failure_loss='20'
uci set mwan3.wan.recovery_loss='5'
uci set mwan3.wan.interval='5'
uci set mwan3.wan.down='3'
uci set mwan3.wan.up='8'

uci set mwan3.wan_m1=member
uci set mwan3.wan_m1.interface='wan'
uci set mwan3.wan_m1.metric='2'
uci set mwan3.wan_m1.weight='3'

uci set mwan3.ovpn_m1=member
uci set mwan3.ovpn_m1.interface='ovpn'
uci set mwan3.ovpn_m1.metric='1'
uci set mwan3.ovpn_m1.weight='6'

uci set mwan3.wan_policy=policy
uci set mwan3.wan_policy.last_resort='default'
uci add_list mwan3.wan_policy.use_member='wan_m1'

uci set mwan3.default_policy=policy
uci set mwan3.default_policy.last_resort='default'
uci add_list mwan3.default_policy.use_member='ovpn_m1'
uci add_list mwan3.default_policy.use_member='wan_m1'

uci set mwan3.default_rule_v4=rule
uci set mwan3.default_rule_v4.dest_ip='0.0.0.0/0'
uci set mwan3.default_rule_v4.family='ipv4'
uci set mwan3.default_rule_v4.use_policy='default_policy'

uci commit mwan3
/etc/init.d/mwan3 restart

The mwan3 is configured at this point, you can see mwan3 status at http://openwrt.lan/cgi-bin/luci/admin/status/overview at the bottom of page. ovpn interface status will show as disabled, and opening a tunnel tun0 will fix that.

Image 9

Reboot router with reboot if you can’t see the two interfaces. The next step is to open the tunnel tun0, so that ovpn interface starts working.

Creating the tunnel ‘tun0’

All information to start a tunnel is inside an *.ovpn file. Some additional options are to be added to this file, one of them being a line route-noexec so that openvpn client won’t make modifications to routing table, as routes are managed automatically by mwan3. Another is a line dev tun0 so that the tunnel opened will be named tun0.

Download ovpn File

I use NordVPN, hence can download an *.ovpn file from this page.

path=/etc/openvpn/server1.ovpn
ovpnurl=
https://downloads.nordcdn.com/configs/files/ovpn_legacy/servers/in101.nordvpn.com.udp1194.ovpn

curl --output $path $ovpnurl

Create Credentials File

echo "vpn_username" >> /etc/openvpn/credentials
echo "vpn_password" >> /etc/openvpn/credentials

Modify ovpn File

Now to add the required custom options (auth-user-pass, dev tun0 and route-noexec) to file, run the below commands:

if grep -F "auth-user-pass" $path
then
sed -i "/auth-user-pass/c\auth-user-pass /etc/openvpn/credentials" $path
else
echo -e "auth-user-pass /etc/openvpn/credentials\n$(cat $path)" > $path
fi

if grep -F "dev tun" $path
then
sed -i "/dev tun/c\dev tun0" $path
else
echo -e "dev tun0\n$(cat $path)" > $path
fi

if grep -F "route-noexec" $path
then
echo "already present in file..."
else
echo -e "route-noexec\n$(cat $path)" > $path
fi

Configure openvpn instance

Default openvpn configuration contains some dummy configuration, hence empty the file.

rm /etc/config/openvpn
touch /etc/config/openvpn

Now to create a new openvpn instance.

uci set openvpn.ovpn1=openvpn
uci set openvpn.ovpn1.config=$path
uci set openvpn.ovpn1.enabled='1'

uci commit openvpn
/etc/init.d/openvpn restart

After this step, you can access the openvpn instance at http://openwrt.lan/cgi-bin/luci/admin/vpn/openvpn. Enable and start this instance ovpn1.

Image 10

In case the instance does not start: you can manually run openvpn command and check what's wrong.

openvpn --config $path

Testing and Verifying

You can now test the tunnel using ping -I tun0 8.8.8.8. mwan3 will now automatically detect ovpn as a working interface and will switch all traffic through it. Verify the change in public IP address on your connected devices.

Image 11

Both the interfaces in mwan3 status in luci must be green at this point.

Image 12

Status LED Configuration

You can use one of the available LEDs on the router to show the status of ovpn network. The LED can be configured turn on when ovpn interface is connected and turn off when disconnected. This will be handy to quickly show the status of the VPN connection.

The device’s LEDs are listed as files in this directory /sys/class/leds, they can be programmatically turned on and off using the below lines.

echo default-on > /sys/class/leds/<led_file>/trigger
echo none > /sys/class/leds/<led_file>/trigger 

mwan3 has a notification script (/etc/mwan3.user) to help us run commands when interfaces managed by it go up or down. You can modify this script at http://openwrt.lan/cgi-bin/luci/admin/network/mwan/notify. Append the following lines to it.

if [ $ACTION == 'ifup' ]; then                                                  
if [ $INTERFACE == 'ovpn' ]; then                                       
echo default-on > /sys/class/leds/<led_file>/trigger                               
fi                                                                      
fi                                       
                                         
if [ $ACTION == 'ifdown' ]; then         
if [ $INTERFACE == 'ovpn' ]; then
echo none > /sys/class/leds/<led_file>/trigger 
fi                                  
fi

Prevent DNS Leak

The above configuration will leak dns requests through wan interface, and the sniffer can log the dns requests. To avoid this, enter the following commands. Check DNS leak test to confirm dns is not leaking.

uci set network.wan.peerdns='0'
uci commit network

/etc/init.d/network restart 

Further Enhancements

As any number of interfaces can be managed by mwan3, like a USB 4G dongle that will act like the last resort if both wan and ovpn are down. We can also implement kill switch configuration so that when vpn is down, internet will go off, instead of falling back to unprotected internet. These things can be done by tweaking the mwan3 configuration and adding new policies.

I have also attached some config files in a zip here, in case that might help.

Other cleaner and more compatible (without mwan3) method of implementing VPN OpenWRT router here: Self-Healing Randomized VPN with Kill Switch in OpenWRT Router

History

  • 1st March, 2021: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)