In short
- A VPN tunnel is a packet inside a packet. Your computer encrypts each IP packet, makes it the payload of a new packet addressed to the VPN server, and the server unwraps it and sends it on.
- WireGuard is a network interface with a list of peers. Each peer is a public key plus the tunnel addresses it may use, and that one list decides where outgoing packets go and which incoming packets are accepted. It runs over UDP only and has been part of Linux since 5.6.
- OpenVPN runs a TLS session to agree keys, usually identifies people by certificates from a certificate authority you run, and can use UDP or TCP. It trades WireGuard's fixed design for choice, and the upkeep that comes with it.
- The wrapping costs at least 60 bytes per WireGuard packet over IPv4 and 80 over IPv6, so the tunnel's MTU must be smaller than the path's. Get it wrong and small things work while large transfers hang.
- Running your own takes one UDP port, IP forwarding, a NAT rule and a key or certificate per person. Prefer UDP: a TCP tunnel can stall badly when packets are lost.
On this page
- A tunnel is a packet inside a packet
- WireGuard: an interface with a list of keys
- OpenVPN: TLS, certificates and a program in user space
- The two designs side by side
- Why a tunnel over TCP can stall
- MTU: why small things work and big transfers hang
- Running your own: one port, forwarding, NAT and a key per person
- What the rules allow, and what passes the filter
- Questions
- Sources
Connect a laptop to a VPN in a café, send all of its traffic through the tunnel, and the café's network loses sight of almost everything you do. It no longer sees which sites you open or which services you talk to. It sees one stream of packets going to one address, and the size and timing of each. Everything else is inside those packets, encrypted.
Your traffic has not vanished, though. It comes out of the VPN server, and whoever runs that server can read it as plainly as the café could before. WireGuard and OpenVPN both work this way, and they differ in almost everything else: how the two ends prove who they are, where the code runs, what the tunnel travels over, and how much there is to configure. When you run your own server, those differences decide what you open and what you hand each person who connects.
A tunnel is a packet inside a packet
Your computer already decides, for every packet it sends, which network interface the packet leaves by: the routing table matches the destination address and picks one. A VPN adds one more interface to that choice. To the rest of the system it looks like a network card, but no cable is attached, and packets routed into it are handed to the VPN software instead. On Linux the classic way to build such an interface is the TUN/TAP driver, which gives a program in user space the packets that would otherwise have gone to physical hardware.1 WireGuard on Linux skips that hand-off: wg0 is an interface type of its own,3 and the encryption happens inside the kernel.7
The VPN software encrypts each packet it receives and makes the result the payload of a brand new packet, with a new header addressed to the VPN server. That step is called encapsulation, and it is the whole trick. WireGuard's own one-line description is that it encapsulates IP packets over UDP.2 The new packet crosses the internet like any other UDP datagram. At the server the steps run backwards: strip the outer headers, decrypt, check, and out comes the original packet, which the server's kernel routes onwards as if it had arrived on a cable.
Three parties see three different things. The networks in between (the café's Wi-Fi, your provider, every router on the way) see only the outer packet: your address, the server's address, a UDP port, a size and a time. The server sees the inner packet in full once it has decrypted it. The website sees a request from the server's address, because the server rewrote the source on the way out, a step covered in running your own.
WireGuard: an interface with a list of keys
WireGuard is deliberately small. You add an interface, by convention wg0, give it your private key and your peers' public keys, and send packets across it. It is an ordinary interface, addressed and routed with the usual ip commands; only the WireGuard settings go through the wg tool. The project says it is meant to be small enough for a single person to review in full.2
A peer's identity is its public key and nothing else: no usernames, no certificates, no certificate authority. Two machines connect by exchanging public keys, much as you would exchange SSH keys, and getting the keys to the right places is up to you, since key distribution is explicitly outside WireGuard's scope.2 A key pair takes two commands, wg genkey and wg pubkey.3
Cryptokey routing: one list that routes and filters
Each peer also has a list of allowed IPs: the tunnel addresses it may use. WireGuard calls the idea cryptokey routing, and the one list does two jobs. Sending, WireGuard matches the packet's destination against the peers' allowed IPs, and the peer that matches decides which key encrypts the packet and where it goes. Receiving, a packet that authenticates as a peer must carry an inner source address from that same peer's list, or it is dropped.2
So on a WireGuard server, a packet's inner source address is exactly as trustworthy as the key it arrived under. A firewall rule that lets 10.0.0.4 reach the office network is really a rule about whoever holds the office router's key. A client's list usually runs the other way. Its only peer is the server, with allowed IPs of 0.0.0.0/0, a wildcard that accepts packets from any source the server forwards.2 The wg-quick helper turns allowed IPs into routes, and takes over the default gateway when the list contains the default route.5
Quiet, roaming, and not really stateless
WireGuard presents itself as having no connections to manage and no state to worry about.2 That is true of the interface, not of the protocol. Underneath, a handshake built on the Noise IK pattern agrees session keys, and it repeats every few minutes so the keys keep rotating. The rekey is driven by the clock, not by what earlier packets said, so a lost packet cannot derail it. There is no cipher to choose: the protocol names one set of primitives, ChaCha20 with Poly1305 for encryption, Curve25519 for key exchange and BLAKE2s for hashing.6
A server learns where each client is from the packets themselves. A peer's endpoint follows the source address and port of its latest correctly authenticated packet,4 which is how a phone can move from Wi-Fi to mobile data and keep its tunnel. A packet that does not authenticate gets no reply at all; the protocol page calls the server silent and invisible to anyone without a valid key.6 For a client behind NAT that the server must reach while it is idle, PersistentKeepalive sends an authenticated empty packet at a fixed interval to keep the NAT mapping open. The manual's example is 25 seconds, and the option is off unless you set it.4
WireGuard became part of Linux in version 5.6, released on 29 March 2020.7 Among the costs on its own list of known limitations: it does not run over TCP, and it is not post-quantum secure by default, although an optional pre-shared key adds a layer of protection there.8
OpenVPN: TLS, certificates and a program in user space
OpenVPN is older and broader. It builds its security on TLS and takes much of its cryptography from the OpenSSL library, and it can bridge Ethernet networks as well as route IP, over UDP or TCP, through NAT and proxies.9
Two channels on one port
In TLS mode, a connection carries two channels multiplexed over one TCP or UDP port. The control channel runs a TLS session, and that session agrees the keys for the data channel, which carries your packets. Over UDP, OpenVPN gives the control channel a reliability layer of its own and forwards tunnel data as it is,9 so your packets are never resent by the tunnel. The data cipher is negotiated from a list, by default AES-256-GCM, AES-128-GCM and, where the library has it, ChaCha20-Poly1305.9
Anyone can send packets to the port, and OpenVPN can ignore strangers: --tls-auth signs every control channel packet with a shared key, an "HMAC firewall" in the manual's words that drops badly signed packets unanswered, and --tls-crypt also encrypts them, which hides the certificates. Against denial of service, the manual pairs UDP with either one.9
Certificates and an authority of your own
Each peer in TLS mode should have its own certificate and private key,9 signed by a certificate authority (CA) that both sides trust. For a private VPN that CA is yours; the OpenVPN how-to covers building one, revoking certificates, and adding smart cards or passwords on top.10 The CA brings chores WireGuard does not have. A lost laptop's certificate goes on a revocation list that the server checks, and every client must check that it is talking to the server, most simply with remote-cert-tls server. The manual calls that check an important precaution against an authorised client impersonating the server.9
A program in user space, for now
Classic OpenVPN is an ordinary program. It reads packets from a tun device, encrypts them itself and writes the result to a normal socket, so every packet leaves the kernel for the openvpn process and comes back. A tun device carries IP packets (layer 3); a tap device carries whole Ethernet frames (layer 2), for bridging networks together.9
That round trip is shrinking. OpenVPN 2.6 uses data channel offload (DCO) when the configuration and the kernel allow it, which needs AEAD ciphers and the separate ovpn-dco kernel module.9 Linux 6.16, released on 27 July 2025, merged OpenVPN data channel offload into the kernel itself,11 as a reworked module called ovpn whose interface only OpenVPN 2.7 supports.12 Either way, the data channel is what moves. The TLS control channel stays in the program.
For transport, --proto takes udp, tcp-client or tcp-server, and the default port, 1194, is OpenVPN's official IANA assignment. The manual treats UDP as the normal case and TCP as the fallback when UDP is blocked.9
The two designs side by side
| WireGuard | OpenVPN | |
|---|---|---|
| Runs over | UDP only | UDP or TCP |
| A peer is identified by | Its public key | A certificate from your CA, optionally with a username and password |
| Cryptography | One fixed set, nothing to choose | Negotiated from a list you can change |
| Where packets are encrypted | In the kernel, on Linux | In the openvpn process, or in the kernel with DCO |
| Carries | IP packets | IP packets (tun) or Ethernet frames (tap) |
| Replies to a stranger | Never | Yes, unless tls-auth or tls-crypt is on |
| Adding a person | A key pair and one [Peer] block | A certificate signed by your CA |
| Removing a person | Delete their [Peer] block | Revoke the certificate in the list the server checks |
| Port | Whatever you set; the examples use 51820 | 1194 by default |
Which one to run
If you control every device that will connect, and UDP gets through the networks they use, WireGuard is the shorter path: one port, one key pair per device, nothing to renew. Choose OpenVPN when you need something only it does: a TCP tunnel, username and password logins, certificates from an authority you already run, smart cards, or layer 2 bridging with tap.
Speed is deliberately not among those reasons. It depends on the processor, the cipher, the kernel and whether DCO is on, so if throughput matters, measure both on the machine you will use.
Why a tunnel over TCP can stall
TCP guarantees delivery by resending whatever was not acknowledged, and each timeout makes the next one longer, exponentially, up to several minutes in a bad patch.13 On a real network that patience is right. In a tunnel that itself runs over TCP it goes wrong, because two TCP connections are now trying to recover from the same loss.
Olaf Titz described the failure in 2001. The outer connection, the tunnel, may be carrying slow timers left over from an earlier bad patch. When it loses a packet, it queues a resend and backs off, and the whole tunnel waits. The inner connection, your download, gets no acknowledgement in time and queues a resend of its own. Its timer is still shorter than the outer one, so it piles up resends faster than the outer layer can carry them, and every one makes the backlog worse: what Titz calls an internal meltdown. None of those inner resends were needed, since the outer layer was going to deliver the original anyway.13
A second cost follows from TCP delivering bytes in order. A TCP tunnel is one ordered stream, so a single lost outer segment holds back every packet queued behind it, from every connection inside the tunnel. A voice call or a game, which would rather lose one packet than wait for it, waits with everything else. That is reasoning, not a measurement, but both projects reach the same conclusion.
WireGuard refuses TCP outright, pointing to the "classically terrible network performance" of tunnelling TCP over TCP.8 OpenVPN supports it, but its manual expects TCP to do somewhat worse than UDP whenever the network is lossy or congested.9 So use UDP, and keep TCP for networks that let nothing else through.
MTU: why small things work and big transfers hang
Every link has a maximum transmission unit (MTU): the largest packet it carries in one piece. On Ethernet the largest IP datagram is 1,500 bytes.14 A tunnel packet has to fit inside that limit together with its wrapping, so the tunnel interface needs a smaller MTU than the path it runs over.
Worked example: one packet through WireGuard
Take the packet drawn at the top of the page. A laptop with the tunnel address 10.0.0.2 sends a 1,200-byte IPv4 packet to a website: a 20-byte IP header, a 20-byte TCP header and 1,160 bytes of data. WireGuard turns it into a data message with a 16-byte header (a one-byte message type, three reserved bytes, a four-byte receiver index and an eight-byte counter) and a 16-byte authentication tag after the encrypted packet. It also pads the inner packet to a multiple of 16 bytes, but 1,200 is already 75 × 16, so nothing is added.6 Around that go an 8-byte UDP header15 and a 20-byte outer IPv4 header, the smallest an IPv4 header can be.16
Add it up: 1,200 + 16 + 16 + 8 + 20 = 1,260 bytes on the wire. The wrapping is 60 bytes, 5% of this packet. If the outer packet is IPv6, whose header is 40 bytes, 20 more than the smallest IPv4 header,17 the same packet becomes 1,280 bytes and the wrapping 80.
- WireGuard wrapping per packet, IPv6 outside
- 80bytes
- Largest inner packet on a 1,500-byte path, IPv6 outside
- 1,420bytes
The cost is per packet, not per byte, so small packets pay the most. A 100-byte voice or game packet is padded to 112 bytes and then wrapped: 112 + 32 + 8 + 20 = 172 bytes over IPv4, 72% more than it started with, against 5% for the 1,200-byte packet above.
What that means for the tunnel's MTU
On a path that carries 1,500-byte packets, the largest inner packet that still fits is 1,500 minus 60, or 1,440 bytes, under an IPv4 outer header, and 1,500 minus 80, or 1,420 bytes, under IPv6. The padding cannot spoil that sum, because the Linux implementation never pads a packet beyond the interface's MTU.18 A TCP connection inside a 1,420-byte tunnel can then carry 1,380 bytes of data per segment, since the IPv4 and TCP headers take 40 bytes between them.17 If you set no MTU yourself, wg-quick works one out from the endpoint's address or the default route, which its manual calls usually a sane choice.5
There is a floor as well. IPv6 requires every link to carry packets of at least 1,280 bytes,17 and a tunnel interface is a link. If your tunnel carries IPv6, its MTU cannot go below 1,280, so the path underneath must carry at least 1,280 + 80 = 1,360 bytes when the outer header is IPv6.
When the numbers are wrong
A packet too big for the next link is either split into fragments or dropped. Senders find a path's real limit through path MTU discovery, which depends on ICMP "packet too big" messages coming back; when the network cannot deliver those, discovery fails. RFC 8900 warns that fragmented packets may disappear into black holes, and recommends that protocols deal with packet size at their own layer.19 The symptom is distinctive. Ping works, an SSH login works, small pages load, and then a large download, an upload or a git push hangs part-way. Lower the tunnel's MTU, or clamp the TCP maximum segment size on the server so connections never send segments too big for the tunnel.
OpenVPN has knobs for the same problem. Its manual suggests --tun-mtu 1500 --fragment 1300 --mssfix as a good first try for MTU trouble, noting that --fragment works only over UDP, adds 4 bytes to every datagram and is meant as a last resort when path MTU discovery is broken.9
Running your own: one port, forwarding, NAT and a key per person
The server side is three pieces of Linux plumbing, the same for both projects, and one piece of bookkeeping, which differs.
Open one UDP port
Set the port explicitly and allow it in the server's firewall and in any filter in front of the server. Nothing else needs to be open for the VPN.
Turn on forwarding
Set net.ipv4.ip_forward to 1, and put the setting under /etc/sysctl.d/ so it survives a reboot.
Masquerade what leaves the public interface
Rewrite the source of tunnel traffic to the server's own address as it leaves, or replies to private addresses such as 10.0.0.2 have no way back.
Issue a key or a certificate per person
WireGuard: a key pair per device, and a [Peer] block with its own /32 address. OpenVPN: a certificate per person, signed by your CA.
Configure the client
The server's public key or your CA certificate, the server's endpoint, a DNS server, and what to route through the tunnel: 0.0.0.0/0 covers IPv4 only, so add ::/0 to send everything, or list only your private networks.
Test with something big
A fresh handshake and a ping prove the tunnel is up. Only a large download proves the MTU is right.
If you leave ListenPort unset, WireGuard picks a random port,4 and your firewall rule stops matching after a restart. Forwarding between interfaces is off by default (ip_forward is 0).20 The NAT rule uses masquerade, which is source NAT to the address of the interface the packet leaves by.21 On a WireGuard server the setup looks like this, with keys made under umask 077 so that nobody else can read them:3
umask 077wg genkey | tee server.key | wg pubkey > server.pubsysctl -w net.ipv4.ip_forward=1net.ipv4.ip_forward = 1nft add table natnft 'add chain nat postrouting { type nat hook postrouting priority 100 ; }'nft add rule nat postrouting ip saddr 10.0.0.0/24 oifname "eth0" masqueradeReplace eth0 with the interface that holds the server's public address; ip route show default names it. Like the sysctl, the nft rules vanish on reboot: save them in your distribution's nftables configuration, or run them from PostUp and PostDown lines in the WireGuard file.5 That file gives the interface its tunnel address, its port and its key, then one block per peer:
cat /etc/wireguard/wg0.conf[Interface]Address = 10.0.0.1/24ListenPort = 51820PrivateKey = (the contents of server.key) [Peer]PublicKey = (the laptop's public key)AllowedIPs = 10.0.0.2/32 [Peer]PublicKey = (the phone's public key)AllowedIPs = 10.0.0.3/32The client's file is the mirror image. Its one peer is the server, with an Endpoint to find it and allowed IPs of 0.0.0.0/0 and ::/0, the IPv4 and IPv6 default routes,5 so that everything goes through the tunnel:
cat /etc/wireguard/wg0.conf[Interface]Address = 10.0.0.2/32PrivateKey = (the laptop's private key)DNS = 9.9.9.9 [Peer]PublicKey = (the contents of server.pub)Endpoint = 203.0.113.10:51820AllowedIPs = 0.0.0.0/0, ::/0Both halves matter: with 0.0.0.0/0 alone, IPv6 traffic on a café network that offers it leaves outside the tunnel. For IPv6 to work through the tunnel rather than simply stop, give the tunnel IPv6 addresses and forward IPv6 on the server. The DNS line has wg-quick set the laptop's resolver while the tunnel is up,5 here a public one, reached through the tunnel. Without it, lookups can still go to the café's resolver, which usually sits on its local network and is reached directly.
Bring each side up with wg-quick up wg0, which reads /etc/wireguard/wg0.conf,5 and ask the server what it sees. A recent handshake and a learned endpoint mean the tunnel is up:
wg showinterface: wg0 public key: (the server's public key) private key: (hidden) listening port: 51820 peer: (the laptop's public key) endpoint: 192.0.2.44:53211 allowed ips: 10.0.0.2/32 latest handshake: 41 seconds ago transfer: 1.52 MiB received, 12.84 MiB sentAn OpenVPN server needs the same forwarding, a NAT rule for its own address pool and one open UDP port. Its configuration carries the certificates:
cat server.confport 1194proto udpdev tunca ca.crtcert server.crtkey server.keydh noneserver 10.8.0.0 255.255.255.0tls-crypt tc.keyThe server line hands clients addresses from 10.8.0.0/24, dh none leaves key exchange to elliptic curves, and every peer uses the same tls-crypt key.9 Each client's file carries the CA certificate, its own certificate and key, that shared key, and remote-cert-tls server.
Mistakes that cost an evening
- Forwarding or NAT missing. The handshake succeeds and nothing past the server answers. Check
sysctl net.ipv4.ip_forward, check that the NAT rule names the interface that really holds the public address, and that the host firewall's forward chain accepts tunnel traffic, since a drop policy there blocks it silently. - The port open in one place only. An allow rule in the host firewall does nothing if a filter in front of the server drops the port, and the other way round. A WireGuard server stays silent either way, so the client just keeps trying.
- One key on two devices. The server moves a peer's endpoint to wherever its latest authenticated packet came from,4 so two devices sharing a key keep taking the endpoint from each other, and each loses replies meant for it. Give every device its own key pair and its own address.
- Overlapping allowed IPs. An outgoing packet goes to exactly one peer, so two peers listing the same address cannot both receive traffic for it. A /32 per client avoids the question.
- TCP by habit. Switching an OpenVPN server to TCP because TCP sounds more reliable invites the meltdown described above.
- Clients that never check the server. Without
remote-cert-tls serveror another server check, an OpenVPN client accepts any certificate your CA signed, including another client's.9
What the rules allow, and what passes the filter
Clouduxe's Acceptable Use Policy allows a VPN for yourself, your organisation or your customers, provided it is restricted to the people you intend to serve. What it does not allow is an open proxy, or an anonymising service that relays other people's traffic without identifying them. WireGuard builds that restriction into its design: every peer is a key you issued, so the peer list is the list of people you serve. With OpenVPN your CA plays the same part, as long as you revoke what you no longer want.
The second rule is about protocols. Only TCP, UDP and ICMP reach a Clouduxe server through the DDoS filter. WireGuard over UDP and OpenVPN over UDP or TCP pass as they are. Plain IPsec does not: its ESP packets are their own IP protocol, number 50, neither TCP nor UDP.22 IPsec's NAT traversal mode wraps ESP inside UDP, on the same port as its IKE key exchange,23 and that is the form that gets through. It needs UDP rules for 500, where IKE starts, and 4500, where traffic moves once a NAT is found.24
Everything the people on a VPN server fetch crosses it twice, in and out, so size the plan by traffic (the bandwidth guide explains), and put it near them, since every packet now detours through it (server location and latency).
Questions
Is WireGuard better than OpenVPN?
For a VPN between devices you control, WireGuard is usually simpler: one UDP port, one key pair per device, and nothing to renew or revoke beyond deleting a peer. OpenVPN is the better fit when you need a TCP tunnel, username and password logins, certificates from an authority you already run, or Ethernet bridging.
Can WireGuard run over TCP?
No. WireGuard sends everything over UDP and deliberately does not support TCP, because TCP carried inside TCP performs badly when packets are lost. OpenVPN can use either, and its manual says it works best over UDP.
What port does WireGuard use?
Whichever port you set as ListenPort. The official examples use 51820, and if you set nothing the port is chosen at random, so a server should always set it. OpenVPN's registered port is 1194.
Why does my VPN connect but large downloads hang?
Usually the MTU. Every tunnel wraps each packet in extra headers (60 to 80 bytes for WireGuard), so full-size packets no longer fit the path, and if the ICMP messages that should report this are filtered, they vanish. Lower the tunnel MTU or clamp the TCP maximum segment size.
Does a VPN make me anonymous?
No. It moves the point where your traffic enters the internet to the VPN server. The networks between you and the server see only encrypted packets, but the server decrypts everything, and the sites you visit see the server's address.
Can I run IPsec on a server that only passes TCP, UDP and ICMP?
Yes, with UDP encapsulation. IPsec's ESP packets are their own IP protocol, number 50, so they are dropped by a filter that passes only TCP, UDP and ICMP. NAT traversal wraps them in UDP, which gets through.
Sources
- Universal TUN/TAP device driverThe Linux kernel documentation
- WireGuard: fast, modern, secure VPN tunnelWireGuard
- Quick StartWireGuard
- wg(8) manual pageWireGuard (wireguard-tools)
- wg-quick(8) manual pageWireGuard (wireguard-tools)
- Protocol and CryptographyWireGuard
- Linux 5.6Kernel Newbies
- Known LimitationsWireGuard
- OpenVPN 2.6 ManualOpenVPN
- OpenVPN 2.x Community How-ToOpenVPN
- Linux 6.16Kernel Newbies
- Changes.rst, release/2.7 branchOpenVPN (GitHub)
- Why TCP Over TCP Is A Bad Idea (2001), archived copyOlaf Titz, via the Internet Archive
- RFC 894: A Standard for the Transmission of IP Datagrams over Ethernet NetworksIETF
- RFC 768: User Datagram ProtocolIETF
- RFC 791: Internet ProtocolIETF
- RFC 8200: Internet Protocol, Version 6 (IPv6) SpecificationIETF
- drivers/net/wireguard/send.cThe Linux kernel source (torvalds/linux on GitHub)
- RFC 8900: IP Fragmentation Considered FragileIETF
- IP SysctlThe Linux kernel documentation
- Performing Network Address Translation (NAT)nftables wiki
- RFC 4303: IP Encapsulating Security Payload (ESP)IETF
- RFC 3948: UDP Encapsulation of IPsec ESP PacketsIETF
- RFC 7296: Internet Key Exchange Protocol Version 2 (IKEv2)IETF