TL;DR:

  • Tailscale builds a private overlay mesh network using WireGuard, with device authentication handled via your existing identity provider — no certificate management, no firewall hole-punching required
  • Subnet routing lets a single Tailscale node act as a gateway for an entire local network of IoT devices that don’t run Tailscale themselves — useful for Modbus, BACnet, and other device-local protocols
  • The tsnet library embeds Tailscale directly into Go applications, so edge software can join the mesh without a separate VPN client installation

Getting secure remote access to distributed edge hardware is one of the more tedious operational problems in IoT deployments. The devices live in varied network environments — factory floors, remote agricultural sites, commercial buildings — often behind NAT, firewalls you don’t control, or cellular gateways. Traditional VPN approaches require either public static IPs on each site, an inbound port, or a hub-and-spoke server that becomes a bottleneck and single point of failure.

Tailscale solves this cleanly. It creates a peer-to-peer WireGuard mesh where every device connects to every other device directly — not through a central server — using DERP relay servers only as a fallback when direct connection isn’t possible. Device authentication is tied to your SSO identity provider. There’s no certificate infrastructure to manage. And the NAT traversal works reliably enough that it’s a viable solution for most real-world network environments.

How Tailscale Works

Every device running Tailscale gets a stable IP address in the 100.x.y.z range (the Tailscale network uses the CGNAT range). These addresses are persistent — the same device always gets the same Tailscale IP regardless of which physical network it’s on or whether its external IP has changed. This makes them reliable for service discovery in distributed systems.

The control plane (Tailscale’s coordination server) handles device authentication, key distribution, and network policy. The data plane is pure WireGuard — encrypted peer-to-peer tunnels between devices. If two devices can reach each other directly (same local network, or both with accessible public IPs), they connect directly. If not, the DERP relay servers provide fallback connectivity.

For IoT deployments, the relevant modes are:

Standard node: A device runs the Tailscale client and joins your tailnet. Works on Linux (Raspberry Pi, industrial Linux gateways, Debian-based edge devices), macOS, Windows, iOS, and Android. This is the simplest option when you control the device OS.

Subnet router: A single Tailscale node advertises routes to a local subnet, making the devices on that subnet reachable from anywhere in the tailnet. If your edge gateway runs Tailscale and your industrial sensors are on a local 192.168.100.0/24 network, the gateway can route traffic to those sensors from anywhere. The sensors don’t run Tailscale — they’re unreachable from the internet but accessible through the gateway from your tailnet.

Exit node: Any device can be configured as an exit node, routing traffic from other tailnet devices through its internet connection. Useful for devices that need consistent egress IP addresses (webhook endpoints, regulatory compliance).

Subnet Routing for Industrial IoT

The subnet routing mode is particularly valuable for industrial environments. Consider a typical factory setup:

  • An edge gateway runs Linux (Raspberry Pi 4 or industrial PC)
  • The gateway connects to PLC, sensors, and HMI devices on a local Ethernet network
  • The PLCs and sensors use Modbus TCP, BACnet/IP, or OPC-UA — they’re not running Tailscale, and you don’t want to change their network configuration

You install Tailscale on the gateway and enable subnet routing:

tailscale up --advertise-routes=192.168.1.0/24

From the Tailscale admin console, you approve the subnet route. Now any device in your tailnet can reach the PLCs and sensors directly via their local IP addresses — from your engineering workstation, your SCADA server, your monitoring platform — without any additional firewall configuration or VPN setup on the factory floor.

This is significantly less disruptive than reconfiguring industrial networks, which often have change management constraints and legacy devices that can’t be touched. The gateway does all the work, and the field devices never know the difference.

The tsnet Library: Embedding Tailscale in Go Applications

For edge software you’re building yourself, the tsnet library lets you embed Tailscale directly into your Go application. The application joins the tailnet as a device without requiring the Tailscale client to be installed on the host OS.

import "tailscale.com/tsnet"

func main() {
    srv := &tsnet.Server{
        Hostname: "edge-sensor-gateway",
        AuthKey:  os.Getenv("TS_AUTHKEY"),
    }
    defer srv.Close()

    ln, err := srv.Listen("tcp", ":8080")
    if err != nil {
        log.Fatal(err)
    }
    // ln is a net.Listener that only accepts connections from your tailnet
    http.Serve(ln, yourHandler)
}

The listening port is only accessible from within your tailnet — it doesn’t listen on the host’s public interfaces at all. This is a significant security improvement over binding to 0.0.0.0 and relying on firewall rules. It’s also much simpler to reason about: the service is only reachable from authorised tailnet members.

This pattern is useful for edge applications that serve dashboards, expose local APIs for monitoring, or need to accept control commands — things you want reachable from your management plane but not from the internet.

ACLs and Device Access Policy

Tailscale’s access control lists (ACLs) let you define which devices can communicate with which. For IoT deployments, this lets you enforce separation even within your tailnet: production sensors don’t need to talk to development workstations, and vice versa.

{
  "acls": [
    {
      "action": "accept",
      "src": ["tag:ops"],
      "dst": ["tag:edge-gateway:*"]
    },
    {
      "action": "accept",
      "src": ["tag:monitoring"],
      "dst": ["tag:edge-sensor:8080"]
    }
  ]
}

Device tags are set at provisioning time and managed through the admin console or via the Tailscale API. Combined with Auth Keys (reusable, pre-authorised keys for automated device provisioning), tags make it practical to onboard a fleet of edge devices with consistent policy applied automatically.

Tailscale vs Raw WireGuard

The comparison comes up often. Raw WireGuard is faster (no overhead from Tailscale’s coordination layer), has no third-party dependency, and is entirely self-hostable. If you have strict data sovereignty requirements or want to avoid any dependency on Tailscale’s infrastructure, raw WireGuard with your own coordination layer (Headscale is the open-source Tailscale-compatible control plane) is the right choice.

For most IoT teams, though, Tailscale’s operational simplicity is worth the trade-offs. The biggest operational cost with raw WireGuard is key management at scale: rotating keys, tracking which public key belongs to which device, handling certificate expiry. Tailscale handles all of this, tied to your identity provider. A device is removed from the network by removing its account or device entry in the admin console — immediately, without tracking down and rotating WireGuard keys.

Headscale is worth evaluating if you want Tailscale’s architecture without the dependency on Tailscale’s coordination server. It’s self-hostable, compatible with the Tailscale client, and mature enough for production use.

Pricing and Scale

Tailscale’s free tier supports up to 100 devices, which covers most small-to-medium IoT deployments. The Personal tier is genuinely unlimited for individual use. The Teams tier (required for SSO integration with Okta, Azure AD, Google Workspace) starts at a per-user/per-month cost with devices not counting separately.

For fleets of headless IoT devices, you’re paying per device only on the enterprise tier. Many teams use the free or personal tier for small deployments and move to enterprise once fleet size and SSO requirements justify it.