Click here to Skip to main content
14,976,254 members
Articles / General Programming / Internet
Posted 1 Mar 2021


4 bookmarked

Configuring VPN client on OpenWRT router

Rate me:
Please Sign up or sign in to vote.
5.00/5 (3 votes)
3 Mar 2021CPOL6 min read
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.

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


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, instead of the default, 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=''
uci set network.lan.netmask=''
uci commit network
/etc/init.d/network restart

The last command restarts the network, and then luci interface can be accessed at 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=''
uci set network.wifi24.netmask=''

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'ipv4'
uci set mwan3.ovpn.initial_state='offline'
uci add_list mwan3.ovpn.track_ip=''
uci add_list mwan3.ovpn.track_ip=''
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=''
uci add_list mwan3.wan.track_ip=''
uci set'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=''
uci set'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.


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
sed -i "/auth-user-pass/c\auth-user-pass /etc/openvpn/credentials" $path
echo -e "auth-user-pass /etc/openvpn/credentials\n$(cat $path)" > $path

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

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

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 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                               
if [ $ACTION == 'ifdown' ]; then         
if [ $INTERFACE == 'ovpn' ]; then
echo none > /sys/class/leds/<led_file>/trigger 

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.


  • 1st March, 2021: Initial version


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


About the Author

Software Developer
India India
No Biography provided

Comments and Discussions

-- There are no messages in this forum --