Skip to content

Instantly share code, notes, and snippets.

@jesserockz
Last active December 4, 2025 20:32
Show Gist options
  • Select an option

  • Save jesserockz/f6e7dc277c8f850dd3d353d41138bb4b to your computer and use it in GitHub Desktop.

Select an option

Save jesserockz/f6e7dc277c8f850dd3d353d41138bb4b to your computer and use it in GitHub Desktop.
Tailscale script for GL-iNet Beryl AX side switch

Tailscale script for GL-iNet Beryl AX side switch

This script allows you to toggle tailscale settings using the physical side switch on the GL-iNet Beryl AX.

To install:

  1. Copy the below file to /etc/gl-switch.d/tailscale.sh and replace the exit_node_ip value with your exit node ip address.

  2. Make sure to set the execute bit on the new file: chmod +x /etc/gl-switch.d/tailscale.sh

  3. Depending on version:

    4.8.0 and above:
    Copy/write the switch-button file below to /etc/config/switch-button

    4.7.4 and below:
    Go to System -> Toggle Button Settings and choose Tailscale (On/Off) in the dropdown and Apply

# /etc/config/switch-button
config main
option func 'tailscale'
#!/bin/sh
# /etc/gl-switch.d/tailscale.sh
action=$1
if [ "$action" = "on" ];then
enabled=true
lan_enabled=false
wan_enabled=true
exit_node_ip="{{ REPLACE WITH YOUR EXIT NODE IP }}"
elif [ "$action" = "off" ];then
enabled=true
lan_enabled=false
wan_enabled=true
exit_node_ip=""
else
echo "Usage: $0 [on|off]"
exit 1
fi
curl -H 'glinet: 1' -s -k http://127.0.0.1/rpc -d "{\"jsonrpc\":\"2.0\",\"method\":\"call\",\"params\":[\"\",\"tailscale\",\"set_config\",{\"enabled\":$enabled,\"lan_enabled\":$lan_enabled,\"wan_enabled\":$wan_enabled,\"exit_node_ip\":\"$exit_node_ip\"}],\"id\":1}"
sleep 5
@Bl4cksus
Copy link

Bl4cksus commented Oct 7, 2025

Incredible this exists - thank you!
Like @smolz I also have a Slate 7 / GL-BE3600 and used the script by @DougS026 to reverse the switch and toggle tailscale. I also find this button behaviour more naturally.

However, this does not change the behaviour of the display of the device. What is now "on" will show as "off" on the screen. This can be solved by editing
/usr/bin/screen_disp_switch

in the if statement at the bottom, just change "$action" = "on" to "$action" = "off"
Maybe not the cleanest way but it does the trick. You can also change the *) Message to be "Tailscale" instead of "Toggle Button", so it will say Tailscale on the display. With that, my full /usr/bin/screen_disp_switch on 4.8.1 looks like this:

#!/bin/sh

action="$1"
func=$(uci -q get switch-button.@main[0].func)
sub_func=$(uci -q get switch-button.@main[0].sub_func)
case "$func" in
    "repeater")
        msg="Repeater"
        ;;
    "wifi")
        if [ "$sub_func" = "main_wifi" ];then
            msg="Main Wi-Fi"
        elif [ "$sub_func" = "guest_wifi" ];then
            msg="Guest Wi-Fi"
        else
            msg="Toggle Button"
        fi
        ;;
    "vpn")
        msg="VPN"
        ;;
    "tor")
        msg="Tor"
        ;;
    "adguardhome")
        msg="AdGuard Home"
        ;;
    "led")
        msg="LED"
        ;;
    *)
        msg="Tailscale"
        ;;
esac

if [ "$action" = "off" ]; then
    ubus call gl_screen set "{\"method\": \"switch\", \"params\": { \"enable\": true, \"mode\": \"$msg\", \"sub_func\": \"$sub_func\"}}"
else
    ubus call gl_screen set "{\"method\": \"switch\", \"params\": { \"enable\": false, \"mode\": \"$msg\", \"sub_func\": \"$sub_func\"}}"
fi

@ghzgod
Copy link

ghzgod commented Oct 22, 2025

Modified the script so that it updates the exit node IP based on the hostname of the exit node (so its dynamic). Additionally, I'm not sure why other scripts enable the WAN boolean, but I have that disabled and everything still works.

#!/bin/sh
# /etc/gl-switch.d/tailscale.sh

EXIT_NODE_NAME="MY-HOME-ROUTER-NODE-NAME"

action=$1

if [ "$action" = "off" ];then
  enabled=true
  lan_enabled=false
  wan_enabled=false
  exit_node_ip=$(tailscale status | awk "/$EXIT_NODE_NAME / && /exit node/ {print \$1}")
elif [ "$action" = "on" ];then
  enabled=true
  lan_enabled=false
  wan_enabled=false
  exit_node_ip=""
else
  echo "Usage: $0 [on|off]"
  exit 1
fi

curl -H  'glinet: 1' -s -k http://127.0.0.1/rpc -d "{\"jsonrpc\":\"2.0\",\"method\":\"call\",\"params\":[\"\",\"tailscale\",\"set_config\",{\"enabled\":$enabled,\"lan_enabled\":$lan_enabled,\"wan_enabled\":$wan_enabled,\"exit_node_ip\":\"$exit_node_ip\"}],\"id\":1}"

sleep 5

@ghzgod
Copy link

ghzgod commented Oct 22, 2025

New update.

If you want a kill switch while your exit node is enabled (and the exit node drops connectivity) then try this at your risk. I haven't had a chance to test thoroughly but it just adds a rule and removes that rule to block WAN connectivity if exit node drops and button is toggled in the on state. If button is turned off...(to the left) then it disables killswitch, and exit node, but keeps tailscale up.

Feedback is welcome/appreciated.

#!/bin/sh
# /etc/gl-switch.d/tailscale.sh

EXIT_NODE_NAME="MY-HOME-ROUTER-NODE-NAME"
KILL_SWITCH_ENABLED=true

action=$1

enable_kill_switch() {
  nft list chain inet fw4 forward_lan | grep -q "iifname \"br-lan\" oifname \"eth0\" counter.*drop"
  if [ $? -ne 0 ]; then
    nft insert rule inet fw4 forward_lan iifname br-lan oifname eth0 counter drop comment "tailscale-kill-switch"
  fi
}

disable_kill_switch() {
  nft -a list chain inet fw4 forward_lan | grep "tailscale-kill-switch" | awk '{print $NF}' | while read handle; do
    nft delete rule inet fw4 forward_lan handle $handle
  done
}

if [ "$action" = "off" ];then
  enabled=true
  lan_enabled=false
  wan_enabled=false
  exit_node_ip=$(tailscale status | awk "/$EXIT_NODE_NAME / {print \$1; exit}")
  
  curl -H  'glinet: 1' -s -k http://127.0.0.1/rpc -d "{\"jsonrpc\":\"2.0\",\"method\":\"call\",\"params\":[\"\",\"tailscale\",\"set_config\",{\"enabled\":$enabled,\"lan_enabled\":$lan_enabled,\"wan_enabled\":$wan_enabled,\"exit_node_ip\":\"$exit_node_ip\"}],\"id\":1}"
  
  sleep 6
  
  if [ "$KILL_SWITCH_ENABLED" = "true" ] && [ -n "$exit_node_ip" ]; then
    enable_kill_switch
  fi
elif [ "$action" = "on" ];then
  enabled=true
  lan_enabled=false
  wan_enabled=false
  exit_node_ip=""
  
  disable_kill_switch
  
  curl -H  'glinet: 1' -s -k http://127.0.0.1/rpc -d "{\"jsonrpc\":\"2.0\",\"method\":\"call\",\"params\":[\"\",\"tailscale\",\"set_config\",{\"enabled\":$enabled,\"lan_enabled\":$lan_enabled,\"wan_enabled\":$wan_enabled,\"exit_node_ip\":\"$exit_node_ip\"}],\"id\":1}"
else
  echo "Usage: $0 [on|off]"
  exit 1
fi

@DougS026
Copy link

Has anyone tried using the side switch to toggle between 2 different exit nodes? I gave it a quick go with the older firmware version but didn't get it fully working before having to turn attention to a different project.

@ghzgod do you think it would be possible to modify your kill switch to instead automatically redirect to a backup exit node if the primary drops?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment