Set up a WireGuard VPN container using a ready-made Docker image¶
Date: 2025-06-23
raspberrypi.com
wireguard.com
docker.com
1. 📁 Create a working directory¶
mkdir ~/vpn && cd ~/vpn
2. 🐳 Create the WireGuard container¶
Let’s use the kylemanna/openvpn image, which works well on Raspberry Pi.
For Raspberry Pi (ARM), you can use a compatible fork like dperson/openvpn-client or pivpn/pivpn. But we’ll go with kylemanna/openvpn for this example.
docker pull lscr.io/linuxserver/wireguard:latest
3. Create a config directory:¶
mkdir -p ~/wireguard/config
4. 🔧 Create docker-compose.yml:¶
version: '3.8'
services:
wireguard:
image: lscr.io/linuxserver/wireguard:latest
container_name: wireguard
cap_add:
- NET_ADMIN
- SYS_MODULE
environment:
- PUID=1000
- PGID=1000
- TZ=Europe/London
- SERVERURL=your.domain.com # Use Dynu DNS or public IP
- SERVERPORT=51820
- PEERS=1
- PEERDNS=auto
- INTERNAL_SUBNET=10.13.13.0
volumes:
- ./config:/config
- /lib/modules:/lib/modules
ports:
- 51820:51820/udp
sysctls:
- net.ipv4.conf.all.src_valid_mark=1
restart: unless-stopped
Replace your.domain.com with your DDNS or external IP.
5. Start the container:¶
cd ~/wireguard
docker compose up -d
Get the client config: Once running, check the ~/wireguard/config/peer1/peer1.conf file — it’s your WireGuard config for the first peer. You can scan the QR code using the WireGuard mobile app too.
✅ 6. Check if the VPN config was generated¶
The PEERS=1 environment variable you used means WireGuard should auto-generate one client configuration.
Check if the config was created inside the container volume:
ls ~/docker/wireguard/config/peer1
You should see a file like:
peer1.conf
✅ 7. Transfer the VPN config to your Mac¶
You can do this in one of several ways:
🟢 A. Display it in the terminal (easy and quick):
nano ~/docker/wireguard/config/peer1/peer1.conf
Copy the whole text into a new file on your Mac:
Open TextEdit Paste contents Save as: peer1.conf Then use this config in the WireGuard app.
[Interface]
Address = 10.13.13.2
PrivateKey = 3en7YcU+VBICIXVmGZw13BRx3YmYcX3yqESk2A=
ListenPort = 51820
DNS = 10.13.13.1
[Peer]
PublicKey = lxKATfac6Og/Na4gRZHxEeDlstzpfmR5Cn7k0k=
PresharedKey = vEO8WWgHdtecQaH5zIo6WrqVCwHRFoZaL79Jdo=
Endpoint = your.domain.com:51820
AllowedIPs = 0.0.0.0/0, ::/0
8. Install WireGuard on Your Mac 💻¶
Download WireGuard from the official site:
https://apps.apple.com/us/app/wireguard/id1451685025
Open the app → Click "+" → Import tunnel from file → select peer1.conf
🛠️ Steps to Add Your Phone as a WireGuard Peer 📲¶
- On the Pi using:
wg genkey | tee phone_private.key | wg pubkey > phone_public.key
- Create the Phone's Client Config
Example (can be scanned into the WireGuard app as a QR code later):
[Interface]
PrivateKey = <PHONE_PRIVATE_KEY>
Address = 10.0.0.3/32
DNS = 1.1.1.1
[Peer]
PublicKey = <RASPBERRY_PI_PUBLIC_KEY>
Endpoint = your-public-ip-or-dynamic-dns-name:51820
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25
- Add Phone as a Peer on the Pi
Edit /etc/wireguard/wg0.conf
on your Raspberry Pi and add:
[Peer]
PublicKey = <PHONE_PUBLIC_KEY>
AllowedIPs = 10.0.0.3/32
Then restart WireGuard on the Pi:
docker restart wireguard
✅ Final Step: Import Config into Your Phone¶
Install the QR encode tool
sudo apt update
sudo apt install qrencode
If you generated the config on your Pi, use QR code to import it into the WireGuard mobile app:
qrencode -t ansiutf8 < phone.conf
or
qrencode -o phone.png < phone.conf
Then scan the QR code with the WireGuard app.
WireGuard: Add a New Peer (Client) Guide¶
This guide explains how to add a new peer (client) to your existing WireGuard VPN setup on a Raspberry Pi using Docker.
✅ Steps to Add a New WireGuard Peer (Client)¶
1. Generate Key Pair for the Client¶
Run this on the Pi (or any device):
wg genkey | tee client_private.key | wg pubkey > client_public.key
2. Create the Client Config File¶
Use an existing config (e.g. peer1.conf
) as a template and modify:
[Interface]
Address = 10.13.13.X/32 # Unique IP for this client
PrivateKey = <NEW_PRIVATE_KEY>
DNS = 10.13.13.1
[Peer]
PublicKey = <SERVER_PUBLIC_KEY>
PresharedKey = <PRESHARED_KEY> # (Optional, but recommended)
Endpoint = your.domain.name:51820
AllowedIPs = 0.0.0.0/0, ::/0
PersistentKeepalive = 25 # Useful for mobile clients
3. Update Server Config (wg0.conf
)¶
Append a new [Peer]
block to your server config:
[Peer]
PublicKey = <NEW_CLIENT_PUBLIC_KEY>
PresharedKey = <PRESHARED_KEY> # (Same one if shared)
AllowedIPs = 10.13.13.X/32
4. Restart WireGuard¶
If using Docker:
docker restart wireguard
Or native:
sudo wg-quick down wg0 && sudo wg-quick up wg0
5. Generate QR Code (Optional, for mobile)¶
qrencode -t ansiutf8 < client.conf
Or generate PNG:
qrencode -o client.png < client.conf
🔁 Summary for Each New Peer:¶
- Unique IP (
10.13.13.X
) - Unique private key
- Add public key to server
- Use existing preshared key (or new one)
🧠 Useful Commands¶
# Check WireGuard status inside container
docker exec -it wireguard wg show
# View logs
docker logs wireguard
# Restart container
docker restart wireguard
Example settings for wg0.conf and peers¶
nano wg_confs/wg0.conf¶
[Interface]
Address = 10.13.13.1
ListenPort = 51820
PrivateKey = Rhq0A/I3yCk+Zh4XyZ7rSc8iaH6cF0MI+WaJXg=
# Enable NAT and forwarding
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth+ -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth+ -j MASQUERADE
# === Peer 1: MacBook ===
[Peer]
PublicKey = X+Sy45dS03ZA6Qz9wmziJCfCcgW2PhBC6zgvkk=
PresharedKey = vEO8WWgHdtecQaH5zIo6WrqVCwHRFoZaL79Jdo=
AllowedIPs = 10.13.13.2/32
# === Peer 2: iPhone ===
[Peer]
PublicKey = NtOzvjLy17UeIv2KeWHWoDZPdXPQLtzmYfUbyM=
PresharedKey = vEO8WWgHdtecQaH5zIo6WrqVCwHRFoZaL79Jdo=
AllowedIPs = 10.13.13.3/32
nano peer1/peer1.conf¶
[Interface]
Address = 10.13.13.2
PrivateKey = 3en7YcU+VBICIXVmGZw13BRx3YmYcX3yqESk2A=
ListenPort = 51820
DNS = 10.13.13.1
[Peer]
PublicKey = lxKATfac6Og/Na4gRZHxEeDlstzpfmR5Cn7k0k=
PresharedKey = vEO8WWgHdtecQaH5zIo6WrqVCwHRFoZaL79Jdo=
Endpoint = 84.65.97.18:51820
AllowedIPs = 0.0.0.0/0, ::/0
nano iphone15/iphone15.conf¶
[Interface]
Address = 10.13.13.3
PrivateKey = kVpsSAy4GTUf9XHezplE++zc0SM3EKFJ0e5IFY=
ListenPort = 51820
DNS = 10.13.13.1
[Peer]
PublicKey = lxKATfac6Og/Na4gRZHxEeDlstzpfmR5Cn7k0k=
PresharedKey = vEO8WWgHdtecQaH5zIo6WrqVCwHRFoZaL79Jdo=
Endpoint = 84.65.97.18:51820
AllowedIPs = 0.0.0.0/0, ::/0
Author¶
János Rostás & ChatGPT
Electronic and Computer Engineering Student | Raspberry Pi Enthusiast | janosrostas.co.uk
![]() |