WireGuard config generator

Describe the server and who connects to it, and get every config file: the server's wg0.conf, a file for each laptop, phone or server that connects, the commands to start it and the firewall rules. By default the keys are made with wg on your own computer; if you choose, this browser makes them. This page loads no analytics, and nothing leaves it.

The server
The public host name or IP address peers connect to, for example vpn.example.com.
WireGuard listens on UDP. 51820 is the usual port.
A private IPv4 range used only by the tunnel. The server takes its first address, each peer the next one.
Where forwarded traffic leaves the server, usually eth0 or ens3 (see ip route show default). Used for a full tunnel and for networks behind the server.
The firewall script keeps it open, so enabling ufw does not lock you out.
Peers
Names the file and the interface on that device, for example laptop: up to 15 letters, digits or _ = + . -
Traffic
Split tunnel: ranges the peers reach through the server, such as its LAN or a cloud VPC, separated by commas. For example 192.168.10.0/24.
IP addresses, separated by commas. Useful with a full tunnel, so DNS questions go through it too.
Peers send a small packet this often, so a NAT router or firewall in front of them keeps the tunnel open. 25 is the usual value; 0 turns it off.
An extra symmetric key that each peer shares with the server, on top of the key pair: one more layer of protection, which wg(8) describes as post-quantum resistance.

Or make the keys in this browser (optional)

For when wg is not at hand, or to scan a QR code from this screen. Your browser makes the keys on this device: they are not sent anywhere, not saved, not put in the link and not measured.

What it does

It writes a complete WireGuard setup for one server and the devices that connect to it: the server's wg0.conf with a [Peer] block for each device, each device's own file with the server as its peer, the commands to start the tunnel on the server, a ufw firewall script, and a QR code for phones when the keys are made here. Addresses come from one tunnel network, which is checked against the networks Docker creates.

How it works

  1. Every file is written by the same engine as our other Linux tools (@anaroq/linux). Names, addresses, ranges and the interface are checked for form, so a field cannot add a line of its own, and two peers can never claim the same addresses.
  2. By default the files hold placeholders, and a short script makes every key with wg genkey, wg pubkey and wg genpsk on your computer and writes it in. Our tests run that script and bring the server and its peers up with wg-quick in containers, then check the handshake, the tunnel in both directions and, for a full tunnel, NAT to a host outside it.
  3. If you make the keys here, the browser's WebCrypto X25519 makes them (or, where a browser lacks it, the bundled tweetnacl library); our tests check that the public key derived from each private key is the one wg pubkey prints, on known keys and on fresh ones.
  4. This page loads no analytics, its security policy lets it connect only to this site, and nothing is kept in the link or in browser storage.

What each option does

Address and AllowedIPs
Each device gets one address on the tunnel network. On the server, a peer's AllowedIPs is that one address: traffic for it goes to that peer, and traffic from it is accepted only with that source. On a peer, AllowedIPs is what goes through the tunnel.
Full and split tunnel
A full tunnel sends 0.0.0.0/0 and ::/0 through the server, so all traffic leaves from the server's address. A split tunnel sends only the tunnel network and the networks you list.
PostUp and PostDown (NAT)
When the server forwards traffic, wg-quick runs these iptables rules as the tunnel comes up and goes down: forwarding to and from the tunnel is accepted, and the tunnel network is masqueraded out of the server's interface.
PersistentKeepalive
A packet every few seconds from the peer keeps the NAT mapping of its router open, so the server can reach a peer that has been idle.
PresharedKey
A symmetric key mixed into the handshake, unique to each server and peer pair. It adds protection on top of the key pair and does not replace it.

Example

A server at vpn.example.com and two peers, a laptop and a phone, on a split tunnel over 10.8.0.0/24, with keys left to wg:

The server's wg0.conf
wg0.conf
# WireGuard interface wg0. Contains a private key: keep it mode 0600.
# Generated by @anaroq/linux 1.0.0 (ANAROQ). Start with: sudo systemctl enable --now wg-quick@wg0
[Interface]
PrivateKey = @SERVER_PRIVATE_KEY@
Address = 10.8.0.1/24
ListenPort = 51820

# laptop
[Peer]
PublicKey = @PEER_1_PUBLIC_KEY@
PresharedKey = @PEER_1_PRESHARED_KEY@
AllowedIPs = 10.8.0.2/32

# phone
[Peer]
PublicKey = @PEER_2_PUBLIC_KEY@
PresharedKey = @PEER_2_PRESHARED_KEY@
AllowedIPs = 10.8.0.3/32
The laptop's laptop.conf
laptop.conf
# WireGuard interface laptop. Contains a private key: keep it mode 0600.
# Generated by @anaroq/linux 1.0.0 (ANAROQ). Start with: sudo systemctl enable --now wg-quick@laptop
[Interface]
PrivateKey = @PEER_1_PRIVATE_KEY@
Address = 10.8.0.2/32

# server vpn.example.com
[Peer]
PublicKey = @SERVER_PUBLIC_KEY@
PresharedKey = @PEER_1_PRESHARED_KEY@
AllowedIPs = 10.8.0.0/24
Endpoint = vpn.example.com:51820
PersistentKeepalive = 25
And the script that makes the keys on your computer:
make-wireguard-keys.sh
#!/usr/bin/env bash
# Makes the WireGuard keys with wg on this computer and writes them into the config
# files in this directory, in place of their @…_KEY@ placeholders. Generated by ANAROQ.
# Usage: bash make-wireguard-keys.sh   (needs wireguard-tools: wg genkey, wg pubkey, wg genpsk)
set -euo pipefail
umask 077

command -v wg >/dev/null 2>&1 || { echo 'wg not found: install wireguard-tools first.' >&2; exit 1; }
for f in wg0.conf laptop.conf phone.conf; do
  [ -f "$f" ] || { echo "$f is not in this directory." >&2; exit 1; }
done
grep -q '@SERVER_PRIVATE_KEY@' wg0.conf || { echo 'The keys are already filled in.' >&2; exit 1; }

# fill FILE PLACEHOLDER KEY: base64 keys have no | or &, so sed takes them as they are.
fill() {
  local tmp
  tmp=$(mktemp)
  sed "s|$2|$3|g" "$1" > "$tmp"
  cat "$tmp" > "$1"
  rm -f "$tmp"
}

server_key=$(wg genkey)
server_pub=$(printf '%s\n' "$server_key" | wg pubkey)
fill wg0.conf @SERVER_PRIVATE_KEY@ "$server_key"

# Peer 1: laptop
key=$(wg genkey)
pub=$(printf '%s\n' "$key" | wg pubkey)
fill laptop.conf @PEER_1_PRIVATE_KEY@ "$key"
fill laptop.conf @SERVER_PUBLIC_KEY@ "$server_pub"
fill wg0.conf @PEER_1_PUBLIC_KEY@ "$pub"
psk=$(wg genpsk)
fill laptop.conf @PEER_1_PRESHARED_KEY@ "$psk"
fill wg0.conf @PEER_1_PRESHARED_KEY@ "$psk"

# Peer 2: phone
key=$(wg genkey)
pub=$(printf '%s\n' "$key" | wg pubkey)
fill phone.conf @PEER_2_PRIVATE_KEY@ "$key"
fill phone.conf @SERVER_PUBLIC_KEY@ "$server_pub"
fill wg0.conf @PEER_2_PUBLIC_KEY@ "$pub"
psk=$(wg genpsk)
fill phone.conf @PEER_2_PRESHARED_KEY@ "$psk"
fill wg0.conf @PEER_2_PRESHARED_KEY@ "$psk"

chmod 600 wg0.conf laptop.conf phone.conf
unset server_key key psk
echo 'Done: wg0.conf, laptop.conf, phone.conf now hold their keys. Keep them private (mode 600).'

Limits

  • One server, IPv4 tunnel addresses, and peers that connect to the server only: no site-to-site mesh between peers, and not a managed VPN (Tailscale, NetBird and similar tools manage keys and peers for you).
  • A full tunnel routes IPv6 into the tunnel too (::/0) and does not give peers an IPv6 address, so IPv6 traffic stops instead of leaking around the tunnel. On a Linux peer whose kernel has IPv6 switched off, remove ::/0 from its file.
  • The server steps are for Debian or Ubuntu with ufw and iptables; other systems need their own commands.
  • It cannot check that the server is reachable, that the UDP port is open at your cloud provider's firewall, or that the address is right.
  • Keys made in the browser are only as safe as the device and the browser; the wg script is the safer default.

Methodology: how the numbers are worked out

Sources

  1. WireGuard: Quick Start
  2. wg(8) manual page
  3. wg-quick(8) manual page
  4. RFC 7748: Elliptic Curves for Security (X25519)
  5. MDN: SubtleCrypto.generateKey() (X25519)
  6. Docker: default address pools (daemon.json)
  7. Ubuntu manual: ufw(8)

Updated

Next step

SSH config generator and key helper

A free public tool by ANAROQ, a company building compute infrastructure. What ANAROQ is building