I've got my Wireguard setup working reliably, but wondering what the best way is to toggle it on and off. It boots up, sets the time exactly because Wireguard needs that to work, and comes up and works. But, if I want to turn it off to connect to the Internet without going through the VPN, what do I do? And then what to do to turn it back on? It's very simple with OpenVPN. Not so with the wireguard. Is there a package? A simple way to do it from Luci? Or do I need a UCI commands script?
You can disable the interface either with LuCi or with uci.
See for some pointers for using uci commands a script I use for WG failover:
For disabling an interface:
wgi="your WG interface"
uci -q set network.${wgi}.disabled="1"
To disable:
uci -q del network.${wgi}.disabled
After disabling do a service network restart
To turn it back on do I just substitute disabled="0" for disabled="1" and restart the network?
What would be great is maybe two scripts I can add to the luci-app-commands menu item and run the scripts from inside Luci.
Could I simplify this to:
uci -q set network.wg0.disabled="1"
service network restart
To toggle it off
And then:
uci -q set network.wg0.disabled="0"
service network restart
To turn in back on?
I just have the one interface wg0
One simple script or two?
.
Make two scripts:
wgon
#!/bin/sh
# this script enables the wg0 interface
# deleting the disabled entry automatically enables the interface
uci -q del network.wg0.disabled
uci -q commit network #only necessary to make persistent between reboots
service network restart
wgoff
#!/bin/sh
# this script disables the wg0 interface
uci -q set network.wg0.disabled='1'
uci -q commit network #only necessary to make persistent between reboots
service network restart
Make two scripts with the respective names save them e.g. in /usr/
make executable:
chmod +x /usr/wgon
chmod +x /usr/wgoff
You can call the scripts from the command line e.g. with your phone with ssh apps like connectbot or juicessh, some have handy macros to execute scripts
Thanks so much for the simple solution. Great!
I'm testing the scripts now. Is the ${wgi} in the wgon script a typo? Should it be wg0 instead or is the ${wgi} the right way to do this?
.Sorry is a typo, I have corrected it
I think this will be used by a lot of people. The WireGuard is way faster than OpenVPN. Thank you again.
This is coming, a menu driven script to control your WireGuard tunnels
I like it!!! Something I can trigger from luci-app-commands package too I think.
First draft is ready: https://github.com/egc112/OpenWRT-egc-add-on/tree/main/wireguard-companion
@KSofen I had the same question for my setup.
What I did is that I have defined two IPs for my PC between which I can switch.
One is routed through the VPN interface and the other one not (firewall).
So I switch VPN on/off via toggling between the two IP address.
I did this in pfSense but it might work with OpenWrt too.
Have you ever tried this:
#!/bin/sh
#DEBUG=y # comment/uncomment to disable/enable debug mode
#CHECKSERVER=y # comment/uncomment to disable/enable check if the WG interface is a server by checking if a port is openend
# name: wireguard-companion.sh
# version: 1.01, 14-june-2024, by egc
# purpose: Toggle WireGuard tunnels on/off, show status and log
# script type: standalone
# installation:
# 1. Copy wireguard-companion.sh from https://raw.githubusercontent.com/egc112/OpenWRT-egc-add-on/main/wireguard-companion/wireguard-companion.sh to /usr/share
# either with, from commandline (SSH): curl -o /usr/share/wireguard-companion.sh https://raw.githubusercontent.com/egc112/OpenWRT-egc-add-on/main/wireguard-companion/wireguard-companion.sh
# or by clicking the download icon in the upper right corner of the script
# 2. Make executable: chmod +x /usr/share/wireguard-companion.sh
# 3. Run from command line with /usr/share/wireguard-companion.sh, most SSH clients will let you run a command on connection, if you use a key to connect, you can have an app like experience
# 4. Debug by removing the # on the second line of this script.
# 5. To skip WireGuard interfaces from the list which are a server, remove the # on the third line of this script
# usage:
# Toggle tunnels to enable/disable the WireGuard tunnel, show status, log and restart WireGuard or reboot from the command line
# A full Network restart (option 7) is only necessary if you disabled all tunnels to get a the default route back
# ================================================================================================================================
green='\e[92m'
blue='\e[96m'
red='\e[91m'
yellow='\e[93m'
clear='\e[0m'
ColorGreen(){
echo -ne "$green$1$clear"
}
ColorBlue(){
echo -ne "$blue""$1""$clear"
}
ColorYellow(){
echo -ne "$yellow""$1""$clear"
}
ColorRed(){
echo -ne "$red""$1""$clear"
}
[[ -z ${DEBUG+x} ]] || set -x
wireguard_state(){
stat=""
VAR=$(/usr/bin/wg | sed "/$1/,/interface/!d;/interface/d")
if [[ ! -z "$VAR" ]]; then
echo "${VAR//$'\n'/\\n}" | tr '\n' ' '
fi
}
WrongCommand () {
menu
}
any_key(){
read -n 1 -s -r -p " Press any key to continue"
return 0
}
show_tunnels(){
local x=1
for x in $(seq 1 $maxtunnels); do
eval "wgx=\$$(echo WG"${x}")"
disabled=$(uci -q get network."${wgx}".disabled)
dstate=${disabled:-0}
[[ $dstate -eq 0 ]] && state=$(ColorGreen 'enabled ') || state=$(ColorRed 'disabled')
echo -e " tunnel $x $state $(ColorYellow "${wgx}")"
x=$((x+1))
done
}
toggle_confirm(){
[[ $2 -eq 0 ]] && state="${red}disable${clear}" || state="${green}enable${clear}"
echo -e -n "\n Do you want to ${state} tunnel ${yellow}$1${clear}: Y/n ? : "
read -n 1 y_or_n
if [[ "$y_or_n" = "N" || "$y_or_n" = "n" ]]; then
echo -e "\n ${red}Abort${clear}"
any_key
menu
else
[[ $2 -eq 0 ]] && uci -q set network."$1".disabled='1' || { uci -q del network."$1".auto; uci -q del network."$1".disabled; }
pending=1
return 0
fi
}
toggle_tunnel(){
local wgtn=$(eval echo "\$$(echo WG"${1}")")
[[ $2 -eq 1 ]] && dstate=1 || dstate=$(uci -q get network."${wgtn}".disabled)
dstate=${dstate:-0}
if [[ $dstate -eq 1 ]]; then
toggle_confirm "$wgtn" 1
echo -e "\n Tunnel $wgtn will be ${green}enabled${clear}"
echo -e " ${yellow}Restart Network if all tunnels are disabled${clear}"
any_key
return 0
elif [[ $dstate -eq 0 ]]; then
toggle_confirm "$wgtn" 0
echo -e "\n Tunnel $wgtn is ${red}disabled${clear}"
echo -e " ${yellow}Restart Network if all tunnels are disabled${clear}"
any_key
return 0
else
echo -e "$red"" Tunnel $wgtn does not exist""$clear" Please choose an existing tunnel
return 1
fi
return 0
}
submenu_toggle(){
local wgtn
show_tunnels
[[ "$1" -eq 1 ]] && TOGGLE="enable, all \n others are disabled" || TOGGLE=toggle
echo -ne "\n ${yellow}Enter tunnel to $TOGGLE (1 - $nrtun, 0=Exit):${clear} "
[[ "$maxtunnels" -lt 10 ]] && read -n 1 tn || read tn # use this with more than 10 tunnels
if [[ $tn -eq 0 ]] 2>/dev/null; then
echo -e "\n Returning to main menu"
return 0
elif [[ $tn -gt 0 && $tn -le $maxtunnels ]] 2>/dev/null; then
toggle_tunnel "$tn" "$1"
if [[ "$1" -eq 1 ]]; then
for x in $(seq 1 $maxtunnels); do
[[ $x -eq $tn ]] && continue
wgtn=$(eval echo "\$$(echo WG"${x}")")
uci -q set network."$wgtn".disabled='1'
done
fi
uci commit network
service network reload
return 0
else
echo -e "$red""\n Wrong option, choose valid tunnel!\n""$clear"; submenu_toggle "$1"
fi
}
submenu_showstatus(){
wg show
echo -e "\n"
any_key
return 0
}
search_tunnels() {
local i=0
for line in $(uci -q show | grep "proto='wireguard'" | awk -F. '{print $2}'); do
if [[ ! -z ${CHECKSERVER+x} ]] && [[ ! -z $(uci -q get network."${line}".listen_port) ]] && grep -q "$(uci -q get network."${line}".listen_port)" /etc/config/firewall; then
echo "$line is wg server"
else
i=$((i+1))
eval WG$i="$line"
fi
done
maxtunnels=${i}
}
menu(){
clear
[[ $pending -eq 1 ]] && echo -e "\n ${yellow}Restart Network (option 8) if all tunnels are \n disabled or default route is missing${clear}"
echo -e "\n number state label"
show_tunnels
echo -e -n "
WireGuard toggle script to enable/disable tunnels
$(ColorGreen '1)') Showtunnels/Refresh
$(ColorGreen '2)') Toggle tunnel
$(ColorGreen '3)') Enable tunnel, Disable all others
$(ColorGreen '4)') Show WireGuard Status
$(ColorGreen '5)') Show Routes
$(ColorGreen '6)') Show Log
$(ColorGreen '8)') Restart Network
$(ColorGreen '9)') Save Settings and Reboot Router
$(ColorGreen '0)') Exit
$(ColorBlue 'Choose an option:') "
read -n 1 a
case $a in
"1"|"" )
menu
;;
2 )
echo -e " Toggle tunnel on/off\n"
submenu_toggle 0
menu
;;
3 )
echo -e " Enable tunnel, Disable others\n"
submenu_toggle 1
menu
;;
4 )
echo -e " Show WireGuard Status\n"
submenu_showstatus
menu
;;
5 )
echo -e " Show Routes\n"
ip route show
any_key
menu
;;
6 )
logread
any_key
menu
;;
8 )
echo -e "\n Restarting Network"
uci commit network
service network restart
pending=0
any_key
menu
;;
9 )
echo -e -n "\n Are you sure you want to Reboot y/N?: "
read -n 1 y_or_n
if [[ "$y_or_n" = "Y" || "$y_or_n" = "y" ]]; then
echo -e "\n Rebooting, Bye Bye"
uci commit
/sbin/reboot
exit 0
else
echo -e " ABORT"
any_key
fi
menu
;;
0 ) echo -e "\n Thanks for using wireguard-companion.sh"; exit 0 ;;
*) echo -e "$red"" Wrong option.""$clear"; any_key; WrongCommand;;
esac
}
clear
pending=0
search_tunnels
menu
It added quotes around variables when referencing them in UCI commands (e.g., uci -q get network."${wgx}".disabled
). To avoid potential issues with special characters in variable names.
It alse changed some single quotes to double quotes in strings displayed to the user (e.g., menu options). This is a matter of style, and both single and double quotes are valid for defining strings in shell scripts. Double quotes allow for easier interpolation of variables within the string.
My eventual, long-term goal is to get OPNSense on some good hardware operating as my firewall before the router and move the VPN server to that instead of using Raspberry Pi4 on the LAN port of the router. I know OpenWrt can be an OpenVPN server too. Still learning new stuff. WireGuard is much faster and preferable if I can get it setup right. But I just have the one WireGuard interface connecting to my home VPN server. The on/off toggle script @egc made is really all I need here, but of course I'm going to try his new script too.
When I cannot find a problem with a script otherwise it is too much OCD
You might be sane. I'm impressed.
I wanted to use wireguard-companion.sh from within Luci using the luci-app-commands package. When I execute it from there instead of from an open ssh shell connection, it doesn't open a shell window to display the menu which is expected because you have to ssh to the router and get the command prompt.
Is there a way do this where it will popup the menu when executed from luci-app-commands screen? I realize you'd have to have the first step parse the login and password to get there. What do you think?
You have to open it from the command line.
I use Connectbot on my Android phone and tablet, I have added an SSH key to login and added the command /usr/share/wireguard-companion.sh
as command to execute on logon so it can give you an app like experience, one button click to get the menu.
The same can also be done with Putty for Windows clients.
If doing your browsing from an iPhone/modern Android, I have a different suggestion for you. Use native MAC of your mobile device to connect, then enter that MAC address in a pbr policy to connect to the internet via wg tunnel, then when you want to browse without wg, in your phone settins enable MAC address masking, so the phone will reconnect to the WiFi with randomized MAC and it should go to the internet without wg tunnel.
Not sure if desktop OSes have the similar MAC randomization feature, but if they do, should also work for desktop OS.
Just for the record -- these two scripts are working perfectly for me and can be called from Luci with the luci-app-commands package installed and configured. Super easy and this simple solution was just the best for my setup. WireGuard is still a tricky one and making sure your time is correct is critical for some reason. But now, I can easily switch WG on and off, or enable OpenVPN, or turn it all off and use it as a regular router. I just needed a few little tweaks.
So if anyone has WireGuard issues - make sure your time is set before checking anything else.