Back to Blog
WireGuard
Networking
Kubernetes
Security

Building Private Networks with WireGuard for Kubernetes

2026-04-02 · 10 min read · Serhii Mazurok

Running Kubernetes across multiple providers (Hetzner, AWS, bare-metal) requires a private network layer. WireGuard gives us that - fast, simple, and auditable.


The Problem

When you create a Kubernetes cluster, nodes need to communicate over a private network. Cloud providers offer VPC/VNet, but:

  • Cross-provider clusters have no shared private network
  • Bare-metal / VPS providers often lack private networking entirely
  • VPN solutions like IPSec are complex and slow

We needed something that works everywhere, is fast, and easy to automate.


Why WireGuard?

FeatureWireGuardIPSecOpenVPN
Config complexity~10 linesHundreds of linesModerate
Kernel-spaceYesYesNo (userspace)
Performance~950 Mbps~800 Mbps~500 Mbps
Handshake1 RTTMultiple RTTsMultiple RTTs
Code size~4K lines~400K lines~100K lines
Attack surfaceMinimalLargeModerate

WireGuard operates in kernel space (built into Linux since 5.6), uses modern cryptography (Curve25519, ChaCha20, Poly1305), and is conceptually simple: each peer has a public key and a list of allowed IPs.


Architecture

Our mesh network architecture for a 3-node cluster:

┌──────────────┐     WireGuard tunnel     ┌──────────────┐
│  Node 1      │◄────────────────────────►│  Node 2      │
│  10.10.0.1   │                          │  10.10.0.2   │
│  Hetzner     │                          │  Hetzner     │
└──────┬───────┘                          └──────┬───────┘
       │                                         │
       │         WireGuard tunnel                │
       │    ┌──────────────┐                     │
       └───►│  Node 3      │◄────────────────────┘
            │  10.10.0.3   │
            │  AWS EC2     │
            └──────────────┘

Each node has a WireGuard interface (wg0) with a private IP from the 10.10.0.0/24 range. Every node peers with every other node - a full mesh.


Key Exchange Flow

Our automated provisioning follows these steps:

1. Generate keys - each node generates a Curve25519 key pair 2. Exchange public keys - via the Segla control plane API (encrypted at rest) 3. Configure peers - each node receives the public key + public endpoint of every other node 4. Establish tunnels - WireGuard establishes connections automatically 5. Health check - we verify connectivity between all peers before proceeding with K8s installation

# Generated config on Node 1
[Interface]
PrivateKey = <node1-private-key>
Address = 10.10.0.1/24
ListenPort = 51820

[Peer] PublicKey = <node2-public-key> Endpoint = 167.235.12.46:51820 AllowedIPs = 10.10.0.2/32 PersistentKeepalive = 25

[Peer] PublicKey = <node3-public-key> Endpoint = 3.121.45.67:51820 AllowedIPs = 10.10.0.3/32 PersistentKeepalive = 25


Kubernetes Integration

Once the WireGuard mesh is up, Kubernetes sees all nodes on the same 10.10.0.0/24 network. We configure:

  • kubelet binds to the WireGuard IP (--node-ip=10.10.0.X)
  • etcd peers communicate over WireGuard IPs
  • kube-apiserver listens on the WireGuard interface
  • Pod CIDR (10.244.0.0/16) routes through the WireGuard overlay

This means the kube-apiserver is never exposed on the public internet. Access goes through our tunnel proxy at .kube-apiserver-tunnel.segla.io.


Performance

We benchmarked WireGuard overhead on Hetzner CX41 instances (same datacenter):

MetricDirectWireGuardOverhead
TCP throughput980 Mbps945 Mbps~3.6%
Latency (p50)0.28 ms0.31 ms+0.03 ms
Latency (p99)0.42 ms0.48 ms+0.06 ms

For cross-provider (Hetzner → AWS Frankfurt), the WireGuard overhead is negligible compared to the base internet latency (~1-2 ms).


Monitoring

We monitor the mesh with:

  • wg show output parsed by a Prometheus exporter
  • Per-peer metrics: last_handshake_seconds, transfer_bytes_received, transfer_bytes_sent
  • Alerts on handshake age > 3 minutes (indicates connectivity loss)
  • Latency between all peer pairs (ping over WireGuard)
# Alert rule
  • alert: WireGuardPeerDown
expr: time() - wireguard_last_handshake_seconds > 180 for: 2m labels: severity: critical annotations: summary: "WireGuard peer {{ $labels.peer }} is unreachable"

Key Takeaways

1. WireGuard is the right choice for multi-provider Kubernetes networking - fast, simple, auditable 2. Full mesh works well for clusters up to ~50 nodes. Beyond that, consider a hub-and-spoke topology 3. Automate key exchange through your control plane, never manually 4. Monitor handshake age - it's the best indicator of tunnel health 5. Bind K8s components to WireGuard IPs to keep the control plane off the public internet


Segla automates all of this. Create a cluster, select your servers, and the mesh is built in under 60 seconds. Try it free →

The modern platform for cloud-native application delivery. From code to production in minutes.

Connect

© 2026 Segla. All rights reserved.

Made with in Ukraine 🇺🇦