Security

WireGuard Server: Installation and Configuration Guide for Linux and Windows

May 12, 2026·7 min read

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.

Visualization · WireGuard handshake — server ↔ peer client

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.

ComponentWireGuard roleTunnel IP (example)
VPN Server (Linux / Windows)Static peer (active ListenPort)10.8.0.1/24
Peer / remote clientDynamic 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

SymptomProbable causeSolution
No handshake after 2 minUDP port 51820 blockedOpen UDP 51820 in the server firewall / security group
Handshake OK but no pingRoutes or AllowedIPs misconfiguredVerify that the peer AllowedIPs includes the destination IP
Tunnel drops after 3–5 min idle4G NAT expires the UDP sessionEnsure PersistentKeepalive = 25 on the Index AMI peer
Invalid public keyCharacters cut when copyingThe 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.