WireGuard clients

Chapter 4 — WireGuard Clients

The server is running. Now connect to it. WireGuard has official client apps for Windows, macOS, iOS, and Android — all free, all using the same config file format you wrote in Chapter 3. This chapter walks through installing each one, importing a config, enabling the kill switch, and verifying the tunnel is working.

The Client Config — Quick Recap

Every client needs its own .conf file generated on the server in Chapter 3. It looks like this — make sure you have it ready before starting any of the platform sections below:

[Interface] Address = 10.0.0.2/32 # this client's VPN IP PrivateKey = Y2nL7rH8T4wX3vK9m... # client's private key DNS = 10.0.0.1 # optional — use server as DNS [Peer] PublicKey = P3mK9vX2nL7rH8T4... # server public key Endpoint = your.server.ip:51820 AllowedIPs = 0.0.0.0/0 # full tunnel PersistentKeepalive = 25
Transfer the config file securely. It contains the client's private key. Use a QR code displayed on-screen (Chapter 3), copy it over SSH/SCP, or use an encrypted password manager. Never send it over plain email, WhatsApp, or Slack.

Windows

🪟
Windows 10 / 11
Official WireGuard app — wireguard.com/install · also available via winget
  1. Install the app. Download from wireguard.com/install or run winget install WireGuard.WireGuard in PowerShell. The installer adds a WireGuard system service and a tray icon.
  2. Import the config. Open WireGuard → click the arrow next to Add TunnelImport tunnel(s) from file → select your client1.conf file. The tunnel appears in the list with its name taken from the filename.
  3. Activate. Click the tunnel name → click Activate. The status changes to Active and a green indicator appears in the system tray.
  4. Enable the kill switch (recommended). Click Edit on the tunnel → tick Block all traffic when tunnel is not active (kill switch). This prevents any traffic leaving your machine if the VPN drops.

Command-line alternative (no GUI)

Windows PowerShell — WireGuard CLI
# copy config to the WireGuard directory PS> Copy-Item client1.conf "C:\Program Files\WireGuard\Data\Configurations\" # install and start the tunnel as a Windows service PS> & "C:\Program Files\WireGuard\wireguard.exe" /installtunnelservice "C:\Program Files\WireGuard\Data\Configurations\client1.conf" # start / stop via sc (service control) PS> sc.exe start WireGuardTunnel$client1 PS> sc.exe stop WireGuardTunnel$client1

macOS

🍎
macOS 12 Monterey and later
Mac App Store · also available via Homebrew
  1. Install. Search WireGuard in the Mac App Store, or run brew install wireguard-tools for the command-line version (no GUI, same as Linux).
  2. Import. Open WireGuard → click the + button → Import tunnel(s) from file → select your .conf file. macOS will ask for permission to add VPN configurations — click Allow.
  3. Activate. Toggle the tunnel on. Status shows in the menu bar icon.
  4. On-Demand (optional). Click Edit → enable On-Demand → set rules, e.g. activate automatically when Wi-Fi is connected but not when on a trusted SSID. Useful for always-on protection on untrusted networks.

Homebrew / command-line (wg-quick)

macOS terminal — wg-quick
# install wireguard-tools (includes wg-quick) philip@mac:~$ brew install wireguard-tools # copy config and bring tunnel up philip@mac:~$ sudo cp client1.conf /etc/wireguard/wg0.conf philip@mac:~$ sudo wg-quick up wg0 philip@mac:~$ sudo wg-quick down wg0

iOS

📱
iPhone / iPad — iOS 15+
App Store — free · deepest integration via QR code import
  1. Install WireGuard from the App Store.
  2. Import via QR code (easiest). On the server, run qrencode -t ansiutf8 < /etc/wireguard/client1.conf → hold your phone up to the screen → tap Allow to add the VPN profile.
  3. Or import a file. Transfer the .conf file to your phone via AirDrop, iCloud Drive, or the Files app → open it → iOS offers to import it into WireGuard.
  4. Activate. Tap the toggle next to the tunnel name. iOS adds a VPN indicator to the status bar.
  5. On-Demand (optional). Tap the tunnel info icon → On-Demand Activation → choose Wi-Fi, cellular, or both. Useful for automatic activation on all networks except your home Wi-Fi.
Kill switch on iOS: iOS has no explicit kill switch toggle in the WireGuard app, but when On-Demand is enabled iOS re-establishes the tunnel automatically if it drops — effectively achieving the same result. For a true kill switch, enable On-Demand on all interfaces with no exclusions.

Android

🤖
Android 7+ (API 24+)
Google Play Store · also F-Droid for open-source build
  1. Install WireGuard from the Play Store (or F-Droid).
  2. Import via QR code. Tap the + button → Scan from QR code → scan the code generated by qrencode on the server. Name the tunnel and tap Create Tunnel.
  3. Or import a file. Tap +Import from file or archive → navigate to the .conf file on the device.
  4. Activate. Toggle the tunnel on. Android will prompt you to approve the VPN connection on first use.
  5. Enable the kill switch. Go to Android Settings → Network → VPN → tap the gear icon next to the WireGuard VPN → enable Always-on VPN and Block connections without VPN. This is Android's system-level kill switch — more reliable than any in-app toggle.
Android kill switch is system-level. Unlike the in-app toggles on Windows and iOS, Android's "Block connections without VPN" is enforced by the OS network stack — no traffic leaves the device on any interface if the VPN is down, regardless of which app is trying to send it.

Kill Switch Summary — Platform Comparison

Windows
Built-in
Tick "Block all traffic when tunnel is not active" in the tunnel Edit dialog
macOS
Limited
No kill switch in the GUI app. Use On-Demand rules or a firewall rule via pf
iOS
Via On-Demand
Enable On-Demand on all interfaces with no exclusions — iOS reconnects automatically
Android
System-level
Settings → Network → VPN → Always-on VPN + Block connections without VPN

Verifying the Connection on Any Platform

TestHow to run itExpected result
Public IP changed Visit ifconfig.me or ipinfo.io Shows your VPN server's IP, not your real IP
Ping VPN server ping 10.0.0.1 Replies with low latency
DNS not leaking Visit dnsleaktest.com → Extended test Only your VPN server or its upstream DNS visible
WebRTC leak Visit browserleaks.com/webrtc No local IP exposed (or only VPN IP visible)
Server sees handshake wg show Peer shows "latest handshake: N seconds ago"

Common Client Problems

Tunnel activates but no internet
IP forwarding not enabled on the server, or the iptables MASQUERADE rule is missing/wrong interface name.
On the server: cat /proc/sys/net/ipv4/ip_forward should return 1. Check iptables -t nat -L for the POSTROUTING rule. Verify the interface name in PostUp matches your actual external interface.
Handshake never completes
UDP port 51820 is blocked by a firewall between client and server, or the Endpoint IP/port in the client config is wrong.
Confirm the server's public IP in Endpoint. Test UDP reachability: nc -u your.server.ip 51820. Check ufw status on the server. Try a different network (mobile data vs Wi-Fi) to isolate the blocking firewall.
DNS leaking despite DNS setting
The DNS = 10.0.0.1 line sets the resolver but the OS may still use its default DNS for non-tunnelled queries, or AllowedIPs doesn't include the DNS server's IP.
Ensure AllowedIPs = 0.0.0.0/0 (full tunnel). On Windows, check that the WireGuard interface's DNS is listed first in network adapter settings. Run dnsleaktest.com to confirm.
Tunnel drops on mobile when screen locks
Mobile OS aggressively kills background network connections to save battery.
Ensure PersistentKeepalive = 25 is set in the client config — this sends a UDP keepalive every 25 seconds to prevent NAT tables from timing out. Enable On-Demand on iOS for automatic reconnection.
Wrong key — handshake rejected
The public key in the server's [Peer] block doesn't match the client's actual private key, or keys were copy-pasted with extra whitespace.
On the client, run wg show and note the public key shown. Compare it to what's in the server's wg0.conf [Peer] block. Regenerate and re-import the config if they don't match.
Can reach VPN server but not LAN devices
You're in split-tunnel mode (AllowedIPs = 10.0.0.0/24) and LAN devices have a different subnet, or the server isn't routing to the LAN.
Add the LAN subnet to AllowedIPs on the client, e.g. 10.0.0.0/24, 192.168.0.0/24. Ensure the server has a route to the LAN (it does if it's on the LAN; it won't if it's a remote VPS).
Next — Chapter 5: OpenVPN Server. WireGuard is the right choice for most new deployments, but some networks block UDP entirely. Chapter 5 covers installing OpenVPN on Linux, building a PKI with Easy-RSA, writing the server config, and issuing client certificates — giving you a VPN that can tunnel over TCP port 443 and pass through almost any firewall.