How to Set Up a WireGuard VPN Server: Step-by-Step Guide

WireGuard is the VPN protocol that changed everything. It runs in kernel space on Linux, uses ~4,000 lines of code (vs OpenVPN’s 400,000+), and delivers 2-3x better performance with lower CPU and battery usage. Since its inclusion in the Linux kernel (5.6+), it’s become the foundation for every modern self-hosted VPN tool.

This guide covers three ways to set up WireGuard, from manual to fully managed:

  1. Manual WireGuard on Ubuntu — full control, learn the internals
  2. WG-Easy with Docker — web UI, five-minute setup
  3. NetBird — mesh networking, zero-trust, and WireGuard without the config files

Start with whichever matches your needs. If you’re learning, go manual. If you need a working VPN fast, go WG-Easy. If you’re building for a team, skip straight to NetBird.

Prerequisites

You’ll need:

  • A server with a public IP address (VPS, cloud instance, or home server with port forwarding)
  • Ubuntu 22.04 or newer (other Linux distros work, but commands may differ)
  • Root or sudo access
  • UDP port 51820 open in your firewall

Where to host: Any VPS provider works. If you want a free option, Oracle Cloud’s free tier gives you a VM with a public IP at no cost — more than enough for a WireGuard server.

Option 1: Manual WireGuard Setup on Ubuntu

This is the “learn how it works” approach. You’ll understand every piece of the puzzle.

Step 1: Install WireGuard

sudo apt update && sudo apt install wireguard -y

WireGuard is included in the default Ubuntu repositories since 22.04. The kernel module loads automatically.

Step 2: Generate Server Keys

wg genkey | tee /etc/wireguard/server_private.key | wg pubkey > /etc/wireguard/server_public.key
chmod 600 /etc/wireguard/server_private.key

This generates a private/public key pair. The private key never leaves the server.

Step 3: Create Server Configuration

sudo nano /etc/wireguard/wg0.conf
[Interface]

PrivateKey = <paste-server-private-key>

Address = 10.0.0.1/24

ListenPort = 51820

PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

[Peer]

PublicKey = <client-public-key>

AllowedIPs = 10.0.0.2/32

Replace eth0 with your server’s main network interface (check with ip route | grep default).

Step 4: Enable IP Forwarding

echo "net.ipv4.ip_forward=1" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

Step 5: Start WireGuard

sudo systemctl enable wg-quick@wg0
sudo systemctl start wg-quick@wg0

Verify it’s running:

sudo wg show

You should see the interface with your public key, listening port, and any connected peers.

Step 6: Generate Client Keys and Config

On your client machine (or on the server, then transfer the config):

wg genkey | tee client_private.key | wg pubkey > client_public.key

Create the client config file:

[Interface]

PrivateKey = <client-private-key>

Address = 10.0.0.2/24

DNS = 1.1.1.1

[Peer]

PublicKey = <server-public-key>

Endpoint = your-server-ip:51820

AllowedIPs = 0.0.0.0/0

PersistentKeepalive = 25

Add the client’s public key to the server’s wg0.conf as a [Peer] block (shown in Step 3), then reload:

sudo systemctl restart wg-quick@wg0

Step 7: Connect

Import the client config into the WireGuard app (available for Windows, macOS, iOS, Android, Linux) and activate. You should see a handshake in sudo wg show on the server.

Manual Setup: Pros and Cons

Pros: Full understanding of the protocol. No dependencies. Minimal resource usage. Total control.

Cons: Adding peers means editing config files and restarting. No web UI. No access policies. No peer discovery. Managing 10+ peers this way becomes tedious fast.

Option 2: WG-Easy with Docker (Recommended for Simple Setups)

WG-Easy wraps WireGuard in a Docker container with a clean web UI for managing peers. It’s the sweet spot between manual setup and full mesh networking.

Step 1: Install Docker

If you don’t have Docker yet:

curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER

For a deeper understanding of Docker and Docker Compose, check out our Docker deep dive.

Step 2: Run WG-Easy

docker run -d \

--name wg-easy \

-e LANG=en \

-e WG_HOST=your-server-ip-or-domain \

-e PASSWORD_HASH='<your-bcrypt-hash>' \

-e WG_DEFAULT_DNS=1.1.1.1 \

-v ~/.wg-easy:/etc/wireguard \

-p 51820:51820/udp \

-p 51821:51821/tcp \

--cap-add=NET_ADMIN \

--cap-add=SYS_MODULE \

--sysctl="net.ipv4.conf.all.src_valid_mark=1" \

--sysctl="net.ipv4.ip_forward=1" \

--restart unless-stopped \

ghcr.io/wg-easy/wg-easy

Generate a password hash with:

docker run ghcr.io/wg-easy/wg-easy wgpw 'YOUR_PASSWORD'

Step 3: Access the Web UI

Open http://your-server-ip:51821 in your browser. Log in with the password you set.

From here, you can:

  • Create new clients with one click
  • Download client configs or scan QR codes
  • See connection status for each peer
  • Enable/disable peers

That’s it. You have a production-ready WireGuard VPN with a management interface.

WG-Easy: Pros and Cons

Pros: Five-minute setup. Web UI for managing peers. QR codes for mobile clients. Docker makes deployment and updates trivial.

Cons: Still client-server (hub-and-spoke). No mesh networking. No access policies beyond “connected or not.” Not ideal for teams that need identity-based access control.

Option 3: NetBird (When You Need More Than a Tunnel)

If you’ve read through the manual setup and WG-Easy sections, you’ll notice a pattern: as your needs grow beyond “one tunnel, a few peers,” the configuration overhead grows with it. Access policies, peer management, identity integration, multi-site connectivity — none of that comes free with raw WireGuard or WG-Easy.

NetBird handles all of this. It uses WireGuard under the hood, but abstracts away the pain: key generation, IP assignment, NAT traversal, peer discovery, and access policies. You get WireGuard’s performance with a management layer built for teams.

Quick Start (Cloud — Free Tier)

  1. Sign up at netbird.io (no credit card required)
  2. Install the agent on your first device:
curl -fsSL https://pkgs.netbird.io/install.sh | sh
sudo netbird up
  1. Authenticate in the browser when prompted
  2. Install on a second device and repeat
  3. Both devices can now reach each other directly by NetBird IP or hostname

Total time: under five minutes. Both devices are connected peer-to-peer through WireGuard, with NAT traversal handled automatically.

Why Choose NetBird Over Manual WireGuard

Feature Manual WireGuard WG-Easy NetBird
Peer-to-peer mesh No No Yes
Web management UI No Yes Yes (Control Center)
Access policies No No Yes (zero-trust)
SSO/OIDC No No Yes
NAT traversal Manual Manual Automatic
SSH key management Manual Manual Identity-based
CLI/API automation No No Yes
Adding a new peer Edit config, restart Click in web UI Install agent, authenticate
Self-hostable Yes Yes Yes (all components)

For a single tunnel to your home lab, WG-Easy is perfect. For a team, a business, or anything that needs access policies and automation, NetBird is the right tool.

Read our full NetBird review for a detailed look at the platform.

Troubleshooting Common Issues

Handshake Not Completing

Most common cause: UDP port 51820 isn’t open. Check:

sudo ufw status

# or

sudo iptables -L -n | grep 51820

Also verify your cloud provider’s security group allows UDP 51820 inbound.

Peers Can Connect but Can’t Reach the Internet

IP forwarding isn’t enabled, or the MASQUERADE rule is wrong:

# Check IP forwarding

sysctl net.ipv4.ip_forward

# Should return: net.ipv4.ip_forward = 1

# Check NAT rules

sudo iptables -t nat -L POSTROUTING

Make sure the interface in your PostUp/PostDown rules matches your server’s actual network interface.

DNS Not Working Through the Tunnel

Set DNS explicitly in the client config:

DNS = 1.1.1.1, 8.8.8.8

Some Linux distributions require resolvconf installed for WireGuard’s DNS settings to take effect:

sudo apt install resolvconf

Connection Drops Behind NAT

Add PersistentKeepalive = 25 to the [Peer] section in the client config. This sends a keepalive packet every 25 seconds, preventing NAT timeouts.

Conclusion

WireGuard is the best VPN protocol available in 2026. The question is how much abstraction you want on top of it.

Manual setup teaches you how WireGuard works. Valuable for learning, viable for personal use, but doesn’t scale well.

WG-Easy is the sweet spot for personal and home lab VPN. One Docker command, a web UI, and you’re done.

NetBird is where WireGuard meets the needs of real IT teams. Mesh networking, zero-trust access, CLI/API automation, and a management interface that makes distributed networking manageable.

Pick the level that matches your needs. All three give you WireGuard’s speed, security, and simplicity.

For the full VPN landscape, see our guide to the best self-hosted VPN solutions in 2026. For protocol details, read our WireGuard vs OpenVPN comparison.