LUNAROPS · OPERATIONAL UPLINK 100% UPTIME 1,247d POSTS 893 JEFF.MOON@LUNAROPS.DEV UTC --:--:--

WireGuard vs OpenVPN vs Tailscale

wireguardopenvpntailscalevpncryptographynat-traversal

The first thing to get straight is that comparing WireGuard, OpenVPN, and Tailscale is a category error as usually framed, because they do not all sit at the same layer. WireGuard and OpenVPN are data-plane protocols — they define how two endpoints encrypt and exchange packets. Tailscale is a control plane that uses WireGuard as its data plane: it does not encrypt your packets with some third protocol, it orchestrates WireGuard tunnels for you, solving the key distribution, NAT traversal, and access control that raw WireGuard leaves entirely to you. So the real comparison is two-and-a-half-way: WireGuard versus OpenVPN as cryptographic protocols, and then Tailscale (or Headscale, or Netbird) as the question of whether you want a coordination service managing WireGuard on your behalf. Almost every “which VPN should I use” argument is muddled because people compare a protocol to a managed product as if they were the same kind of thing.

Once you see that structure, the decisions get clear. The protocol question — WireGuard or OpenVPN — is mostly settled in WireGuard’s favor on performance and auditability, with OpenVPN retaining a few genuine advantages around flexibility and firewall evasion that still matter in specific situations. The control-plane question — raw config or a coordinator like Tailscale — is the one most people actually face, and it is a trade between operational simplicity and depending on (and trusting) a coordination service. This post works through the cryptography, the NAT-traversal mechanics, and the threat models, then gives a decision framework.


The protocols at the cryptographic level

WireGuard and OpenVPN embody opposite design philosophies, and the philosophies explain almost every practical difference.

OpenVPN is cryptographically agile. It runs a TLS handshake (it is essentially TLS-over-a-tunnel) and negotiates from a menu: you pick the cipher (AES-256-GCM, ChaCha20-Poly1305, historically Blowfish), the auth digest, the TLS version, the key exchange. This is the same design as TLS itself, and it carries the same baggage. Agility means OpenVPN can adapt to new ciphers and interoperate widely, but it also means a large configuration surface, a large codebase (OpenVPN links against OpenSSL — hundreds of thousands of lines between them), and the classic agility failure mode: downgrade attacks and misconfiguration. An OpenVPN deployment can be perfectly secure or quietly weak depending on a dozen config directives, and telling which from the outside is hard.

WireGuard takes the opposite stance: no agility at all. There is exactly one key exchange (Curve25519 ECDH via the Noise IK handshake pattern), one cipher (ChaCha20-Poly1305 for data, with Poly1305 for authentication), one hash (BLAKE2s), one KDF (HKDF). You cannot negotiate, downgrade, or misconfigure the crypto because there is nothing to choose. If the chosen primitives are ever broken, WireGuard versions the whole protocol and you upgrade — there is no in-band negotiation to attack. The entire kernel implementation is around 4,000 lines of code, small enough to actually audit, versus OpenVPN’s sprawl. This is the single biggest reason WireGuard won mindshare: the attack surface is a rounding error by comparison, and there are no knobs to get wrong.

HANDSHAKE SHAPE

OpenVPN (TLS-based):
  ClientHello --> negotiate version, cipher suite, TLS params
  Cert exchange / key exchange (RSA or ECDHE)
  TLS established --> control channel --> derive data-channel keys
  [ many round trips, large state machine, cipher menu ]

WireGuard (Noise IK, fixed):
  Initiator -> Responder : handshake initiation (ephemeral + static, Curve25519)
  Responder -> Initiator : handshake response
  [ 1-RTT, no negotiation, both sides know each other's static pubkey a priori ]
  -> transport keys derived, data flows as authenticated ChaCha20-Poly1305

The handshake difference has a security consequence beyond simplicity. WireGuard’s Noise IK pattern requires each peer to already know the other’s static public key before the handshake — there is no certificate authority, no in-band identity presentation. This makes WireGuard silent to unauthenticated scanners: a WireGuard endpoint does not respond at all to a packet that is not a valid handshake from a known key, so a port scan sees nothing. OpenVPN, like any TLS service, will respond to a connection attempt (it has a handshake to begin), which makes it discoverable and gives an attacker something to probe. WireGuard’s “stealth” is a real property that falls directly out of its key model, not an add-on.

Property WireGuard OpenVPN
Design philosophy Fixed crypto, no negotiation Agile, TLS-style negotiation
Key exchange Curve25519 (Noise IK) RSA / ECDHE via TLS
Data cipher ChaCha20-Poly1305 (only) AES-GCM, ChaCha20, others
Codebase size ~4,000 LOC (kernel) OpenSSL + ~100Ks LOC
Config surface Tiny (keys, IPs, endpoints) Large (dozens of directives)
Transport UDP only UDP or TCP
Responds to scanners No (silent) Yes (TLS handshake)
Roaming Built-in (endpoint re-bind) Reconnect/renegotiate
Downgrade attacks Impossible (no negotiation) A real configuration concern

The one place OpenVPN’s flexibility is a genuine advantage is transport. WireGuard is UDP-only, by design and without exception. OpenVPN can run over TCP, and specifically over TCP port 443, where it is very hard to distinguish from ordinary HTTPS. In hostile networks that block UDP or do deep-packet-inspection to kill VPNs — restrictive corporate firewalls, censored national networks — OpenVPN-over-TCP-443 (or OpenVPN wrapped in stunnel/obfsproxy) gets through where WireGuard’s UDP simply cannot. WireGuard’s answer is to be tunneled inside something else (udp2raw, or a separate obfuscation layer), which is exactly the kind of bolt-on the protocol otherwise avoids. If your threat is censorship and DPI, OpenVPN’s agility stops being baggage and becomes the feature.

A second OpenVPN edge: TCP mode gives you reliable, in-order delivery, which matters if you are tunneling a protocol that behaves badly over lossy UDP. The catch is TCP-over-TCP meltdown — running TCP traffic inside a TCP tunnel stacks two congestion-control loops that fight each other under loss, producing catastrophic latency collapse. So OpenVPN-over-TCP is for firewall evasion, not for performance; for throughput you want UDP, where WireGuard’s lean datapath simply wins, often by a wide margin in both throughput and latency.


Why WireGuard’s purity creates an operations problem

WireGuard’s minimalism is a gift to security and a burden to operations, and this burden is the entire reason Tailscale exists. The protocol deliberately does nothing about three things every real deployment needs:

  • Key distribution. Every peer must be configured with every other peer’s public key and allowed IPs. For two endpoints this is trivial. For fifty laptops, phones, and servers in a mesh, it is N-squared manual configuration, and every new device means editing config on every existing peer.
  • NAT traversal and roaming endpoints. WireGuard can follow a roaming peer (when an authenticated packet arrives from a new source address, it updates the endpoint), but it has no mechanism to discover how to reach a peer behind NAT in the first place. Both peers behind NAT with no public endpoint simply cannot connect without help.
  • Access control and identity. WireGuard authorizes by key and by the AllowedIPs list — that is the entire authorization model. There is no concept of users, groups, device posture, expiry, or policy. A key is valid until you manually remove it from every peer.

The minimalism is visible in the config itself. A complete WireGuard peer is a dozen lines, and every public key in the [Peer] blocks has to be hand-placed on every other node:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# /etc/wireguard/wg0.conf  -- one node in a mesh
[Interface]
Address = 10.0.0.2/24
PrivateKey = <this node's private key>
ListenPort = 51820

[Peer]                              # the hub / public-endpoint node
PublicKey = <hub public key>
Endpoint = vpn.example.com:51820    # only this peer has a routable endpoint
AllowedIPs = 10.0.0.0/24
PersistentKeepalive = 25            # hold the NAT mapping open

# bring it up; inspect handshakes and transfer
# wg-quick up wg0
# wg show wg0

That AllowedIPs line is the entire routing and authorization model — it is both the crypto-key-routing table (which keys are allowed which source IPs) and the access policy. There is no expiry, no user, no group. A static WireGuard config like this is perfect for a fixed topology: a handful of servers, a home router with a public endpoint, a site-to-site link. The moment the topology is dynamic — devices that roam, come and go, sit behind CGNAT, and need group-based access — the manual N-squared model collapses, and you either build a coordination layer yourself or adopt one. That coordination layer is the actual product category Tailscale occupies.


Tailscale: a control plane over WireGuard

Tailscale is not a third VPN protocol. Its data plane is WireGuard — the same ChaCha20-Poly1305 tunnels, the same kernel module where available. What Tailscale adds is a coordination server (the control plane) that solves exactly the three things raw WireGuard ignores. Devices authenticate to the coordinator using your existing identity provider (Google, Okta, GitHub via OIDC), the coordinator distributes everyone’s public keys and the current network map to every node, and it brokers NAT traversal. Crucially, the coordinator never sees your traffic or your private keys — those stay on the devices, and the WireGuard tunnels are end-to-end between peers. The coordinator is a key-exchange and policy directory, not a relay for your data (with one exception, DERP, below).

TAILSCALE: DATA PLANE vs CONTROL PLANE

   control plane (sees keys + policy, NOT traffic):
        +-------------------------+
        |  Coordination server    |  <- OIDC login, key directory,
        |  (Tailscale or self-    |     ACL policy, network map push
        |   hosted Headscale)     |
        +-------------------------+
           ^            ^
           | (control)  | (control)
        Laptop        Server          phone
           \            /                |
            \  direct  /   WireGuard     |
             +========+  (data plane)====+
             end-to-end encrypted, peer-to-peer
             coordinator never on this path

The NAT-traversal magic is the part that feels like cheating. Tailscale uses STUN to discover each node’s public ip:port mapping, then performs UDP hole punching: both peers, learning each other’s mappings via the coordinator, fire packets at each other simultaneously so that each side’s NAT sees an “outbound” flow and permits the “reply,” establishing a direct peer-to-peer tunnel even though neither has a public endpoint. When hole punching fails — symmetric NATs that randomize ports, strict firewalls — Tailscale falls back to DERP (Designed Encrypted Relay for Packets), a network of relay servers that forward the still-WireGuard-encrypted packets. DERP can see ciphertext and timing but not plaintext, because the WireGuard keys never leave the endpoints. The result is that a connection always works, degrading from direct-P2P to relayed rather than failing, which is the property raw WireGuard cannot offer on its own.

The honest cost of Tailscale is dependency and trust. Your network’s ability to form new connections depends on the coordination server being up and trustworthy. If Tailscale’s coordinator is unreachable, existing tunnels keep working but new device auth and network-map changes stall. And while the coordinator cannot read your traffic, it can (in principle) push a malicious network map or inject a node — the trust you place in it is real, even if narrow. This is why Headscale, an open-source reimplementation of the coordination server, exists: you get Tailscale’s ergonomics with a coordinator you run and trust yourself, at the cost of operating it. For the full setup mechanics of the managed product, see the Tailscale complete guide and the zero-trust home network walkthrough; the Funnel vs Cloudflare Tunnels comparison covers the public-exposure variant.


Threat models, honestly

The three options fail differently, and matching the failure mode to your actual threat is the whole point.

Raw WireGuard has the smallest cryptographic attack surface and no third-party dependency — you trust only the code (auditable) and your own key management. Its weaknesses are operational: keys do not expire, there is no revocation beyond manually deleting them everywhere, and a compromised device’s key stays valid until you notice and remove it from every peer. There is no central log of who connected. For a small, static, high-trust topology this is a feature (no one to trust but yourself); for a fleet it is a liability (no lifecycle management).

OpenVPN has a larger attack surface (OpenSSL CVEs, the config-misconfiguration risk) but a richer security model: it has real PKI with certificate revocation lists, per-user certificates, and TLS-auth/tls-crypt to authenticate the control channel against scanning and DoS. A mature OpenVPN deployment with proper PKI has lifecycle management WireGuard lacks natively. The price is complexity and the standing risk that one of those many directives is wrong.

Tailscale shifts the threat model to identity and the coordinator. Authorization is tied to your IdP, so you get SSO, group-based ACLs, device expiry, and an audit log — genuinely better lifecycle management than either protocol alone. But you have added the coordinator to your trust base and your dependency graph. The relevant questions become: do you trust the coordination service (or run Headscale), and what happens to your access if it is unavailable or compromised? For most organizations the IdP-integrated access control is worth the dependency; for an air-gapped or maximally-paranoid setup it is exactly the wrong trade.

ATTACK SURFACE vs OPERATIONAL CAPABILITY

  small surface, manual ops          large surface / external dep, rich ops
  <----------------------------------------------------------------------->
  raw WireGuard        OpenVPN+PKI          Tailscale (managed)
  - 4k LOC             - revocable certs    - SSO + group ACLs
  - no lifecycle       - per-user identity  - device expiry + audit log
  - you trust only     - you trust your     - you trust the coordinator
    your own keys        PKI + OpenSSL        (or run Headscale)

The decision framework

Strip away the tribalism and the choice falls out of two questions: is your topology static or dynamic, and what is your real threat.

  • Two fixed endpoints with at least one public IP (site-to-site, server-to-server, home router to VPS): raw WireGuard. It is the fastest, leanest, most auditable option, and the manual config is trivial at this size. Reach for the WireGuard from scratch setup. Adding a coordinator here is pure overhead.
  • A fleet of roaming devices, users, and group-based access (a team, a homelab with phones and laptops behind CGNAT, anything needing SSO): Tailscale, or Headscale if you want to own the coordinator. The NAT traversal and identity-based ACLs are the entire value, and rebuilding them by hand is a project you do not want. This is where most people actually are.
  • You must traverse a hostile, DPI-heavy, or UDP-blocking network (censorship, restrictive corporate firewall): OpenVPN over TCP 443, possibly obfuscated. This is the one scenario where OpenVPN’s agility is decisively better, because WireGuard’s UDP-only purity is a liability you cannot configure around without bolting on a tunnel.
  • Maximum auditability and zero external dependencies (air-gapped, high-assurance, regulatory): raw WireGuard with disciplined manual key management, or OpenVPN with a self-run PKI if you need certificate revocation and per-user identity. The common thread is no coordinator in your trust base.

The pattern across all four: WireGuard is the best protocol and the right default for static topologies; Tailscale/Headscale is the right system for dynamic fleets because it solves WireGuard’s operational gaps without replacing its crypto; OpenVPN survives specifically where transport flexibility and mature PKI matter more than lean performance. They are not really competitors so much as answers to different questions, and most “which is best” debates are just people who have different topologies talking past each other. For the broader access-control picture these all plug into, the zero-trust networking post covers the policy layer that sits above any of them.


Verdict

WireGuard won the protocol argument: fixed, auditable crypto in 4,000 lines, no negotiation to downgrade, silent to scanners, and faster than OpenVPN on UDP — use it as your default data plane and stop agonizing. OpenVPN is not obsolete; its TLS agility, TCP-443 transport, and mature certificate PKI are genuinely better in exactly two situations — traversing networks that block or inspect UDP, and deployments that need per-user certificate revocation more than they need lean performance. Tailscale is not a third protocol to weigh against those two; it is WireGuard’s missing control plane, solving key distribution, NAT traversal via hole punching with DERP fallback, and identity-based access control, at the cost of trusting (or self-hosting, via Headscale) a coordination server. So the real decision is two steps: pick WireGuard unless you specifically need OpenVPN’s firewall evasion or PKI, then decide whether your topology is static enough to manage WireGuard by hand or dynamic enough to want a coordinator doing it for you. Match the tool to the topology and the threat, not to the benchmark everyone quotes.


Sources

Comments