What is WireGuard?
WireGuard is an open-source VPN protocol integrated in the Linux kernel since version 5.6 (also available on Windows, macOS, Android and iOS). Its design is minimalist: under 4,000 lines of code, modern cryptography (Curve25519, ChaCha20-Poly1305, BLAKE2s) and reproducible configuration based on key pairs. Unlike OpenVPN or IPsec, it requires no certificate infrastructure and the handshake takes milliseconds instead of seconds.
Why use it for IoT?
IoT gateways deployed in the field connect from operator networks with NAT or CGNAT — they have no fixed public IP and are not directly reachable. With WireGuard, each device establishes an encrypted tunnel to a central server with a static IP. The central system sees all gateways as if they were on the same local network, without opening ports to the outside or managing complex VPNs.
WireGuard enables secure, encrypted access to any remote device or infrastructure over an untrusted network. Unlike OpenVPN or IPSec, WireGuard operates in the Linux kernel space with only ~4,000 lines of code, resulting in latencies below 10 ms and negligible CPU usage even on embedded hardware. This guide covers the complete server-side setup: key generation, wg0.conf configuration, systemd service activation and handshake verification with a peer.
Tunnel architecture
The WireGuard tunnel is point-to-point: a central server (your instance on AWS, GCP or on-premise) acts as a static peer with a fixed public IP, and the remote peer is the dynamic client that initiates the connection. This creates an encrypted access channel for remote configuration, diagnostics or any service requiring secure communication between both endpoints.
| Component | WireGuard role | Tunnel IP (example) |
|---|---|---|
| VPN Server (Linux / Windows) | Static peer (active ListenPort) | 10.8.0.1/24 |
| Peer / remote client | Dynamic peer (initiates connection) | 10.8.0.2/32 |
Step 1 — Install WireGuard on the server
Linux (Ubuntu / Debian)
On an Ubuntu 22.04 or Debian 12 server (recommended):
sudo apt update && sudo apt install -y wireguard sudo modprobe wireguard # loads the kernel module
Verify the module is available:
lsmod | grep wireguard # wireguard 90112 0
Windows 10 / 11
Download the official installer from wireguard.com/install or via winget:
# Option A — winget (Windows 10 v1709+ / Windows 11) winget install WireGuard.WireGuard # Option B — graphical installer # Download the .msi from wireguard.com/install and run as Administrator
Verify that wg.exe is available by opening PowerShell or CMD:
wg --version # wireguard-windows v0.5.3
Step 2 — Generate key pair on the server
Linux (Ubuntu / Debian)
# Generate server private key wg genkey | sudo tee /etc/wireguard/server_private.key # Derive the public key sudo cat /etc/wireguard/server_private.key | wg pubkey | sudo tee /etc/wireguard/server_public.key sudo chmod 600 /etc/wireguard/server_private.key
Save the server public key in a safe place — you will need to share it with every peer that connects.
Windows 10 / 11
wg.exe is installed at C:\Program Files\WireGuard\. Run PowerShell as Administrator:
cd "C:Program FilesWireGuard" # Generate the server private key .wg.exe genkey | Set-Content server_private.key # Derive the public key Get-Content .server_private.key | .wg.exe pubkey | Set-Content server_public.key
GUI alternative: in the WireGuard app click 'Add Tunnel' → 'Add empty tunnel'. The app generates the key pair automatically and displays the public key. Just add Address, ListenPort and the [Peer] blocks.
Step 3 — Create the server configuration file
Linux (Ubuntu / Debian)
Create /etc/wireguard/wg0.conf with the following content (replace values between < >): (/etc/wireguard/wg0.conf)
[Interface] PrivateKey = <contents of server_private.key> Address = 10.8.0.1/24 ListenPort = 51820 # Enable IP forwarding for routing between peers PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE [Peer] # gateway IoT / embedded device Index AMI — unit 001 PublicKey = <Index AMI public key — generated in Step 4> AllowedIPs = 10.8.0.2/32
Note: UDP port 51820 must be open in the server firewall. On AWS: inbound rule UDP 51820 in the Security Group. On GCP: VPC firewall rule with UDP protocol and port 51820.
Windows 10 / 11
The wg0.conf format is identical to Linux. Windows does not require the PostUp/PostDown lines (manual routing if needed):
[Interface] PrivateKey = <contenido de server_private.key> Address = 10.8.0.1/24 ListenPort = 51820 [Peer] PublicKey = <clave pública del peer — generada en Paso 4> AllowedIPs = 10.8.0.2/32
Import the file as a Windows service (PowerShell or CMD as Administrator):
# Install the tunnel as a Windows service wireguard /installtunnelservice "C:WireGuardwg0.conf" # The service starts automatically with name: WireGuardTunnel$wg0
Open UDP port 51820 in Windows Firewall (PowerShell as Administrator):
New-NetFirewallRule -DisplayName "WireGuard VPN" ` -Direction Inbound -Protocol UDP ` -LocalPort 51820 -Action Allow
Step 4 — Add the peer to the server
When the peer sends you their public key, add a [Peer] block at the end of the server's wg0.conf file:
[Peer] # Descriptive peer name (optional comment) PublicKey = <peer public key> AllowedIPs = 10.8.0.2/32
Reload the configuration without restarting the service:
Linux (Ubuntu / Debian)
sudo wg syncconf wg0 <(wg-quick strip wg0)
Windows 10 / 11
Open the WireGuard GUI → select the wg0 tunnel → edit the file and add the [Peer] block → apply changes.
Step 5 — Bring up the interface and verify the handshake
Linux (Ubuntu / Debian)
On the server:
sudo systemctl enable wg-quick@wg0 sudo systemctl start wg-quick@wg0
Verify the interface status:
sudo wg show # Expected output: interface: wg0 public key: <server public key> private key: (hidden) listening port: 51820 peer: <Index AMI public key> endpoint: <Index AMI 4G IP>:XXXXX allowed ips: 10.8.0.2/32 latest handshake: 3 seconds ago transfer: 1.23 KiB received, 2.45 KiB sent
The latest handshake field with a recent value (less than 3 minutes) confirms the tunnel is active. If it does not appear, check the troubleshooting section.
Windows 10 / 11
If you installed the service with /installtunnelservice, the tunnel starts automatically. For manual control from PowerShell:
sc start WireGuardTunnel$wg0 # o para detenerlo: sc stop WireGuardTunnel$wg0
GUI alternative: open WireGuard from the system tray or Start menu and toggle the wg0 tunnel switch.
Verify tunnel status with wg.exe (must be in PATH or use full path):
wg show # interface: wg0 # public key: ... # listening port: 51820 # peer: ... # latest handshake: 3 seconds ago
Step 6 — Verify end-to-end connectivity
From the server, ping the Index AMI tunnel IP:
ping 10.8.0.2 # PING 10.8.0.2 (10.8.0.2): 56 data bytes # 64 bytes from 10.8.0.2: icmp_seq=0 ttl=64 time=8.3 ms
Latency below 15 ms over LTE is normal. If your management application runs on the same server, it can already reach the peer directly via 10.8.0.2.
Troubleshooting
| Symptom | Probable cause | Solution |
|---|---|---|
| No handshake after 2 min | UDP port 51820 blocked | Open UDP 51820 in the server firewall / security group |
| Handshake OK but no ping | Routes or AllowedIPs misconfigured | Verify that the peer AllowedIPs includes the destination IP |
| Tunnel drops after 3–5 min idle | 4G NAT expires the UDP session | Ensure PersistentKeepalive = 25 on the Index AMI peer |
| Invalid public key | Characters cut when copying | The key is exactly 44 base64 characters; copy it in full |
Mesh topology (multiple gateways)
For deployments with more than one Index AMI, add an additional [Peer] block for each unit in the server's wg0.conf. Each Index AMI receives a unique tunnel IP (10.8.0.2, 10.8.0.3, …). The server acts as a central hub — gateways do not need visibility between each other.
[Peer] # gateway IoT / embedded device Index AMI — unit 002 PublicKey = <unit 002 public key> AllowedIPs = 10.8.0.3/32 [Peer] # gateway IoT / embedded device Index AMI — unit 003 PublicKey = <unit 003 public key> AllowedIPs = 10.8.0.4/32
Linux (Ubuntu / Debian)
Apply changes hot without restarting the service:
sudo wg addconf wg0 /etc/wireguard/wg0.conf # or if adding the peer directly: sudo wg set wg0 peer <public key> allowed-ips 10.8.0.3/32
Windows 10 / 11
On Windows, hot changes with wg addconf are not directly available. To add a peer, edit wg0.conf, stop the service with sc stop WireGuardTunnel$wg0 (or from the GUI), then restart it.
Next steps
With the server active and the handshake verified, the encrypted tunnel is operational. The remote peer is securely accessible via its tunnel IP from any point on the network. If the peer's RS485 bus has communication faults, see the RS485 field diagnostics guide.