How to run Tailscale on a Synology rt6600ax router

25 Feb 2025 09:00 | synology | security | tailscale

Steps for installing Tailscale on a Synology rt6600ax. The same steps will probably work on the 2600 but I haven’t tried it.

1) SSH to the router as root

2) Retrieve the package for DSM7 / ARMv8:

curl https://pkgs.tailscale.com/stable/tailscale-armv8-1.80.0-700080000-dsm7.spk -o tailscale-armv8-1.80.0-700080000-dsm7.spk

3) untar the package:

mkdir tmp && cd tmp
tar xf ../tailscale-armv8-1.80.0-700080000-dsm7.spk

4) untar the inner package containing the binaries:

tar xf package.tgz

5) copy the binaries to /usr/local/bin/

cp bin/tailscale /usr/local/bin/
cp bin/tailscaled /usr/local/bin/

6) cleanup

cd
rm -rf tmp tailscale-armv8-1.80.0-700080000-dsm7.spk

7) create a wrapper script at /usr/local/bin/tailscale_wrapper.sh - this will be used to keep the service running

#!/bin/ash
if [ ! -e /var/db/tailscale ] ; then
    mkdir /var/db/tailscale
fi
cd /var/db/tailscale
while :
do
    /usr/local/bin/tailscaled --state=tailscaled.state 1>/var/log/tailscale.stdout 2>/var/log/tailscale.stderr
    sleep 1
done

8) create /etc/rc.local to start the tailscale service when the router boots:

Update: this method results in the tailscaled process and its bash wrapper being killed under certain conditions, like the ssh daemon being turned off and on again. To work around this I recommend running the tailscale wrapper from cron so that it always gets restarted. Add this line to /var/spool/cron/crontabs/root:

* * * * * root /usr/bin/flock -x -n /root/.tailscaled.lock /usr/local/bin/tailscale_wrapper.sh

9) ensure the wrapper script is executable:

chmod 755 /etc/rc.local /usr/local/bin/tailscale_wrapper.sh

10) run tailscaled manually once in order to register the device with your account:

mkdir /var/db/tailscale
cd /var/db/tailscale
/usr/local/bin/tailscaled --state=tailscaled.state

You will be prompted to visit a link in order to link the device to your account. Once this is completed successfully you can press ctrl-c to quit tailscaled.

11) reload the crond process with:

killall -HUP crond

After 60 seconds tailscaled should be running, then bring tailscale up with:

tailscale up

If you want to use the router as an exit node:

tailscale up --advertise-exit-node

This should work but you may need to configure firewall rules to allow access to the LAN.

Creating firewall rules for access to the router over Tailscale

In order to access the router via Tailscale you need to allow your other tailscale devices in the firewall. This can be done through the SRM interface.

1) Create firewall rule

2) Source network interface - All (there’s no way to select the tailscale interface so we have to select All here, but we will limit traffic by specific IP addresses anyway so this is ok)

3) Source IP address - specific IP address, enter the tailscale IP address of the machine on your tailscale network you want to be able to access the router

4) Source port - All

5) Destination network interface - All

6) Destination IP address - SRM

7) Destination ports - enter 22,8001 for ssh and the web interface, or just 8001 for the web interface

8) Action allow

Click apply and enjoy secure access to your synology router through your Wireguard Tailscale network from anywhere in the world :)

Enabling access from the tailnet

If you want your router to be accessible to all hosts over the tailnet, run this via cron:

#!/usr/bin/env python
import os
import sys
import re
ALLOW_PORTS = [22, 8001]
allowed = {}
for line in os.popen("/sbin/iptables -L INPUT_FIREWALL -n -v").read().rstrip().split("\n"):
    m = re.match('^.*? RETURN[\s\t]+tcp.*?tailscale0[\s\t]+\*[\s\t]+0\.0\.0\.0\/0[\s\t]+0\.0\.0\.0\/0[\s\t]+tcp[\s\t]+dpt:([\d]+)', line)
    if m:
        allowed[int(m.group(1))] = 1
for port in ALLOW_PORTS:
    if port not in allowed:
        print("allowing tcp/%d ipv4 through the tailscale0 interface" % (port))
        os.system("/sbin/iptables -I INPUT_FIREWALL -i tailscale0 -p tcp -m tcp --dport %d -j RETURN" % (port))
allowed = {}
for line in os.popen("/sbin/ip6tables -L INPUT_FIREWALL -n -v").read().rstrip().split("\n"):
    m = re.match('^.*? RETURN[\s\t]+tcp.*?tailscale0[\s\t]+\*[\s\t]+::\/0[\s\t]+::\/0[\s\t]+tcp[\s\t]+dpt:([\d]+)', line)
    if m:
        allowed[int(m.group(1))] = 1
for port in ALLOW_PORTS:
    if port not in allowed:
        print("allowing tcp/%d ipv6 through the tailscale0 interface" % (port))
        os.system("/sbin/ip6tables -I INPUT_FIREWALL -i tailscale0 -p tcp -m tcp --dport %d -j RETURN" % (port))

Unfortunately there’s no way to target the tailscale0 interface directly in the UI, so your only options there are to allow access from specific tailnet hosts or the entire internet which is obviously not desirable. Running the above via cron allows rules to persist that allow access from all hosts on the tailnet, even new or ephemeral ones.

Running as an exit node

If you want to run tailscaled on the router as an exit node you need to give it an explicit port and allow traffic through the firewall in order to get direct connections. This is probably a good idea regardless of whether you run as an exit node or not.

1) Choose a high port number to use for tailscale

2) Update the /usr/local/bin/tailscale_wrapper.sh script to specify your port:

#!/bin/ash
if [ ! -e /var/db/tailscale ] ; then
    mkdir /var/db/tailscale
fi
cd /var/db/tailscale
while :
do
    /usr/local/bin/tailscaled --state=tailscaled.state -port=<PORT NUMBER> 1>/var/log/tailscale.stdout 2>/var/log/tailscale.stderr
    sleep 1
done

3) kill the wrapper process and tailscaled so it gets restarted

4) Create a firewall rule through the SRM interface allowing:

Protocol: udp Source network interface: All Source IP: All Source ports: All Destination network interface: All Destination IP address: SRM Destination Ports: