Site-to-site VPN using TAILSCALE/HEADSCALE between OPNSENSE and UNIFI OS

This is a guide in establishing a secure and reliable site-to-site VPN between OPNSense and UniFi OS using Tailscale or selfhosted Headscale. This setup enables seamless communication between networks, simplifies routing, and provides modern WireGuard-based mesh connectivity without complex firewall configurations.

ENVIRONMENT:

SITE A – OPNSENSE 25.7

192.168.10.0/24, VLAN1 192.168.11.0/24

SITE B – UNIFI CLOUD GATEWAY ULTRA on UNIFI OS 9.4

192.168.20.0/24, VLAN2 192.168.21.0/24

t

CASE DEPLOYMENT:

  • SITE B for simplicity of use is using UNIFI router, which can be easily replaced if needed and it is considered more reliable when experiencing power loss. The site has a LTE connection with cgi-NAT so you cannot use a IPSEC or any connection over static IP. Moreover UNIFI does not have a lot of options in terms of configuring OpenVPN or WG site-to-site if they’re using more complex configurations. That’s why TAILSCALE has proven to be a perfect solution to work and manage remotely.

  • SITE A has already OpenVPN site-to-site connections, Wireguard servers, Wireguard site-to-site. Installing Tailscale on OPNSENSE does not interfere with other connections. NETBIRD was not used since you need to get rid of any existing configuration on OPNSENSE.

1. OPNSENSE TAILSCALE SETUP

1.1 Add the Community Repository to OPNsense

By default, Tailscale plugin is not included in the available plugins to download/install in OPNsense. In order to extend the list of plugins, we need to add the  community plugin repository that includes a list of additional packages.

Before we can install the Tailscale plugin, we will need to setup & install that community repository.

To do this, we’ll need direct SSH or console access to our OPNsense appliance from our LAN.

SSH is disabled by default, but we can enable it quickly by navigating to System > Settings > Administration and then scrolling down to the Secure Shell section.

We’ll need to check the box for Enable Secure Shell and Permit Password Login. If you’re logging into OPNsense with the root account, you’ll also need to select Permit root user login.

Then scroll down to the bottom of the page & click Save.

By default OPNsense will set SSH Listen Interface set to All. It is recommend to enable access only LAN interface.
If you don’t need SSH to be accessible all the time, please remember to disable this service once you’re finished setting this up.

Okay, now that’s enabled – we can connect to our OPNsense appliance using your preferred SSH client (like PuTTY).

If you’re using the root account, you’ll likely be dropped into the OPNsense shell – but you can select option 8 here to access the underlying FreeBSD shell.

In order to install the community repository, we’ll pull down the repository config file using the following command:

fetch -o /usr/local/etc/pkg/repos/mimugmail.conf https://www.routerperformance.net/mimugmail.conf

Then, we’ll need to ask OPNsense to update it’s local cache with the new repo – so it knows what packages are hosted there:

If everything is successful, you’ll see output similar to below – which lists the mimugmailrepository now:

root@0xOPNsense:/home/matt # pkg update 
[...]
All repositories are up to date.

After these steps, you no longer need opened SSH connection, so please close the port 22 by going to System > Settings > Administration and then scrolling down to the Secure Shell section.

1.2 Installing the TAILSCALE PLUGIN

Now that the additional package repository is set up, we can download & install the Tailscale plugin via the OPNsense web interface.

So back in our browser, we can nagivate to: System > Firmware > Plugins. On this page we can search for adguard or scroll through the list to find it.

Then we just click the plus icon on the right side to install (not shown in the screenshotbelow).

This should install pretty quickly:



1.3 TAILSCALE CONFIGURATION

Please follow initial configuration of TAILSCALE as per guide

Ref: https://www.youtube.com/watch?v=VD2oMin_V3M 

In our scenario we would advertise a SITE A network: 192.168.10.0/24

Once the initial config is done verify Firewall > Rules > TAILSCALE

I have added an additional rule under the advertised LAN in Firewall > Rules > LAN (should be treated as optional)

Now our LAN should be accessible from outside on clients which have TAILSCALE installed.


Now in order to be able to see advertisted subnet on SITE B that we would create later on, we need to create one rule under FIREWALL >> NAT >> OUTBOUND

NAT OUTBOUND needs to be in Hybrid Mode

 

Create a new rule then:

  • Interface: Tailscalenode
  • Source: LAN net
  • Destination: any
  • Translation/target: Tailscalenode address (!!!!!!!)
  • Log packets: yes
  • Description: Tailscale access to subnets

Save & Apply

 

We have configured all needed things on OPNSENSE

2. UNIFI OS TAILSCALE SETUP:

2.1 Install Tailscale on UNIFI

Please acknowledge with TAILSCALE script for UNIFI over https://github.com/SierraSoftworks/tailscale-udm


SSH TO UNIFI THEN EXECUTE:

curl -sSLq https://raw.github.com/SierraSoftworks/tailscale-udm/main/install.sh | sh

2.2 Connect to Tailscale with advertising the subnet you want to be accessible on SITE A

Enable TAILSCALE service on unifi listing all subnets from Site B that you want to advertise

tailscale up --advertise-routes=”192.168.20.0/24,192.168.21.0/24″ --accept-routes=true --advertise-exit-node=true

Make sure you Accept the new machine on Tailscale dashboard and accept advertised routes

2.3 CREATE A NAT POSTROUTING RULE

In order to see advertised route from SITE A: 192.168.10.0/24 you need to create a rule for all subnets or specific ones to allow that

Choose an option which better suits your needs

OPTION A: ALLOW ALL INTERNAL SUBNETS TO REACH TO TAILSCALE AND CONNECT TO ADVERTISED SUBNETS

iptables -t nat -A POSTROUTING -o tailscale0 -j MASQUERADE

OPTION B: ALLOW ONLY INTERNAL 192.168.20.0/24 TO REACH TO TAILSCALE AND CONNECT TO ADVERTISED SUBNETS

iptables -t nat -A POSTROUTING -s 192.168.20.0/24 -o tailscale0 -j MASQUERADE

In my setup, I’ve chosen option B – any user under LAN 192.168.20.0/24 should be able to ping any device on 192.168.10.0/24

2.3 MAKE THE CHANGE PERSISTENT

With each device reboot the postrouting will dissappear so we need to make the change persistent on UNIFI OS 4.9

Copy & paste to UNIFI SSH:

# Pick the persistent base dir automatically
if [ -d /data ]; then BASE=/data; else BASE=/mnt/data; fi
echo "Using $BASE"
# Write the script
cat >"$BASE/ts-nat.sh" <<'EOF'
#!/bin/sh
PATH=/usr/sbin:/usr/bin:/sbin:/bin
LOG=/var/log/ts-nat.log
IF=tailscale0
SUBNET=192.168.20.0/24   # <-- change if needed

echo "$(date) ts-nat: start" >> "$LOG"

# Wait (max 10 minutes) for tailscale0 to appear
i=0
while ! ip link show "$IF" >/dev/null 2>&1; do
  i=$((i+1))
  [ "$i" -ge 600 ] && echo "$(date) ts-nat: $IF not up, giving up" >> "$LOG" && exit 0
  sleep 1
done
echo "$(date) ts-nat: $IF is up" >> "$LOG"

# Make sure IPv4 forwarding is on (harmless if already enabled)
sysctl -w net.ipv4.ip_forward=1 >/dev/null 2>&1 || true

# Add MASQUERADE only if it's not already present
if ! iptables -t nat -C POSTROUTING -s "$SUBNET" -o "$IF" -j MASQUERADE 2>/dev/null; then
  iptables -t nat -A POSTROUTING -s "$SUBNET" -o "$IF" -j MASQUERADE
  echo "$(date) ts-nat: added MASQUERADE $SUBNET -> $IF" >> "$LOG"
else
  echo "$(date) ts-nat: MASQUERADE already present" >> "$LOG"
fi
EOF

chmod +x "$BASE/ts-nat.sh"

Install the shell script as a service:

cat >/etc/systemd/system/ts-nat.service <

Verify the iptables before reboot

iptables -t nat -L POSTROUTING -n -v | grep tailscale0
tail -n 50 /var/log/ts-nat.log

You should see the MASQUERADE rule and a log entry like “added MASQUERADE …”.

 

REBOOT UNIFI

UNIFI# restart

 

Verify the changes after reboot

systemctl status ts-nat.service --no-pager
iptables -t nat -L POSTROUTING -n -v | grep tailscale0
tail -n 50 /var/log/ts-nat.log

3. VERIFY THE SITE-TO-SITE CONNECTIVITY

On SITE A, please use a terminal which has not Tailscale application installed and is under 192.168.10.1. Then ping the remote network 192.168.20.1

On SITE B, please use a terminal which has not Tailscale application installed and is under 192.168.20.1. Then ping the remote network 192.168.10.1

4. (OPTIONAL) MODYFING ACCESS TO EACH SUBNET

You may modify ACL on Tailscale if you’d like to have more granular way of connecting clients between subnets as per described:

 

ref: https://www.youtube.com/watch?v=Jn8_Sh4r8d4 

Or by creating Firewall rules on each device



0 Shares:
You May Also Like