VPNSmith
self-host-vpnINFO

WireGuard QR Code: Generate It from a .conf (qrencode)

Turn a WireGuard .conf into a QR code with one qrencode command, or create configs and QR codes in your browser. And why the QR code is your private key.

By Eric Gerard · Founder · VPNSmith - Self-host VPN & GDPR VPS specialist5 min readPhoto via Pexels

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.

Seen from behind, a woman holds up a smartphone to photograph a large QR code printed on a green panel, her screen showing the code framed inside a payment app in Spanish
Seen from behind, a woman holds up a smartphone to photograph a large QR code printed on a green panel, her screen showing the code framed inside a payment app in Spanish

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. clear alone does not empty the scrollback. Use reset, or close the terminal window entirely.
  • Delete PNG files immediately. A client1.png sitting 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→

Frequently asked questions

How do I create a WireGuard QR code?
Install qrencode and pipe a client config file into it with the terminal output option: qrencode -t ansiutf8 < client.conf. The WireGuard mobile app scans it directly from the screen. There is no separate format, the QR code simply contains the config file as text.
Is a WireGuard QR code safe to share?
No. The QR code contains the entire config file including the client's private key. Anyone who photographs it, or finds it in a screenshot or a scrollback buffer, has full access to your tunnel as that peer.
Can I generate the QR code as an image file?
Yes, qrencode -o client.png < client.conf writes a PNG. Delete it once scanned, because an image file persists in ways a terminal display does not, including in cloud photo backups if it lands in a synced folder.
Why does my phone scan the code but the tunnel does not connect?
The QR code only carries the config. If the handshake never completes, the problem is the config itself or the network path: wrong endpoint, wrong port, firewall on the server, or a peer entry missing on the server side for this client's public key.