Intro Link to heading

This post is intended to serve as a reminder to myself of how I managed to get devices that are not on my tailnet to route to devices that are, via my OPNsense firewall. Hopefully this will help someone else achieve something similar as well! This isn’t a very complicated process and uses some networking technologies that have been around for a long time but I thought it would be best to document the process.

Why do I want to do this? Link to heading

That you can only answer, but I can tell you why I wanted to do it. First I need to explain a little bit about how tailscale works. Tailscale is a ‘mesh VPN’ this is opposed to a traditional VPN which uses a hub and spoke model (one central device in the middle such as a router and many clients connected to it). One advantage of a mesh VPN is that it creates a ‘flat’ network, meaning that devices do not have to route via a central router, they can talk directly over the mesh. Using tailscale you can install the tailscale client on 2 devices and like magic they can both route to each other via the ’tailnet’. This does raise a question though, what if one wants to route to a device that can’t have tailscale installed on it? Well tailscale has this covered as well via the subnet router feature.

There is one path missing though, what if I want to route from a device not on a tailnet to a device on a tailnet? You might be asking why anyone would want to do that, for me it was simply because I don’t want all my devices to be on the tailnet, just the ones that roam or aren’t on my LAN such as EC2’s etc. If I want to access these devices from my PC which doesn’t have tailscale installed I need a way to go via the tailnet. Whilst tailscale does support pretty much all modern OS’s if you manage to encounter a device that can’t get tailscale installed on it but needs to, this guide may help.

What do I need? Link to heading

In order to do this I used to following components to get it working, it is possible to do the same thing with different technologies, where appropriate I will try and offer alternatives.

  1. A tailnet (duh), either using tailscale proper or an open-source alternative like headscale.
  2. A firewall running OPNsense, however any OS that has a tailnet client and can be configured as a router with SNAT will work; Linux or FreeBSD (and derivatives such as OPNsense) are a good choice.
  3. Unbound DNS running on OPNsense, but any DNS resolver, or forwarder that allows domain level overrides will work. For the scope of this guide the DNS software will need to run on the same device that is running the tailscale client providing the NAT (so in my case OPNsense).

So how do I do this? Link to heading

Step one: Link to heading

Firstly you will need to install tailscale on your OPNsense router, if you haven’t done this already rather than using the guide on the tailscale website, I recommend using the plugin method as it is easier and more in line with how additional software is installed in OPNsense. An excellent video from the developer of the tailscale plugin that has a full tutorial can be found here. Make sure you assign an interface as shown in the video.

Step two: Link to heading

  • Go to Firewall > NAT > Outbound in the menu.
  • Click the top right radio button to change the mode to Hybrid outbound NAT rule generation (automatically generated rules are applied after manual rules). Click save, then click Apply Changes to apply the change.

Image showing the radio button setting

  • Click the plus icon to create a new rule.

Image showing where to find the plus button for a new rule

  • Under the interface section select the newly created tailscale interface (mine is named TLSC). For TCP/IP version select IPv4 (if you want ipv6 as well you can duplicate this rule).
  • Under source address leave as any if you want all devices on the LAN to be able to reach tailscale, otherwise select an address/device/subnet/alias.
  • Leave source port as any.
  • VERY IMPORTANT: Under destination address set it to single host or network and enter 100.64.0.0/10 (place 100.64.0.0 in the textbox and select /10 from the dropdown).
  • The rest can be left as default.

Image showing the rest of the SNAT rules

Now we’ve setup the source NAT (SNAT) from our router, from a non tailscale device we can reach the tailnet via ip address, to test this find an IP of one of your tailnet devices (either by going to the tailscale website or running tailscale status on the cli of a device on the tailnet) and do a simple ping, you should get a response.

Step Three: Link to heading

If you are using the tailscale magic DNS feature (which if your not check it out, it’s very slick), the last piece of the puzzle is getting DNS resolution to work from a non tailnet device. This is possible if you are using unbound on OPNsense as the DNS server for devices on your network (and may be possible with other DNS servers avaiable on tailscale).

  • Go to the tailscale website and navigate to DNS on then top bar and copy the domain under Tailnet name.
  • Go to Firewall > Services > Unbound DNS > Query Forwarding.
  • Click the plus icon to create a new forwarding rule.
  • For Domain we need to enter our tailnet magic DNS domain name we copied earlier.
  • Set server IP to 100.100.100.100, if you’re wondering why that is the address you can read more here.
  • Set the port to 53.

Image showing DNS settings

Now from a non-tailnet device, attempt to do a domain lookup and you should be able to lookup devices on your tailnet!

Final Words Link to heading

Firstly thanks for reading! I hope this helps someone out there! Before I end the post I just wanted to add some final things that may help someone who doesn’t have the exact same network setup:

  • If you can’t install OPNsense on your router but you have the ability to create static routes, you could spin up a device running tailscale (whether that be a pyhsical hardware device or a VM) and make a route to 100.64.0.0/10 on your router using the tailscale device as the gateway, and on the tailscale device create a NAT rule for traffic coming in on it’s LAN interface to do a SNAT and forward the traffic onto the tailnet that way.
  • If you’re doing this on a Linux box there are a tonne of different ways to approach but my advice would be to do it in nftables or if on an older distro, iptables.
  • If you’re on FreeBSD you can use either pf or ipfw.
  • If your DNS server isn’t on tailscale (and for whatever reason it can’t be) and you want the magic DNS to work you could create a small DNS server using unbound on a device that is running tailscale that is just set to forward requests to the 100.100.100.100:53 DNS server, and then on the device doing DNS for the network, set an override rule in for your tailnet domain to send it to the LAN interface of the device running unbound.

Thanks again for reading!