Tailscale alternatives for your own servers

By

Tailscale alternatives for a VPS: November 2026 prices, the SSH fixes, and when WireGuard, Headscale, or Cloudflare Access fits.

Tailscale puts your laptop and a VPS on one private network, without you running a VPN server. That part is real, and it is why people reach for it after a break-in.

It is also a hosted coordination service. The machine that introduces your nodes is one Tailscale runs. WireGuard carries the packets. You do not operate that introduction unless you replace it.

On 2 November 2026, Philipp Keller described a lockdown after his server was compromised. Cloudflare’s WAF sits in front. SSH is reachable only over Tailscale. He added a daily npm audit and a weekly AI audit.

The replies are the useful part. One calls Tailscale a layer on WireGuard and says to run WireGuard yourself. Another says OpenSSH with public keys has been hardened for years, and that Tailscale moves you onto a coordination server you do not control. A third says Tailscale was hacked recently and should be patched. A fourth says to turn on Tailnet Lock, leave Tailscale SSH off, use ordinary OpenSSH inside the tailnet, and rotate a leaked auth key. A fifth says Docker published ports skip ufw, so a database can stay open on the public IP after SSH has moved.

This post checks those claims against Tailscale’s own pages, as of November 2026. The install walkthrough for a closed public firewall is how to secure a VPS with Tailscale and Cloudflare Tunnel. I will not repeat it. The Tailscale course is the longer lesson path, and the VPN course builds plain WireGuard and a Cloudflare private network.

What Tailscale gets right

Tailscale’s client makes a WireGuard tunnel between two machines that may both sit behind NAT. Tailscale’s coordination-server page says the client tries a direct connection, and falls back to a DERP relay when the networks will not allow one. A firewall that blocks unsolicited inbound traffic can still work, because your node dials out.

That is the fair answer to “it is only WireGuard.” The data plane is WireGuard. The product is the part WireGuard does not include: login, IP addresses, names, access rules, and NAT traversal. If you enjoy exchanging keys by hand, you do not need that product. If you want a new VPS on the network before lunch, you do.

Access rules decide which node may talk to which port. The VPS guide uses grants for that, and the course spends a module on them. MagicDNS, listed on the pricing page, gives the nodes names so you are not pasting 100. addresses into every command.

Setup is the other half of the pitch. You install a client, sign in, and the node appears. Headscale and raw WireGuard both ask you to operate more of that yourself.

The free plan and the login

There is no separate password for a tailnet. You sign in with an identity provider.

Tailscale’s pricing page, read in November 2026, says a tailnet created with a public email domain such as Gmail, Apple, or a personal GitHub account is personal use. Those tailnets land on the free Personal plan. A custom domain is treated as business use and starts a 14-day Enterprise trial.

Personal is free for non-commercial use, and the page says that free tier stays free. The limits listed there:

Personal planLimit
Price$0
UsersUp to 6
User devicesUnlimited
ACL groupsUp to 3
Tagged resources50 to start. The comparison table lists $1 per month for each extra one
Ephemeral resources1,000 minutes per month

A homelab or a single-person side project fits. A company tailnet on a custom domain does not stay on that free plan. After the 14-day trial, existing users and devices keep working if you have not picked a plan. New users, new devices, and new auth keys are blocked until you do.

Paid self-serve prices on the same page:

  • Standard is $8 per user per month. Unlimited users, up to 10 ACL groups, 1,000 ephemeral minutes.
  • Premium is $18 per user per month. Up to 300 ACL groups, 10,000 ephemeral minutes, and the logging and routing features listed under that plan.
  • Enterprise is custom.

The second factor sits at the identity provider, because that is the login. Turn it on there before the tailnet matters.

Open source projects can also ask for the Community on GitHub plan. Tailscale’s open source page says any OSI-licensed project can use it, and that the plan currently requires GitHub for authentication.

Who you trust

The coordination server distributes public keys and firewall rules. It does not carry your traffic. Devices keep keys locally and cache the rules. If that server is down, existing peers can still talk until a key expires. You cannot add a user or a device, refresh keys, change rules, or revoke a key while it is down.

DERP servers do two jobs. They help two nodes find each other, and they relay WireGuard packets when a direct path fails. Tailscale says private keys never leave the device that generated them, so a DERP server cannot decrypt what it forwards. Clients cache the DERP map, which is why relays can still work while coordination is down. Tailscale also documents peer relays: another node in your tailnet can relay, if you set that up, before traffic falls back to DERP.

Without Tailnet Lock, you trust the coordination server to tell the truth about who is on the network. Tailscale’s Tailnet Lock page states the failure plainly. A malicious or compromised coordination server could insert a node, and that node could then talk to yours. Tailnet Lock makes a new node key useless until a trusted node in your tailnet signs it. Signing keys are checked on your nodes. The white paper says those signing keys are not stored by the control plane.

The split between open and closed source is on Tailscale’s open source page and in the tailscale/tailscale repo. The tailscaled daemon, the CLI, and the DERP server code are open. The LICENSE file in that repo is BSD 3-Clause. The Linux and Android clients, including the GUI, are open. The Windows and macOS GUIs are not. The hosted coordination server is closed.

Headscale is an independent implementation of that control server. Its LICENSE is also BSD 3-Clause. Tailscale employs the maintainer and says it does not set Headscale’s direction. Headscale’s own README aims at one tailnet, for a person or a small group that will run the server. It is not a Tailscale support contract.

Outages are control-plane outages, which matches the design. On Tailscale’s status page:

  • 16 July 2026: degraded coordination service, elevated errors, then a fix.
  • 19 August 2026: partial outage of the coordination service and the admin console, elevated errors, resolved the same evening.
  • 20 October 2025: control-plane outage. Login, device auth, and changes such as ACLs failed for a subset of customers. The status update says device-to-device traffic for peers that were already connected generally continued, and it says not to remove machines you might not be able to reauthenticate.

Tailscale’s own write-up of shaky uptime says each tailnet sits on one coordination server at a time, and that existing connections keep working when that server is down. Changing the network is what stops.

The security record, as of November 2026

I could not find a Tailscale bulletin, or an official incident report, that says Tailscale the company was breached.

What is documented, and recent, is a set of bugs in Tailscale SSH and Tailscale Serve. Tailscale’s 28 October 2026 post says a researcher published a report that weekend, Tailscale had the report on 24 October, and the fixes shipped in Tailscale 1.104.4. The SSH issues need a peer that is already allowed to connect. They are not a stranger on the internet opening SSH with no account. TS-2026-016 also covers a local user who can write a Serve config.

The four bulletins, all on tailscale.com/security-bulletins:

BulletinWhat Tailscale saysFixed in
TS-2026-014Tailscale SSH forwarded Unix sockets as root, so an authorized peer could reach root-only sockets such as the Docker socket or the local API1.104.4
TS-2026-015An authenticated Tailscale SSH session could grow tailscaled memory without a bound, including after disconnect1.104.4
TS-2026-016tailscale serve could dial privileged Unix sockets, including the local API1.104.4
TS-2026-017With Serve TLS, HTTP/2 could attach one mount’s capability header to another mount’s request1.104.4

If you use Tailscale SSH or Serve, upgrade to 1.104.4 or newer. For TS-2026-014, Tailscale also documents TS_SSH_DISABLE_FORWARDING=1 on the tailscaled service as a mitigation that turns forwarding off without turning Tailscale SSH off.

Two nearby items are easy to mix up with “Tailscale was hacked.”

TS-2026-013 is about eight eMudhra TLS intermediate certificates that were compromised. An attacker could mint certificates for domains they do not own, on machines that still trust those intermediates. Tailscale 1.104.2 or later distrusts them. The bulletin says ordinary tailnet traffic is unaffected, because WireGuard between nodes does not use that public certificate store.

The Hugging Face intrusion, written up by Tailscale on 31 July 2026, used a stolen reusable Tailscale auth key. An agent enrolled 181 nodes. Tailscale says no Tailscale vulnerability was found or exploited. The key was in a secret store the attacker could already read.

The public GitHub Security Advisories for tailscale/tailscale, checked the same day, list three older issues and not these 2026 bulletins: GHSA-vqp6-rc3h-83cp (2022, Windows daemon RCE), GHSA-qccm-wmcq-pwr6 (2022, information disclosure), and GHSA-vfgq-g5x8-g595 (2023, FreeBSD Tailscale SSH group id). The 2026 record that Tailscale is maintaining is the bulletin page, not that advisory list.

Older bulletins are still on the index. One matters if you rely on Tailnet Lock. TS-2025-008 (19 November 2025) says nodes without --statedir or TS_STATE_DIR failed to enforce Tailnet Lock signatures. It was fixed in 1.90.8. A current client is part of turning the feature on.

If you keep Tailscale, harden it

The VPS guide already leaves Tailscale SSH off. The October bulletins are the reason to keep that choice.

Tailscale SSH is a second SSH server inside tailscaled. This advertises it:

tailscale set --ssh

tailscale up --ssh does the same thing. Tailscale says that command makes tailscaled intercept tailnet traffic to port 22 on the Tailscale address, and that existing SSH sessions to that address hang when you turn it on. Your OpenSSH sshd and authorized_keys then stop being the thing a tailnet peer hits on port 22.

Leave the flag off. SSH to the tailnet address with normal OpenSSH, after you have keys working. The SSH course covers host keys, passphrases, and rotation. Test that login before you close the public port. The CVE-2026-98432 post is why a public TCP port is a bad place to leave sshd on an unpatched kernel.

Tailnet Lock is the control-plane check. In the admin console, Tailscale builds a tailscale lock init command. You run that on a signing node. It prints ten disablement secrets. One secret is enough to turn the feature off later:

tailscale lock disable <disablement-secret>

Store a secret somewhere that is not the VPS. After init, check every node:

tailscale lock status

The trusted signing keys should match. A new node does not become a peer until a signing node runs the tailscale lock sign command the admin console prints. A leaked auth key, on its own, does not add a node the others will accept.

A pre-signed auth key is different. Tailscale’s lock docs say you can run tailscale lock sign on a key, and that signed key can enroll devices without a second approval. Treat a pre-signed key like a signing credential.

Auth keys are on the auth keys page. A one-off key enrolls one device. A reusable key enrolls many. Tailscale’s warning is that a stolen reusable key is dangerous, and that it belongs in a secrets store. Keys expire on a timer you set, from 1 to 90 days, and the default is 90. When the auth key expires, a device it already enrolled stays until the node key expires. Node keys last 180 days by default, and you can change that under Device management.

Register a server with the key, and do not add --ssh:

sudo tailscale up --auth-key=tskey-abcdef1432341818

That value is Tailscale’s example. Use the key you just generated. Prefer a one-off key for a single VPS. Do not leave a reusable key in a repo, or in a prompt an agent can read. The Hugging Face write-up is that failure. Ephemeral keys are the documented fit for CI jobs and other short-lived workloads, because Tailscale removes the node when it goes idle.

Device approval is on every plan, from the device approval docs. A new device cannot pass traffic until an Owner, Admin, or IT admin approves it. A pre-approved auth key skips that review. Use pre-approval only for machines you are provisioning on purpose, not for a key that sits in a laptop shell history.

Access rules still matter after the node is in. A tailnet that allows every device to every port is a flat LAN. The VPS guide’s grant is the narrow version: your user, SSH, that one tagged server.

Docker ports and ufw

Moving SSH onto the tailnet does not close a port Docker published.

Docker’s firewall page says published container traffic is handled in the nat table, so it is diverted before ufw’s INPUT and OUTPUT chains. ufw can say “deny incoming” and the published port still answers on the public address. The same warning is on the Ubuntu install page.

Port publishing says a published port is reachable from outside the host unless you bind a specific address. This is Docker’s own example. Only the host can open it:

docker run -p 127.0.0.1:8080:80 -p '[::1]:8080:80' nginx

The same flag takes a Tailscale address instead of 127.0.0.1, if a tailnet peer should reach that container and the public internet should not. Docker also says that in releases older than 28.0.0, other machines on the same L2 network could still reach a port published only on localhost. Read that note if the daemon is old.

Then look from a machine that is not on the tailnet. The CVE post uses this scan, with the documentation address standing in for your VPS:

nmap -Pn -sT -p- 203.0.113.10

-sT is a TCP connect scan. -p- is every TCP port. -Pn skips the ping, which a firewall often drops. You want no open port. filtered means the probe was dropped or rejected. On the server, ss -tlnp shows what is listening. The scan shows what the internet can reach. A provider firewall in front of the VM still matters, because a host firewall does not see every packet Docker already redirected.

Tailscale’s own packet filter is a separate question. In the default netfilter mode it accepts allowed tailnet traffic before ordinary ufw input rules. The VPS guide links the netfilter docs and tells you not to treat a ufw SSH rule as the tailnet policy.

The other choices

Pick a path to a private serverVisitors use Cloudflare Tunnel. Your own machines can use Tailscale, Headscale, or plain WireGuard. A team can use a paid mesh, Teleport for SSH, or Cloudflare Access for one site.VisitorsOnly your machinesNoYesA teamThe whole networkSSH and clustersOne hostnameWho connects?Cloudflare TunnelRun the controlserver?TailscaleHeadscale orWireGuardWhat do they reach?Tailscale or NetBirdTeleportCloudflare Access

Prices below are from each vendor’s site in November 2026. They will move. The “run it” column is the license I could read on the project page, plus who operates the control plane.

OptionRun itPrice in November 2026Pick it when
TailscaleOpen client (BSD 3-Clause). Closed coordination server. HostedPersonal $0, non-commercial, 6 users. Standard $8 per user per month. Premium $18You want the network this week and you accept Tailscale’s control plane
HeadscaleBSD 3-Clause. You host one tailnetNo license feeYou want Tailscale’s clients and your own coordination server
NetBirdBSD 3-Clause, except management/, signal/, relay/, and combined/, which are AGPL-3.0. Hosted plans, code you can run€0 for 5 users and 100 machines. Team €6 per user per month. Business €12. Extra machines €0.50You want a WireGuard mesh, SSO on the free tier, and prices in euros
ZeroTierMost of the repo is MPL. nonfree/ is source-available. Hosted controller. Enterprise lists self-hostedPersonal free, non-commercial, 10 devices. Essential $18 per month, then $2 per extra device. Scale $179 per month, then $1.80You count devices, not seats, and you do not need WireGuard specifically
NetmakerPricing page calls Community Apache 2.0 and free to self-host. GitHub’s license field was not a standard SPDX idBusiness is listed at $4 per active connection per month. An older table on the same page still shows Professional at $99 per monthYou already run WireGuard and want a controller, and you re-read the pricing page before paying
NebulaMIT, from Slack. You run lighthouses and the certificate authorityNo license feeYou will operate the overlay yourself and you do not want a per-user bill
WireGuardKernel code is GPLv2. You run both peersNo license feeTwo or three machines, and you will exchange keys yourself
Cloudflare Tunnel and AccessHosted. cloudflared on your machineThe tunnel guide treats named tunnels as free on every Cloudflare plan. Access plans: $0 up to 50 users, then $7 per user per monthStrangers need the website, or staff need one hostname behind a login
TwingateHosted client and relays. I did not find an open-source controller on the pricing pageStarter $0 up to 5 users. Home $15 per month, non-commercial, up to 7 users. Teams $5 per user per month. Business $10. Yearly billing is listed at 15% lessPeople should reach named resources, not a full mesh of every port
TeleportAGPL-3.0 repo. Cloud or self-hosted. The pricing page has no public numberNo self-serve price listedYou want SSO, audit, and session recording for SSH, Kubernetes, and databases
OpenSSHShips with the system. The portable man page is the upstream referenceNo license feeThe listener is already on a private path, or you accept a public port and lock the config down
knockdGPL-2. You run it on the serverNo license feeYou want the public SSH port closed until a packet sequence arrives, and you still require keys

Headscale

Use Headscale when the objection is the hosted coordination server, and you still want Tailscale’s clients. You patch it, you back it up, and a dead Headscale process has the same shape as a dead Tailscale coordination server: existing tunnels can continue, new enrollment stops. Tailscale’s page is explicit that this is a community project with a narrower scope than the hosted product.

NetBird

NetBird’s pricing is in euros. The free plan includes peer-to-peer connections, access controls, private DNS, network routes, and NetBird SSH, for up to 5 users and 100 machines. Team adds enterprise SSO, SCIM, and audit events at €6 per user per month. Business adds device approval and posture checks at €12. You are billed for users and machines that connected at least once in the period.

The repo license is not one license. Most of it is BSD 3-Clause. The management, signal, relay, and combined directories are AGPL-3.0. Read that split before you embed it in a product you ship.

ZeroTier

ZeroTier’s pricing is per device. Personal is free for non-commercial use, with 10 devices on one network. Essential is $18 per month for a commercial license, 10 devices included, then $2 each, with OIDC. Scale is $179 per month, 100 devices included, then $1.80. Enterprise is the plan that lists self-hosted and air-gapped deployments.

The client repo is not “all open, one license.” The LICENSE file points most of the tree at the MPL and the nonfree/ tree at a source-available license. It is a different protocol from WireGuard. Pick it for the device math, not as a drop-in Tailscale clone.

Netmaker

Netmaker’s pricing page does not present one clean number. The current blocks call the Community edition open source, Apache 2.0, free, and self-hosted, and they list Business at $4 per active connection per month. Further down, an older SaaS table still shows a free Community tier of 3 users and 10 nodes, and Professional at $99 per month. I am not going to pretend those are the same offer. Open the page on the day you pay.

The GitHub repo describes itself as making networks with WireGuard. The license metadata on the repo was NOASSERTION when I checked, so the Apache 2.0 claim I am willing to repeat is the one the pricing page prints.

Nebula

Nebula is a MIT-licensed overlay from Slack. You create a certificate authority, you run lighthouse nodes so others can find each other, and groups in the config decide who can talk. There is no per-seat fee because there is no hosted plan in the project itself. The cost is operation. Pick it when you want that, and when a WireGuard control plane is not the goal.

Plain WireGuard

WireGuard’s site says the kernel components are GPLv2. A tunnel is a key pair and an endpoint. This is the official key generation:

umask 077
wg genkey | tee privatekey | wg pubkey > publickey

wg-quick is the tool that brings an interface up and down from a config file, instead of you calling ip and wg by hand. The quick start shows the manual form, including a peer endpoint. For a machine behind NAT that must accept connections after traffic has gone quiet, the same page says to set PersistentKeepalive to 25 seconds. The default is off.

There is no identity provider, no shared ACL file, and no relay network unless you build one. Two peers are a good fit. Ten laptops that change Wi-Fi networks all week are a worse fit. The VPN course builds a small WireGuard setup and then a Cloudflare private network, which is the right next step if this paragraph is the first time you have configured wg.

Cloudflare Tunnel and Access

A public website does not need a mesh. Cloudflare Tunnel is cloudflared dialing out, and visitors hitting your hostname. Quick tunnels are the temporary trycloudflare.com URL, for an afternoon, not for SSH you depend on.

Cloudflare Access, on the Zero Trust pricing page in November 2026, is $0 for up to 50 users and $7 per user per month after that. Contract pricing is custom. Use Access when a person should open one app in a browser, or SSH through the tunnel, after an identity check. Use a mesh when two servers should reach each other on arbitrary ports without a published hostname.

Twingate

Twingate’s pricing is a hosted access product. Starter is free for up to 5 users. Home is $15 per month, non-commercial, up to 7 users. Teams is $5 per user per month, up to 100 users, with Google Workspace SSO. Business is $10 per user per month, up to 500. Yearly billing is 15% less on those paid plans. Connectors sit in your network and dial out. People reach resources you named, which is a different shape from “every device can be a subnet router.”

Teleport

Teleport is an access proxy for SSH, Kubernetes, databases, desktops, and web apps, with audit and session recording. The repo is AGPL-3.0. The pricing page offers cloud and self-hosted and does not list a dollar amount. Pick it when the problem is “who SSHed to production, and what did they type,” not “give these three machines a private LAN.”

OpenSSH, on purpose

OpenSSH is the baseline under every option above. From the sshd_config man page in OpenSSH portable, as of November 2026:

  • PasswordAuthentication defaults to yes.
  • KbdInteractiveAuthentication defaults to yes.
  • PermitRootLogin defaults to prohibit-password, so root can still use a key.
  • PubkeyAuthentication defaults to yes.

A distro package can ship different values. Set the ones you mean, and prove a key login in a second session before you reload:

PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin no

That is keys only, and no root login. SSH for developers is the client side: ssh-keygen, authorized_keys, and ~/.ssh/config. Securing a server using AI is one pass where an agent applied a firewall and SSH lockdown on a fresh Ubuntu box and explained the diff.

fail2ban is GPL-2. It watches logs and bans addresses that fail login too often. Its README says this lowers the rate of bad attempts and does not replace strong authentication. It is optional, and it is useless against a stolen key.

If the public port has to exist for a few minutes, Firewall Manager opens SSH for your current IP and closes it on a timer. That is a smaller change than a mesh, and it still leaves sshd on a public address while the timer runs.

Port knocking

knockd is a GPL-2 port-knock daemon. The README’s example is a closed firewall, a sequence of TCP SYN packets to high ports, then an iptables rule that opens port 22 to that client. A second sequence closes it. The knocks do not need an open port, because knockd watches the raw interface with libpcap.

The sequence is a shared secret written in packets. Anyone who can see those packets can replay the idea of the sequence. It does not check a user key. NAT and a host that only sees part of the traffic make it brittle. I would use it only as a way to keep sshd from answering the whole internet, and I would still require keys the moment the port opens. Once SSH is on a tailnet, or behind Cloudflare Access, the public port is already gone and knockd has nothing to hide.

Which one I would pick

I have not finished moving a production VPS onto a tailnet. The VPS guide says the same thing. It is the walkthrough I would follow, and it was written from the vendor docs.

For a machine that also serves a public site, I would keep the split that guide uses. Visitors come through Cloudflare Tunnel. I would SSH with OpenSSH over the tailnet, leave Tailscale SSH off, and turn Tailnet Lock on before the server holds anything I care about. Auth keys for build machines would be ephemeral, or one-off, and not a reusable key in a file an agent can read.

Where to host is the earlier question, if you are still choosing the machine.

I would leave Tailscale when I did not want their coordination server in the loop. Headscale if I still wanted the Tailscale clients. Plain WireGuard if there were two peers and I was willing to handle NAT with a keepalive. Nebula if I wanted certificates and lighthouses instead. Teleport if the real need was an audit log of SSH, not a LAN. Cloudflare Access if the real need was one hostname and a login.

If the server was compromised the way Philipp described, I would patch first, including Tailscale 1.104.4 or newer on any node where Tailscale SSH or Serve was enabled. Then I would close the public ports, and I would assume a reusable auth key that ever lived on that machine is burned.

Tagged: Security · All topics

Want me to talk about your product? You can sponsor this site.

Related posts about security: