Tailscale site-to-site pfSense - Linux

#security#networking

How to set up a Tailscale site-to-site L3 connection between a pfSense homelab subnet and a Linux cloud VM subnet.

I wanted an Oracle Cloud VM to be the single entry point to my homelab — monitoring reaching in, nothing listening on my home connection. Client-to-site would have given me access from a laptop. Site-to-site gives the two subnets each other, which is what monitoring actually needs.

Both sides run a subnet router. The machines behind them need nothing installed.

Subnet CIDR Subnet router
Homelab 10.57.57.0/24 10.57.57.1 — pfSense
Cloudlab 192.168.57.0/24 192.168.57.254 — Linux VM
Warning

Overlapping CIDR ranges and 4via6 subnet routing both break this. Check your two ranges before you start, because the failure looks like a routing problem rather than a design one.

pfSense side

Tailscale on pfSense is a FreeBSD port and it shows. Everything below works, but expect the UI to be a step behind the Linux client.

Install from System > Package Manager > Available Packages, then go to VPN > Tailscale and paste in an auth key from the admin console.

  • Enable Tailscale
  • Accept Subnet Routes
  • Advertised Routes: 10.57.57.0/24
  • Advertise Exit Node — optional, unrelated to site-to-site
  • Listen port: leave it

Then Firewall > NAT > Outbound, mode Hybrid Outbound NAT, one manual mapping: interface Tailscale, address family IPv4+IPv6, protocol any, source 10.57.57.0/24, destination any.

Caution (The NAT Alias field is missing)

On pfSense 23.09.1 the Translation Alias field simply isn’t in the UI. Under Translation, set Address to “Network or Alias” and type the Tailscale IP by hand as 100.xx.xx.xx/32.

Linux side

Terminal window
# Install tailscale
curl -sSL https://tailscale.com/install.sh | sh
# Activate routing for IPv4
echo 'net.ipv4.ip_forward = 1' | sudo tee -a /etc/sysctl.conf
# Activate routing for IPv6
echo 'net.ipv6.conf.all.forwarding = 1' | sudo tee -a /etc/sysctl.conf
# Apply routing configuration at kernel level
sudo sysctl -p /etc/sysctl.conf

Bring it up on the 192.168.57.254 device:

Terminal window
tailscale up --advertise-routes=192.168.57.0/24 --snat-subnet-routes=false --accept-routes

--snat-subnet-routes=false is the flag that makes this site-to-site rather than a one-way tunnel. Without it the destination sees the subnet router’s IP instead of the real source host, and return traffic across two networks has nowhere to go. --accept-routes is the other half — it’s what makes this node take the routes pfSense is advertising.

Approve the routes

Advertised is not the same as routed. Until you approve them, both sides are up, connected, and completely unable to reach each other.

In the admin console, open Machines, filter by property:subnet, and on each subnet router use the ellipsis menu → Edit route settings → approve. Skip this if you already have autoApprovers configured.

References