Affiliate disclosure - This post contains Contabo affiliate links. If you grab a VPS through them, we earn a commission at no extra cost to you.
Typing a base64 private key into a phone keyboard is unpleasant enough that people copy configs through chat apps instead, which is worse. The QR code exists to avoid both.
It is one command, and the part worth reading is what happens after you scan it.
No config yet, or no terminal at hand? Our WireGuard config generator creates the server file and one client config per device, each with its QR code, entirely in your browser: the keys are generated locally with Curve25519 and nothing is sent to a server. It does not convert an existing .conf; for that, qrencode below is the tool.
Generating one
Install the encoder:
apt install qrencode # Debian, Ubuntu
dnf install qrencode # Fedora, RHEL
Then, on the machine holding the client config:
qrencode -t ansiutf8 < /etc/wireguard/client1.conf
The code appears in the terminal, drawn in block characters. Open WireGuard on the phone, add a tunnel, scan from QR code, point the camera at the screen. The tunnel is added with its name, addresses, keys and peer, complete.
There is no special format. The QR code contains the config file as plain text. Anything that can read a QR code can read your config.
Size is rarely a constraint here. A typical WireGuard client config runs to a few hundred bytes, and the QR standard goes up to version 40, a 177 by 177 module grid holding 2 953 bytes at the lowest of its four error-correction levels. A config comfortably fits, which is precisely why the whole thing, private key included, travels in one image.
For a file instead of a terminal drawing:
qrencode -o client1.png < /etc/wireguard/client1.conf
If the code will not scan, the usual causes are a terminal font that distorts the blocks, or a very long config. -t utf8 instead of ansiutf8 renders smaller, and reducing the terminal font size helps more than anything else.

The part that matters
A WireGuard client config contains PrivateKey: a 32-byte Curve25519 key, written as 44 base64 characters on a single line. The QR code contains the config. Therefore the QR code is the private key, in a format designed to be read at a distance by a camera.
That changes how it should be handled:
- Do not photograph it. A photo goes into your camera roll and, on most phones, straight into a cloud backup.
- Do not put it in a chat message or an email. Both are stored copies you do not control.
- Clear the terminal after scanning.
clearalone does not empty the scrollback. Usereset, or close the terminal window entirely. - Delete PNG files immediately. A
client1.pngsitting in a home directory outlives the reason it was created. - Do not display it where a camera can see it, which in a shared office includes the window behind you.
One private key per client is the rule the QR code makes easy to break. Generating one config and scanning it onto three phones gives all three the same identity, and the server then cannot tell them apart, cannot revoke one, and will misroute traffic when two are connected at once. Adding a distinct peer per device is covered in adding a WireGuard peer.
Generating the config first, if you do not have one
The QR code is the last step. Before it, the client needs a key pair and a peer entry on the server:
wg genkey | tee client1.key | wg pubkey > client1.pub
Then a config referencing the server's public key, endpoint and AllowedIPs, and a matching [Peer] block on the server carrying client1.pub. Skipping the server side is the most common reason a scanned tunnel connects to nothing: the phone is configured, and the server has never heard of it.
If you would rather not build the files by hand, the config generator writes both sides at once (server [Interface] with every [Peer] block, plus a client file and QR code per device), so the phone you scan and the server it talks to are consistent from the start.
The server needs a public IP address that your phone can reach from a mobile network. A home connection behind CGNAT does not have one (check yours with the WireGuard port checker); a small VPS does, for about €5 a month.
★ Nuremberg GDPR datacenter · ✓ Dedicated IPv4 included · 200 Mbit/s port
A WireGuard server your phone can always reach → Contabo Cloud VPS 4€5.50/month (checked 18 Oct 2026, first 24 months) · fixed public IPv4 · 4 vCPU, 8 GB RAM→Full walkthroughs, including the server side, are in PiVPN WireGuard setup for a Raspberry Pi and self-hosting on a VPS for a rented server. Both generate client configs you can pipe straight into qrencode.
If the scan works but the tunnel does not
The QR code has done its job the moment the tunnel appears in the app. Everything after that is ordinary WireGuard.
Check the phone shows a recent handshake. A healthy peer re-handshakes roughly every 120 seconds, so anything older than about two minutes on an active tunnel is a symptom rather than a pause. If it does not, work through handshake troubleshooting: endpoint address, port reachable from outside (51820/UDP by default), server firewall, and the peer entry. If the handshake succeeds but pages hang, that is MTU, and it is especially common on mobile networks.
Platform specific setup notes are in WireGuard Android setup and WireGuard iOS setup.
★ Nuremberg GDPR datacenter · ✓ Dedicated IPv4 included · 200 Mbit/s port
Self-host your VPN on your own VPS → ContaboFull root access · public IPv4 · pick your region→


