Strongswan IPSec IKEv2 VPN on GL.iNet Beryl AX (GL-MT3000) and physical toggle

I recently bought a GL.iNet Beryl AX (GL-MT3000) travel router, which is running the most recent OEM firmware (version 4.7.0, 05 Dec 2024) based on OpenWRT 21.02. I have a Strongswan IPSec IKEv2 VPN on my home network I use occasionally when traveling. My understanding of these things is sufficient for basic configurations and little more, so I ended spending like 12 hours figuring this out. There were surprisingly few resources addressing this use case, so I am writing this up for others.

This is a brief guide to configuring Strongswan as a client on a Beryl AX to connect to an existing IKEv2 VPN client in tunnel mode such that all traffic from connected devices goes through that connection. The implementation below specifically uses password-based EAP-MSCHAPv2 authentication. I also describe how to make this connection toggle-able via the physical switch on the side of the router in a way that also allows you to use the existing web admin interface to reassign it between other VPNs (and back) without subsequently having to connect via SSH again. This should 95-100% of what is needed to get it working, although I tried a number of things and haven’t reset the router to confirm it works from scratch. This is definitely not the most minimal configuration for achieving this, some things are certainly unnecessary.

I followed this guide (archive.is link) for setting up the server. For variations on this setup on either end, there are various guides and a lot of good documentation. This should work with other IPSec IKEv2 VPN implementations.

I’m assuming you’ve finished basic setup of the router after first boot, have connected any devices you’ll be using to perform the setup to the router’s LAN (via WiFi or ethernet), and have internet/WAN connection via the router. You will need a device with a terminal/command-line interface; a smartphone could work but I would suggest something with a keyboard. With said device connected to the router’s network, you’ll need need connect via SSH and/or use scp to copy files via SSH. If you have difficulty connecting, make sure you didn’t change the SSH port in the router’s settings (under System > Security).

1. Install packages/plugins

You can do this via the command-line or the web admin interface (Applications > Plugins). Install the following packages:

  • strongswan-full
  • ip-full
  • xfrm

Via SSH (on router):

opkg install strongswan-full ip-full xfrm

2. Transfer CA Cert

You will need the ‘ca-cert.pem’ CA certificate you created when creating the VPN server. If you absolutely cannot use scp for some god foresaken reason, you may be able to put it on a USB drive, put that in the USB port on the back, and mount it/find it in the /mnt folder via ssh, and use the normal cp command from there analogous to the scp command below.

I’m assuming your router’s gateway IP is the default for the Beryl-AX (192.168.8.1); if that’s not the case, change it as needed.

Copy via SSH (via command-line, not initially connected to the router via SSH):

scp [/path/to/ca-cert.pem] [email protected]:/etc/ipsec.d/cacerts/ca-cert.pem

You will be prompted to enter your administrator password to tranfser.

3. Configure IPSec client connection

Either use scp to download, edit, and upload files, or use a text editor; I did the latter. Vim is built-in (command ‘vi’) but nano is simpler.

If you wish to use nano, via SSH (on router):

opkg install nano

Then to open files to edit:

nano /path/to/file.ext

CTRL-O to save as (enter to confirm name), and CTRL-X to exit (will prompt to save if you’ve modified the file since last save).

Open /etc/ipsec.conf and add the following lines (replace square brackets with relevant details):

conn ikev2-vpn
		rightid=[VPN_server_address]
		right=[VPN_server_address]
		rightsubnet=0.0.0.0/0
		rightauth=pubkey
		leftsourceip=%config
		leftid=[VPN_username]
		leftauth=eap-mschapv2
		eap_identity=[VPN_username]
		auto=start
		closeaction=clear

conn pass
		leftsubnet=192.168.8.0/24
		rightsubnet=192.168.8.0/24
		authby=never
		type=pass
		auto=route

Under “conn pass”, replace the left and right subnet with the subnet mask for the IPs you want to be excluded from going through the VPN. ‘192.168.8.0/24’ refers to every IP in the range 192.168.8.0-255. You will want this to cover your gateway IP and probably any other device on the router LAN. If your router uses 192.168.1.0-255 for LAN IPs, change this to 192.168.1.0/24. You can find the right CIDR subnet mask fairly easily online if you want to exclude other/more/fewer IPs.

WARNING: If you don’t have this configured correctly you will likely lose access to the web admin interface and may even lose SSH access when it loads the configuration.

You can also put this in a separate file add the following line to /etc/ipsec.conf (change file path/name as needed)

include /path/to/ikev2_vpn.conf

Additionally, add the following /etc/ipsec.secrets (replace square brackets with relevant info):

[VPN_username] : EAP "[VPN_user_password]"

Note you will need quotes around the password. You can also use client pubkey authentication, there is good documentation for achieving this elsewhere.

4. Test VPN connection

Command-line, via SSH (on router):

service ipsec start

and then

ipsec statusall

You should see an output that looks something like this (relevant, user-specific info in square brackets; irrelevant user-specific info omitted with ellipses/‘…’ throughout).

Connections:
  ikev2-vpn:  %any...[VPN_address]  IKEv1/2
  ikev2-vpn:   local:  [[VPN_username]] uses EAP_MSCHAPV2 authentication with EAP identity '[VPN_username]'
  ikev2-vpn:   remote: [[VPN_address]] uses public key authentication
  ikev2-vpn:   child:  dynamic === 0.0.0.0/0 TUNNEL
		pass:  %any...%any  IKEv1/2
		pass:   local:  uses public key authentication
		pass:   remote: uses public key authentication
		pass:   child:  192.168.8.0/24 === 192.168.8.0/24 PASS
Shunted Connections:
		pass:  192.168.8.0/24 === 192.168.8.0/24 PASS
Security Associations (1 up, 0 connecting):
  ikev2-vpn[1]: ESTABLISHED 9 seconds ago, [local_ip][[VPN_username]]...[VPN_address][[VPN_address]]
  ikev2-vpn[1]: IKEv2 SPIs: ..., EAP reauthentication in 2 hours
  ikev2-vpn[1]: IKE proposal: ...
  ikev2-vpn{1}:  INSTALLED, TUNNEL, reqid 1, ESP in UDP SPIs: ...
  ikev2-vpn{1}:  ..., 0 bytes_i, 0 bytes_o, rekeying in 44 minutes
  ikev2-vpn{1}:   10.10.10.1/32 === 0.0.0.0/0

Of particular note are Security Associations showing the VPN up, with an established connection and an installed tunnel.

5. Configure switch behavior

Create a shell script (ending in .sh) with your chosen VPN name in /etc/gl-switch.d/; I chose /etc/gl-switch.d/ikev2.sh

Add the following to this script:

#!/bin/sh

action=$1

if [ "$action" == "on" ];then
   /etc/init.d/ipsec start
fi

if [ "$action" == "off" ];then
   /etc/init.d/ipsec stop
fi

Ensure it has the correct permissions by entering the following via SSH:

chmod 775 /path/to/file.sh

With the file in this directory, the option to have the switch toggle this VPN should appear in the dropdown list in the web admin interface (System > Toggle Button Settings). In my example, it would appear as ‘ikev2’. If you do not see it, you can manually set the script that will be run by changing a setting via UCI.

Via SSH (on router):

uci set switch-button.@main[0].func="ikev2"

Done! The toggle switch should now control the connection to your IPSec IKEv2 VPN.

You can use the above to add additional functions to the switch. Any file in /etc/gl-switch.d/ will appear in the dropdown for the toggle button settings; any executable shell script [script].sh will appear as [script]. This script will be called by the built-in /etc/rc.button/switch script with the positional argument “on” or “off” based on the switches position (on is the side of the toggle switch with the dot beside it).

You can manually find the state of the switch (output as ‘lo’ or ‘hi’ for ‘on’ and ‘off’, respectively) and other hardware buttons/etc in /sys/kernel/debug/gpio (e.g. print to command-line using)

cat /sys/kernel/debug/gpio

You can specifically get the state of the switch with the following

cat /sys/kernel/debug/gpio | sed -n '/switch/s/.*) *\(in\|out\) *\(hi\|lo\).*/\2/p'

6. Test toggle switch

You can test various aspects of this. For the VPN tunnel’s actual function for end-users, just check your IP by visiting api.ipify.org on a connected device or the following command in terminal (note, run on the router may reflect traffic routing from devices)

curl api.ipify.org

You can check the IPSec connection status (should have no output when off) with

ipsec statusall

And you can check the switch status with

cat /sys/kernel/debug/gpio

Or

cat /sys/kernel/debug/gpio | sed -n '/switch/s/.*) *\(in\|out\) *\(hi\|lo\).*/\2/p'