How to Set Up WireGuard on Docker: A Beginner-Friendly Guide to Private Remote Access for Your Homelab
Learn how to set up WireGuard on Docker with wg-easy, forward the right port, create clients, and securely reach your homelab from anywhere.
Author
David Okonkwo
FTC disclosure: This article contains affiliate links. If you purchase through these links, we may earn a commission at no additional cost to you.
Key Takeaways
- If you want secure remote access to your homelab without publishing half your dashboard stack to the internet, WireGuard is one of the cleanest ways to do it.
- For beginners,
wg-easyis the most approachable Docker-based WireGuard setup because it gives you a web UI, QR codes, and simpler client management. - Forward UDP 51820 to your Docker host, but keep the web UI port private unless you are deliberately protecting it behind a reverse proxy and additional authentication.
- A working setup is not just "container is running". You should also verify the listening port, the handshake, and that the client can actually reach your internal services.
- Most failed WireGuard setups come down to four things: bad DNS, missing router port forwarding, incorrect allowed IPs, or exposing the wrong port.
If you have ever wanted to reach your homelab from outside your house, you have probably hit the same fork in the road a lot of people do. You can expose services one by one and keep chasing reverse proxy rules. You can rely on whatever remote-access feature a single app happens to support. Or you can build one secure tunnel back into your network and stop solving the same problem five different ways.
That is why WireGuard matters. Think of it like giving yourself a private hallway into your home network instead of leaving a bunch of side doors unlocked. Once the tunnel is up, your phone or laptop behaves like it has a safe route back to your lab, whether you are on hotel Wi-Fi, a coffee shop network, or your phone's hotspot.
In this guide, we are going to set up WireGuard on Docker using wg-easy, which is the easiest beginner path I recommend right now. You will end up with a running VPN container, a client profile you can scan into the WireGuard mobile app, and a checklist to verify that the tunnel actually works.
If you want the protocol background first, read the official WireGuard Quick Start. If you want the project docs for the container we are using, keep the official wg-easy Getting Started guide handy. I will also reference the official Docker Compose documentation where it helps.
Why this matters before we touch any commands
A WireGuard setup is not only about privacy in the abstract. In a homelab, it solves very practical problems:
- You can reach dashboards, SSH, file shares, and internal services without opening each one publicly.
- You reduce the attack surface compared with exposing multiple web apps directly.
- You get one repeatable access method for phones, laptops, and tablets.
- You stop depending on whether a particular service has good external auth built in.
Running it in Docker matters too. Docker turns the VPN server into one stack you can version, move, update, back up, and monitor like the rest of your homelab. It is the difference between scribbling a setup on the back of a receipt and having it in a labeled box where you can find it again later.
What you need before you begin
You do not need enterprise gear for this. You do need a few basic pieces in place:
- A Linux host that already runs Docker and Docker Compose
- A public IP or DNS name that points to your home connection
- Router access so you can forward a UDP port
- A phone or laptop with the WireGuard client installed
I also recommend a few pieces of supporting hardware if this VPN server is going to stay on all the time:
- A small dedicated Docker box like a fanless N100 mini PC with 2.5GbE
- A compact travel client for testing or road use, such as a GL.iNet travel router with WireGuard support
- A battery backup like an APC Back-UPS 1500VA so your remote access does not disappear the first time your power flickers
Step 1 - Verify your Docker host is ready
Why this matters
Before we deploy anything, we want to prove the host is already capable of running containers. This sounds obvious, but it saves you from debugging a VPN stack when the real problem is that Docker is not installed correctly or Compose is missing.
Run these commands on your Docker host:
docker --version
docker compose version
uname -m
You should see Docker installed, Compose available, and a supported architecture such as x86_64 or aarch64.
If Docker is not installed yet, follow the official Docker installation instructions for your distro. The wg-easy docs assume Docker Compose is already available, and that is the path we are using here.
What could go wrong
docker: command not foundmeans Docker is not installed yet.docker composefails butdocker-composeworks - you are probably on an older Compose package. Update if you can.- Rootless Docker can work for many stacks, but for a first WireGuard deployment I recommend a normal Docker install so you do not stack networking complexity on top of VPN complexity.
Step 2 - Create a working directory for WireGuard
Why this matters
We want the VPN stack in its own folder so updates, backups, and troubleshooting stay tidy. When you come back in three months, you should not have to play detective.
sudo -S -p '' mkdir -p /opt/wg-easy
cd /opt/wg-easy
You can use another path if you prefer, but keep it consistent with the rest of your homelab layout.
Step 3 - Write the Docker Compose file
Why this matters
This file defines the VPN service, its ports, the capabilities it needs, and the initial setup values that let us skip a manual first-run wizard. That is useful because it makes the deployment reproducible.
Create docker-compose.yml with the following content:
volumes:
etc_wireguard:
services:
wg-easy:
image: ghcr.io/wg-easy/wg-easy:15
container_name: wg-easy
restart: unless-stopped
cap_add:
- NET_ADMIN
- SYS_MODULE
environment:
- INIT_ENABLED=true
- INIT_USERNAME=admin
- INIT_PASSWORD=CHOOSE_A_LONG_UNIQUE_PASSWORD
- INIT_HOST=vpn.example.com
- INIT_PORT=51820
- INIT_DNS=1.1.1.1,1.0.0.1
- INSECURE=true
volumes:
- etc_wireguard:/etc/wireguard
- /lib/modules:/lib/modules:ro
ports:
- "51820:51820/udp"
- "51821:51821/tcp"
sysctls:
- net.ipv4.ip_forward=1
- net.ipv4.conf.all.src_valid_mark=1
- net.ipv6.conf.all.disable_ipv6=0
- net.ipv6.conf.all.forwarding=1
- net.ipv6.conf.default.forwarding=1
Replace these values before you start the container:
CHOOSE_A_LONG_UNIQUE_PASSWORDwith a real admin password for the web UIvpn.example.comwith your public DNS name or home public IP
The image tag matters. The current wg-easy documentation recommends pinning to the latest major version such as :15 instead of using latest, because latest can lag on an older release line.
What the important parts do
NET_ADMINlets the container manage the WireGuard interface and routing rules./lib/modules:/lib/modules:rogives the container read access to kernel modules when needed.51820/udpis the actual WireGuard tunnel port.51821/tcpis thewg-easyadmin UI.INIT_*variables perform the initial setup automatically on first boot.
Important safety note
Do not blindly forward 51821/tcp from your router to the internet. For a beginner setup, you usually want to forward only 51820/udp and keep the web UI reachable from your LAN only.
That single habit prevents a lot of unnecessary risk.
Step 4 - Start the stack
Why this matters
Now we turn the Compose definition into a running service. This is the point where Docker, kernel support, and your configuration all meet, so logs matter.
cd /opt/wg-easy
sudo -S -p '' docker compose up -d
sudo -S -p '' docker compose ps
sudo -S -p '' docker compose logs --tail=100
You want to see the service running without repeated crash loops.
The wg-easy documentation specifically recommends using docker compose up and docker compose down rather than start and stop for this stack. That is worth following.
Quick health checks
Run these commands after the container starts:
sudo -S -p '' ss -ulnp | grep 51820
sudo -S -p '' ss -tlnp | grep 51821
sudo -S -p '' docker exec wg-easy wg show
At this stage, wg show may not list any peers yet. That is fine. The useful part is confirming the service is alive and listening.
What could go wrong
- If the container exits immediately, inspect
docker compose logsfirst. - If the image pulls but the service fails to start, confirm the host kernel supports WireGuard.
- If the UI never comes up, a typo in one of the
INIT_*variables is a common cause.
Step 5 - Allow the correct port through your firewall and router
Why this matters
This is where many first-time setups fail. WireGuard can be installed perfectly and still be unreachable because the path into your network is blocked.
If you use UFW on the Docker host, allow the UDP tunnel port:
sudo -S -p '' ufw allow 51820/udp
sudo -S -p '' ufw status
If you use another firewall tool, create the equivalent allow rule.
Then log in to your router and forward:
- External port:
51820 - Protocol:
UDP - Destination: your Docker host's LAN IP
- Destination port:
51820
Do not forward 51821/tcp unless you know exactly why you need remote UI access and you are protecting it properly.
If firewall rules are still fuzzy, my guides on Homelab Firewall Rules and VLANs for Homelabs Explained will help you make sense of the traffic path.
Step 6 - Open the web UI and create your first client
Why this matters
A VPN server without a client profile is like installing a front door and forgetting the key. We now need a peer that your phone or laptop can actually use.
From a browser on your LAN, open:
http://YOUR-DOCKER-HOST-IP:51821
Log in with the admin username and password you set in the Compose file.
From there:
- Create a new client
- Give it a meaningful name like
iphone,laptop, ortravel-macbook - Download the configuration file or scan the QR code into the WireGuard mobile app
Why wg-easy is good for beginners
The lower-level linuxserver/wireguard image is powerful, but it asks more of you up front. wg-easy gives you a gentler ramp - management UI, QR codes, and less manual client handling. For a first deployment, that tradeoff is worth it.
If you later outgrow it, you can move to a more hands-on stack with a better sense of what WireGuard is actually doing.
Step 7 - Import the client and connect
Why this matters
This is where the setup becomes real. A running container is nice. A successful remote tunnel is the goal.
On your phone or laptop:
- Install the WireGuard app
- Import the generated configuration file or scan the QR code
- Enable the tunnel
Then test in this order:
- Can the client connect without error?
- Does
wg showon the server display a recent handshake? - Can the client reach an internal IP, such as your router, NAS, or Proxmox node?
- Can the client reach an internal hostname if you configured DNS correctly?
Back on the Docker host, verify the handshake:
sudo docker exec wg-easy wg show
You want to see a latest handshake timestamp for the client.
A simple validation path
Start with something boring:
- Ping your router's LAN IP
- Open your Proxmox web UI on its internal address
- SSH to a host that is only reachable from your home network
Boring tests are good here. They tell you whether the tunnel really behaves like a private hallway back into your lab.
If you already expose internal services through a reverse proxy, my Nginx Proxy Manager on Docker guide can help you decide what should stay internal-only and what belongs behind HTTPS.
Step 8 - Lock down the setup after the first successful test
Why this matters
The first working connection is not the finish line. It is the moment to tighten the setup so it stays safe and maintainable.
Do these next:
- Remove or comment out the
INIT_PASSWORDline after first setup if you do not need unattended re-creation. - Back up your Compose file and the persistent WireGuard data.
- Keep the admin UI private to your LAN.
- Add the stack to your normal Docker backup routine.
- Update the container on your regular maintenance cycle.
Update commands are straightforward:
cd /opt/wg-easy
sudo -S -p '' docker compose pull
sudo -S -p '' docker compose up -d
And if you are building out the rest of your host securely, my Docker Security Hardening for Homelabs article is a good next stop.
Common mistakes
1. Forwarding the wrong port
The most common beginner error is forwarding the admin UI port instead of the WireGuard UDP port. The tunnel needs 51820/udp. The admin UI is a separate web interface.
2. Using the wrong public endpoint
If INIT_HOST points to an old IP, a private IP, or a DNS record that no longer matches your home connection, clients will try to phone the wrong number.
3. Broken DNS inside the tunnel
Sometimes the tunnel connects, but internal hostnames do not resolve. That usually means the client can reach the VPN, but it is using the wrong DNS server. Set INIT_DNS to something intentional, and if you run internal DNS like Pi-hole or AdGuard Home, consider pointing the tunnel there.
4. Allowed IPs confusion
Allowed IPs tell the client what traffic should go through the tunnel. If these are too narrow, you connect but cannot reach the internal network you care about. If they are too broad, you may accidentally send all internet traffic through the tunnel when you only wanted homelab access.
5. Double NAT or ISP modem issues
If your router is behind another router or ISP gateway, the port forward may not actually reach your Docker host. In that case, you may need bridge mode, upstream forwarding, or a different remote-access strategy.
6. Treating "container is running" as the only test
A running container is only step one. Always verify the listening port, the handshake, and actual access to a real internal service.
Should you use wg-easy or a lower-level image?
For beginners, I recommend wg-easy first.
Use wg-easy if:
- You want the fastest path to a working setup
- You prefer a web UI for client management
- You want QR codes for mobile clients
- You are learning WireGuard and do not want to hand-edit every peer config
Use a lower-level image like linuxserver/wireguard if:
- You want more manual control
- You already understand WireGuard peers and routing well
- You are comfortable managing clients without a UI
- You want to integrate the setup into a more opinionated networking layout
If you are still choosing the protocol itself, my WireGuard vs OpenVPN for Homelabs comparison will help you decide why WireGuard is usually the simpler call for home use.
FAQ
Is running WireGuard in Docker slower than running it directly on the host?
In most homelab use cases, the performance difference is small enough that ease of management matters more. If you are chasing every last bit of throughput on very fast connections, a host-native install can be worth testing, but Docker is absolutely practical for typical remote-access use.
Do I need a domain name for this setup?
No. You can use a public IP. A domain name is simply easier to remember and easier to update cleanly if your home IP changes.
Should I route all my internet traffic through the tunnel?
Not necessarily. Many homelab users only need secure access to internal services. Full-tunnel routing is useful on untrusted Wi-Fi, but split-tunnel access is often simpler and faster when your goal is only reaching your lab.
Can I use this with Pi-hole or AdGuard Home?
Yes. In fact, pairing WireGuard with internal DNS is one of the nicest upgrades you can make, because remote devices can use the same trusted name resolution as they do at home.
What if my handshake works but I still cannot reach anything?
That usually points to routing, allowed IPs, or firewall rules. Start by checking wg show, then confirm the client received the expected tunnel IP, then test a direct internal IP before worrying about hostnames.
What to learn next
Once you have WireGuard working, you have a solid private access layer. The next useful skills are usually:
- Clean internal DNS so your services resolve the same way at home and away
- Better firewall policy between VLANs and service networks
- Reverse proxy design for the apps you do want accessible over HTTPS
- Docker hardening so your host is not carrying unnecessary risk
A good next reading path on HomelabAddiction is:
- WireGuard vs OpenVPN for Homelabs
- Homelab Firewall Rules
- How to Set Up Nginx Proxy Manager on Docker
- Docker Security Hardening for Homelabs
The nice thing about this setup is that it scales with you. You can start with one phone and one laptop today, and later grow into a cleaner internal network, better DNS, and tighter access control without throwing the whole thing away.
That is what makes WireGuard such a good first serious remote-access tool for a homelab. It is not flashy. It is just dependable - and in a homelab, dependable wins.
