I already had WireGuard running on the server. My laptop was the only client, which was fine until I wanted to check something from my phone.
The iPhone had the WireGuard app installed already, so this was mostly a peer management job: give the phone its own identity, add it to the server, import the config, then check for a handshake.
The important part is not copying the laptop config.

The phone needs its own WireGuard identity, not a copy of the laptop identity. Photo: www.Pixel.la Free Stock Photos, CC0, via Wikimedia Commons.
The peer rule
Every WireGuard device should be its own peer.
The laptop already had a private key, public key, and VPN address. If I reused that same config on the iPhone, the server would see both devices as the same peer. Whichever device spoke most recently would become the current endpoint for that peer.
That gets messy quickly. One device appears to work, the other drops off, and the tunnel starts looking unreliable even though the real issue is duplicate peer identity.
So the iPhone gets:
- Its own private key
- Its own public key
- Its own VPN IP address
- Its own
[Peer]block on the server
My WireGuard subnet is 10.0.0.0/24. The laptop was already using 10.0.0.2/32, so the iPhone got 10.0.0.3/32.
Check the current tunnel
First, check the existing peers:
sudo wg show
sudo wg show wg0 allowed-ips
The useful part is the allowed ips list. Existing peers look like this, with real public keys in place of the placeholders:
<laptop-public-key> 10.0.0.2/32
The iPhone needs a different address:
<iphone-public-key> 10.0.0.3/32
Those are private VPN addresses. They are not the server’s public internet address.
Generate iPhone keys
On the server, create a client directory and generate a key pair for the phone:
sudo mkdir -p /etc/wireguard/clients
sudo chmod 700 /etc/wireguard/clients
sudo sh -c 'umask 077; wg genkey > /etc/wireguard/clients/iphone.key'
sudo sh -c 'wg pubkey < /etc/wireguard/clients/iphone.key > /etc/wireguard/clients/iphone.pub'
The private key stays on the server long enough to build the phone config, then it is imported into the WireGuard app.
The public key is what the server uses to recognise the iPhone:
sudo cat /etc/wireguard/clients/iphone.pub
Add the phone to the server
Append a new peer block to /etc/wireguard/wg0.conf:
IPHONE_PUB="$(sudo cat /etc/wireguard/clients/iphone.pub)"
sudo tee -a /etc/wireguard/wg0.conf >/dev/null <<EOF
[Peer]
# iPhone
PublicKey = $IPHONE_PUB
AllowedIPs = 10.0.0.3/32
EOF
Then apply the peer to the running tunnel without dropping the current connection:
sudo wg set wg0 peer "$IPHONE_PUB" allowed-ips 10.0.0.3/32
Check it:
sudo wg show wg0 allowed-ips
At this point the server should know about the laptop and the iPhone as separate peers.
Build the iPhone config
The iPhone needs a client config. This is the file the WireGuard app imports.
The commands below read the key values from the server, so there is no need to copy them by hand. The only value to set manually is the public endpoint that reaches the WireGuard UDP port.
Get the server’s public IP if you do not already use a DNS name:
curl -4 ifconfig.me
Then set the endpoint:
WG_ENDPOINT="<server-public-ip-or-dns-name>:51820"
WireGuard uses UDP. A normal HTTP tunnel hostname is not automatically a WireGuard endpoint. Use the public IP or DNS name that actually reaches UDP port 51820 on the server.
Create the iPhone config:
SERVER_PUBLIC_KEY="$(sudo wg show wg0 public-key)"
IPHONE_PRIVATE_KEY="$(sudo cat /etc/wireguard/clients/iphone.key)"
sudo sh -c 'umask 077; cat > /etc/wireguard/clients/iphone.conf' <<EOF
[Interface]
PrivateKey = ${IPHONE_PRIVATE_KEY}
Address = 10.0.0.3/32
DNS = 1.1.1.1
[Peer]
PublicKey = ${SERVER_PUBLIC_KEY}
Endpoint = ${WG_ENDPOINT}
AllowedIPs = 10.0.0.0/24
PersistentKeepalive = 25
EOF
That AllowedIPs line is intentional:
AllowedIPs = 10.0.0.0/24
It means the iPhone only sends traffic for the VPN subnet through WireGuard. That was enough for server access.
If the goal is to route all iPhone internet traffic through the server, the line changes to:
AllowedIPs = 0.0.0.0/0, ::/0
I would not start there for a simple server-access setup. Full-tunnel VPN needs the server’s forwarding, NAT, firewall, and DNS setup to be right. For this use case, the smaller route is cleaner.
Import it with a QR code
Install the QR tool:
sudo apt update
sudo apt install -y qrencode
Generate the QR in the terminal:
sudo sh -c 'qrencode -t ansiutf8 < /etc/wireguard/clients/iphone.conf'
The sudo sh -c wrapper is important.
This version can fail:
sudo qrencode -t ansiutf8 < /etc/wireguard/clients/iphone.conf
The problem is the < /etc/wireguard/clients/iphone.conf part. The shell opens the file before sudo runs, so a protected config file can throw Permission denied.
Small shell detail, easy to miss.
On the iPhone:
- Open WireGuard
- Tap
+ - Choose
Create from QR code - Scan the terminal QR
- Approve the VPN profile
- Turn the tunnel on
Verify the handshake
Back on the server:
sudo wg show
The iPhone peer should show a recent handshake:
peer: <iphone-public-key>
endpoint: <iphone-current-network>:<port>
allowed ips: 10.0.0.3/32
latest handshake: <recent time>
transfer: <traffic counters>
No handshake usually means one of these needs checking:
- The endpoint is not reaching the server
- UDP port
51820is not forwarded or allowed - The server public key in the phone config is wrong
- The iPhone peer public key in
wg0.confis wrong - The iPhone is using an IP already assigned to another peer
Test access
Find the server’s WireGuard address:
ip -4 addr show wg0
In this setup the server is 10.0.0.1, so SSH over the VPN looks like:
ssh <user>@10.0.0.1
For a web service bound to the server, test the VPN address in Safari:
http://10.0.0.1
If the tunnel handshakes but the service does not load, WireGuard is probably working. At that point I would check the service binding, firewall rules, and whether the app is only listening on 127.0.0.1.

Once the tunnel is up, the phone behaves like another device on the private VPN network. Photo: Jon “ShakataGaNai” Davis, CC BY-SA 3.0, via Wikimedia Commons.
The result
The laptop remains one peer. The iPhone is a second peer. Both can connect without overwriting each other’s endpoint.
That is the main thing to remember with WireGuard: peers are identities, and every device gets its own.