Why Tailscale, not a real VPN server

I looked at running my own WireGuard setup by hand … port forwarding, managing keys myself, keeping track of which peer is which. Tailscale does all of that for you, on top of WireGuard, and the actual setup on each machine ends up being a handful of lines. Every device I own is on the same tailnet now: the T620 server, my NixOS desktop, and … the one that surprised me … a MacBook Air 6,2 from 2014 that has no business running anything modern smoothly, and does it fine anyway.

The whole NixOS config, genuinely this short

{
  config,
  pkgs,
  lib,
  ...
}:
{
  services.tailscale.enable = true;

  networking.firewall = {
    enable = true;
    trustedInterfaces = [ "tailscale0" ];
    allowedTCPPorts = [ 22 ];
    allowedUDPPorts = [ 41641 ];
  };

  powerManagement.resumeCommands = ''
    ${pkgs.systemd}/bin/systemctl restart tailscaled
  '';
}

That’s it. Three real settings, not a wall of options.

Breaking down each piece

services.tailscale.enable = true; … installs and enables the daemon. On a normal distro this is a package install plus a systemd enable; on NixOS it’s one line that handles both.

trustedInterfaces = [ "tailscale0" ] … this is the one that actually matters and the one I got wrong on the T620 the first time around. Tailscale creates its own virtual network interface, and without explicitly trusting it in the firewall, traffic coming through the tailnet gets treated the same as traffic from the open internet … meaning things that should just work over Tailscale (SSH, Samba, SFTP) get blocked or, worse, silently forced through a relay because the direct connection can’t establish properly. One line, and every service already running is reachable over the tailnet without touching individual port rules for each thing.

allowedTCPPorts = [ 22 ] … SSH, opened normally, nothing Tailscale-specific about this line, just there because I want SSH reachable.

allowedUDPPorts = [ 41641 ] … this is Tailscale’s own port for direct peer-to-peer connection negotiation (NAT hole-punching). Without it open, Tailscale still works, but every connection falls back to relaying through Tailscale’s own DERP servers instead of connecting directly device-to-device … meaning real, measurable extra latency for absolutely no reason, every single time. I found this out by comparing tailscale status output between two machines and noticing one said direct and the other said relay for the exact same peer, at the exact same location. This one line fixed the difference completely.

The suspend/resume fix, and why it’s there

powerManagement.resumeCommands = ''
  ${pkgs.systemd}/bin/systemctl restart tailscaled
'';

Tailscale’s daemon doesn’t reliably reconnect its tunnel on its own after a laptop wakes from sleep … the underlying network interface comes back, but the tailscaled process itself sometimes just sits there with a dead connection until something kicks it. This forces a clean restart of the daemon specifically at resume, so I never wake the machine up to find Tailscale silently disconnected and have to notice and fix it manually.

The MacBook Air, and why it just works too

The genuinely surprising part wasn’t the NixOS desktop or the Fedora server … both are machines I expected to configure carefully. It was installing Tailscale on a 2014 MacBook Air 6,2 with 4GB of RAM and expecting some kind of fight to get it running smoothly. There wasn’t one. Install the client, log in, done … same tailnet, same access to every other machine, no meaningful resource cost on hardware that struggles with plenty of far lighter software.

That’s the actual point of this whole setup for me. It’s not one clever config on one important machine … it’s the same trivial setup, repeated across genuinely different hardware and different operating systems, and every single one of them just becomes another device on the same private network with zero port forwarding on my actual router and zero manual key management on my end.

What I’d actually tell someone setting this up

Don’t skip the firewall interface trust line if you’re on NixOS or anything with a default-deny firewall … that one line is the difference between “Tailscale is installed” and “Tailscale actually lets your other services through.” And check tailscale status on both ends of a connection you care about being fast … if it says relay instead of showing a direct IP, that’s almost always a firewall/UDP port problem, not something wrong with Tailscale itself.