How to Set Up a WireGuard VPN Server on Raspberry Pi Using Docker
Running your own VPN server at home gives you secure, encrypted access to your local network from anywhere in the world. WireGuard is a modern, high-performance VPN protocol that is lightweight enough to run perfectly on a Raspberry Pi.
In this guide, we will use the linuxserver/wireguard Docker image to get a WireGuard server running quickly and reliably.
What is WireGuard?
WireGuard is a fast, modern VPN tunnel that uses state-of-the-art cryptography. Compared to OpenVPN or IPSec, WireGuard has a much smaller codebase, better performance, and simpler configuration. It is built into the Linux kernel and is ideal for low-powered devices like the Raspberry Pi.
Prerequisites
Before starting, make sure you have:
- A Raspberry Pi (3B+ or newer) running Raspberry Pi OS
- Docker and Docker Compose installed (see our Docker setup guide)
- A static local IP address on your Pi
- Access to your router's admin panel for port forwarding
- Your public IP address or a dynamic DNS hostname
Step 1: Create a Project Directory
mkdir ~/wireguard && cd ~/wireguard
Step 2: Create the Docker Compose File
Create a docker-compose.yml file:
nano docker-compose.yml
Paste the following configuration:
services:
wireguard:
image: linuxserver/wireguard
container_name: wireguard
cap_add:
- NET_ADMIN
- SYS_MODULE
environment:
- PUID=1000
- PGID=1000
- TZ=America/New_York
- SERVERURL=auto
- SERVERPORT=51820
- PEERS=phone,laptop,tablet
- PEERDNS=auto
- INTERNAL_SUBNET=10.13.13.0
- ALLOWEDIPS=0.0.0.0/0
volumes:
- ./config:/config
- /lib/modules:/lib/modules
ports:
- 51820:51820/udp
sysctls:
- net.ipv4.conf.all.src_valid_mark=1
restart: unless-stopped
Important notes about this configuration:
- SERVERURL: Set this to your public IP or dynamic DNS hostname. Using
autowill attempt to detect it automatically. - PEERS: A comma-separated list of client names. Each one generates a separate config file.
- INTERNAL_SUBNET: The private subnet WireGuard uses internally.
- cap_add: WireGuard requires
NET_ADMINandSYS_MODULEcapabilities to create network interfaces. - sysctls: Required for proper packet routing.
Step 3: Start WireGuard
docker-compose up -d
Wait a moment for the container to generate all peer configurations. You can watch the logs:
docker logs -f wireguard
Step 4: Retrieve Client Configurations
The container automatically generates config files for each peer you defined. Find them in the config directory:
ls ~/wireguard/config/peer_phone/
ls ~/wireguard/config/peer_laptop/
ls ~/wireguard/config/peer_tablet/
Each folder contains a peer_phone.conf file (or similar) and a QR code PNG image.
To display the QR code in your terminal for easy mobile setup:
docker exec -it wireguard /app/show-peer phone
This prints a QR code that you can scan directly with the WireGuard mobile app.
Step 5: Connect from Your Devices
On a Phone (iOS or Android)
- Install the WireGuard app from the App Store or Google Play.
- Tap the + button and select Create from QR code.
- Scan the QR code displayed in the terminal from Step 4.
- Toggle the tunnel on. You are now connected.
On a Laptop (Windows, macOS, or Linux)
- Install the WireGuard client from wireguard.com/install.
- Copy the
.conffile from~/wireguard/config/peer_laptop/to your laptop. - Import the tunnel configuration file in the WireGuard client.
- Activate the tunnel.
Step 6: Configure Port Forwarding on Your Router
For external access, you must forward UDP port 51820 on your router to your Raspberry Pi's local IP address.
- Log into your router's admin panel (typically at
192.168.1.1). - Find the Port Forwarding section.
- Create a new rule:
- Protocol: UDP
- External Port: 51820
- Internal IP: Your Pi's local IP (e.g.,
192.168.1.50) - Internal Port: 51820
- Save and apply the rule.
If your ISP gives you a dynamic public IP, consider setting up a dynamic DNS service like DuckDNS or No-IP and using that hostname as your SERVERURL.
Firewall Notes
If you are running ufw on your Pi, allow the WireGuard port:
sudo ufw allow 51820/udp
Adding More Peers Later
To add new clients after the initial setup, update the PEERS environment variable in your docker-compose.yml and recreate the container:
docker-compose down
docker-compose up -d
New peer configs will be generated automatically without affecting existing ones.
Troubleshooting
- Connection times out: Verify port forwarding is configured correctly. Test from outside your home network (e.g., using mobile data).
- Handshake but no traffic: Check that
ALLOWEDIPSis set to0.0.0.0/0for full tunnel, or your specific subnet for split tunnel. - Container won't start: Ensure
/lib/modulesis mounted and thewireguardkernel module is available. Runsudo modprobe wireguardon the host if needed. - Check logs: Run
docker logs wireguardto see detailed output from the container. - DNS not resolving: Make sure
PEERDNSis set correctly. You can point it to your Pi-hole if you have one running.
Conclusion
With WireGuard running on your Raspberry Pi via Docker, you have a lightweight, high-performance VPN server that lets you securely access your home network from anywhere. The linuxserver/wireguard image makes the setup straightforward, handling key generation and peer configuration automatically.