Skip to main contentSkip to navigation
[email protected]
Client AreaSupport
Hosting Mammoth
HostingMammothYour Data, Our Responsibility
Home
Solutions
Hosting Services
Store
Pricing
About
Blog
API
Contact

Stay Ahead of the Curve

Get the latest insights on cybersecurity, AI innovations, and enterprise data solutions delivered to your inbox.

Hosting Mammoth
HostingMammothEnterprise Solutions

Enterprise-grade data solutions. Hosting, recovery, cybersecurity, and AI-powered services for businesses worldwide.

[email protected]
Sun - Fri, 9:00am - 5:00pm

Services

  • Cloud Hosting
  • Data Recovery
  • Cybersecurity
  • Legal Support
  • MSP Services
  • Web Development
  • AI Services
  • Free Server Migration

Hosting

  • VPS Hosting (NVMe SSD)
  • VDS Hosting (NVMe)
  • Storage VPS (High SSD)
  • GPU Servers
  • Managed Services
  • Cloud Firewall
  • Load Balancer
  • One-Click Apps
  • n8n Hosting
  • Object Storage
  • FAQ

Company

  • Store
  • Pricing
  • About Us
  • Locations
  • Blog
  • Testimonials
  • Contact
  • Affiliate Program
  • White-Label
  • Terms of Service
  • Privacy Policy
  • Browser Cookies
  • SLA

Support

  • Client Area
  • Submit Ticket
  • Knowledge Base
  • Server Status
  • API Documentation

© 2026 Hosting Mammoth. All rights reserved.

Knowledge Base
Getting StartedAccount ManagementVPS HostingGPU ServersStorage VPSCloud FirewallLoad BalancerServer ManagementBilling & PaymentsSupport & TicketsAffiliate ProgramReseller ProgramMarketplace & Appsn8n HostingManaged ServicesServer MigrationAPI & DevelopersSecurityTroubleshootingGlossaryInstall Guides
  1. Home
  2. /
  3. Support
  4. /
  5. Install Guides
  6. /
  7. How To Install Wireguard Ubuntu
GUIDEInstall Guides

How to Install WireGuard VPN on Ubuntu 24.04 — Fast, Modern, Self-Hosted

26 min read

How to Install WireGuard VPN on Ubuntu 24.04 — Fast, Modern, Self-Hosted

A personal VPN on a VPS is one of the highest-leverage things you can do with a Linux server: secure your laptop on hotel Wi-Fi, reach a home network from the road, give a small team shared access to internal services, or simply route traffic out of a predictable IP. For years the default answer was OpenVPN, but the landscape shifted when WireGuard landed in the mainline Linux kernel in 2020. It is faster, simpler, and has been formally audited. This guide walks you through a full WireGuard server build on Ubuntu 24.04 LTS — from first SSH connection to mobile QR onboarding and multi-peer production config.

Want a VPN without the setup? The VPS-Server.host Starter plan gives you a static public IP, 2 vCPU and 4 GB RAM — plenty for a personal or small-team WireGuard server. Spin one up in 60 seconds.

Table of Contents

  • Why WireGuard?
  • Prerequisites
  • Step 1: Update System Packages
  • Step 2: Install WireGuard
  • Step 3: Generate the Server Keypair
  • Step 4: Create the Server Config (wg0.conf)
  • Step 5: Enable IP Forwarding
  • Step 6: Configure NAT Masquerade
  • Step 7: Open UDP 51820 in UFW
  • Step 8: Start wg0 and Enable at Boot
  • Step 9: Generate Client Configs
  • Step 10: Connect a Mobile Device with a QR Code
  • Split-Tunnel vs Full-Tunnel
  • Adding Multiple Peers
  • wg-easy: A Web UI Alternative
  • Troubleshooting
  • FAQ
  • Next Steps
  • Why WireGuard?

    WireGuard was designed from scratch by Jason A. Donenfeld to fix the two biggest problems with older VPNs: complexity and speed. The entire codebase is roughly 4,000 lines of C — two orders of magnitude smaller than OpenVPN or IPsec — which makes it far easier to audit and far less prone to bugs. Independent cryptographic reviews (including one commissioned by the French ANSSI) have found no serious issues.

    On the wire it uses a fixed, modern cipher suite: ChaCha20 for symmetric encryption, Poly1305 for authentication, Curve25519 for key exchange, BLAKE2s for hashing, and SipHash24 for hashtable keys. There is no cipher negotiation, which means no downgrade attacks and no configuration surface to misconfigure.

    Because WireGuard runs inside the Linux kernel, packets never copy between kernel and user space the way they do with OpenVPN. The result is dramatically higher throughput — in back-to-back tests it comfortably pushes 1 Gbps on modest hardware where OpenVPN tops out around 200-300 Mbps. Handshakes complete in about 1 RTT, so roaming between networks is nearly instant.

    The configuration model matches the simplicity of the protocol. Instead of a sprawling server.conf with dozens of directives, you get one ini-style file per interface: an [Interface] block for your side, and one [Peer] block per remote endpoint. That is the whole mental model.

    If you are coming from OpenVPN or wrestling with IPsec, the difference is stark — and if you are considering a fully managed mesh VPN, take a look at Tailscale, NetBird or Headscale later in this guide.

    Prerequisites

    Before starting, make sure you have:

    • A VPS running Ubuntu 24.04 LTS with root or sudo access
    • SSH access to the server (built-in terminal on macOS/Linux, or PuTTY/Windows Terminal on Windows)
    • A static public IPv4 address on the server (every VPS-Server.host plan includes one)
    • A client device — desktop (Linux/macOS/Windows) or mobile (iOS/Android)
    Recommended Plan: Starter
    >
    WireGuard is extremely lightweight, so you do not need a large server. Our Starter plan is a great fit:
    >
    - 2 vCPU cores
    - 4 GB RAM
    - 50 GB NVMe SSD
    - 32 TB monthly traffic
    - Dedicated static IPv4
    >
    This easily supports 50-100 concurrent VPN users for everyday browsing. For heavier site-to-site workloads, step up to a 4-6 vCPU plan.

    Connect to your server:

    bash
    ssh root@your-server-ip

    Step 1: Update System Packages

    Start with a clean, patched base. WireGuard has been in the mainline kernel since 5.6, so Ubuntu 24.04 (kernel 6.8+) ships everything you need — but you still want the latest security updates.

    bash
    sudo apt update && sudo apt upgrade -y

    If the kernel was upgraded, reboot before continuing:

    bash
    sudo reboot

    Reconnect via SSH after a minute.

    Step 2: Install WireGuard

    The wireguard package on Ubuntu is a meta-package that pulls in the userspace tools (wg, wg-quick) and the kernel module. Since 24.04 ships with a recent kernel, the module is already available — no DKMS build required.

    bash
    sudo apt install -y wireguard wireguard-tools qrencode

    We add qrencode now so we can later render client configs as QR codes for mobile onboarding.

    Verify the install:

    bash
    wg --version

    Expected output:

    text
    wireguard-tools v1.0.20210914 - https://git.zx2c4.com/wireguard-tools/

    Confirm the kernel module loads:

    bash
    sudo modprobe wireguard && lsmod | grep wireguard

    Expected output:

    text
    wireguard             212992  0
    curve25519_x86_64      36864  1 wireguard
    libchacha20poly1305    16384  1 wireguard
    ip6_udp_tunnel         16384  1 wireguard
    udp_tunnel             32768  1 wireguard

    Step 3: Generate the Server Keypair

    Every WireGuard peer — server or client — is identified by a Curve25519 keypair. There is no certificate authority, no CSRs, no expiry dates. You generate the private key, derive the public key, and share only the public key with the other side.

    Move into the WireGuard config directory and tighten permissions up front:

    bash
    cd /etc/wireguard
    sudo umask 077

    Generate the server keypair with a single pipeline:

    bash
    wg genkey | sudo tee /etc/wireguard/privatekey | wg pubkey | sudo tee /etc/wireguard/publickey

    This produces two files:

    • /etc/wireguard/privatekey — the server's private key (keep secret)
    • /etc/wireguard/publickey — the server's public key (shared with clients)
    Inspect them:

    bash
    sudo cat /etc/wireguard/privatekey
    sudo cat /etc/wireguard/publickey

    Expected output (your keys will differ):

    text
    kJ8+7BqH4zvL9mN3pQ2rS5tU6wX8yA1bC4dE7fG0hJk=
    H3xL9mN5pQ2rS8tU6wX4yA7bC0dE1fG2hJ8kM3nP6qR=

    Both keys are base64-encoded, 44 characters long, and end with =. If yours look different, regenerate them.

    Step 4: Create the Server Config (wg0.conf)

    The server config lives at /etc/wireguard/wg0.conf. The interface name wg0 is convention — you can have wg1, wg2 etc. for separate tunnels.

    First, grab the server's primary network interface name — you will need it for the NAT rules:

    bash
    ip route | grep default

    Expected output:

    text
    default via 203.0.113.1 dev eth0 proto static

    In this example the interface is eth0. On some cloud VPS images it may be ens3, ens18 or enp1s0. Use whatever appears after dev.

    Now create the config:

    bash
    sudo nano /etc/wireguard/wg0.conf

    Paste the following, substituting your server's private key and interface name:

    ini
    [Interface]
    

    Tunnel IP for the server inside the VPN

    Address = 10.8.0.1/24

    UDP port WireGuard listens on

    ListenPort = 51820

    Server private key (from /etc/wireguard/privatekey)

    PrivateKey = kJ8+7BqH4zvL9mN3pQ2rS5tU6wX8yA1bC4dE7fG0hJk=

    Save peer state back to the file when the service stops

    SaveConfig = false

    NAT masquerade so clients can reach the public internet via eth0

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

    --- Peers are appended below, one [Peer] block per client ---

    A quick walk-through:

    • Address = 10.8.0.1/24 — the server's address inside the tunnel. The /24 tells WireGuard the VPN subnet is 10.8.0.0/24, giving you 254 usable peer IPs. Pick any RFC 1918 subnet that does not conflict with your home or office LAN (common choices: 10.8.0.0/24, 10.10.10.0/24, 172.16.100.0/24).
    • ListenPort = 51820 — the default UDP port. You can change this, but keeping it default is fine since only peers with the right key can even get a response.
    • PrivateKey — paste the exact contents of /etc/wireguard/privatekey.
    • SaveConfig = false — keeps the config file stable so git tracking, Ansible etc. work cleanly. If you set this to true, wg-quick down will rewrite the file with any runtime changes, which is surprising.
    • PostUp / PostDown — shell commands run after the interface comes up or before it goes down. These add/remove the NAT and forwarding rules we need to turn the VPS into an internet gateway for VPN clients.
    Save and exit (Ctrl+O, Enter, Ctrl+X).

    Lock down the file permissions:

    bash
    sudo chmod 600 /etc/wireguard/wg0.conf /etc/wireguard/privatekey

    Step 5: Enable IP Forwarding

    By default, Linux does not forward packets between interfaces. Without this, traffic arriving on wg0 will never be routed out to eth0 — clients will connect but reach nothing.

    Enable IPv4 forwarding persistently:

    bash
    echo 'net.ipv4.ip_forward = 1' | sudo tee /etc/sysctl.d/99-wireguard.conf
    echo 'net.ipv6.conf.all.forwarding = 1' | sudo tee -a /etc/sysctl.d/99-wireguard.conf
    sudo sysctl --system

    Expected output (abbreviated):

    text
    * Applying /etc/sysctl.d/99-wireguard.conf ...
    net.ipv4.ip_forward = 1
    net.ipv6.conf.all.forwarding = 1

    Verify the value is live:

    bash
    sysctl net.ipv4.ip_forward

    Expected output:

    text
    net.ipv4.ip_forward = 1

    Step 6: Configure NAT Masquerade

    The PostUp rules in wg0.conf already handle NAT via iptables, and Ubuntu 24.04's iptables-nft shim transparently translates those calls into nftables rules. If you prefer native nftables for clarity, create a persistent ruleset instead:

    bash
    sudo nano /etc/nftables.conf

    Append (or create) the following:

    text
    table inet wireguard_nat {
        chain postrouting {
            type nat hook postrouting priority srcnat; policy accept;
            oifname "eth0" ip saddr 10.8.0.0/24 masquerade
        }

    chain forward { type filter hook forward priority filter; policy accept; iifname "wg0" accept oifname "wg0" accept } }

    Enable and apply:

    bash
    sudo systemctl enable --now nftables
    sudo nft -f /etc/nftables.conf
    sudo nft list ruleset

    If you go the nftables route, remove the PostUp/PostDown lines from wg0.conf so you are not double-applying rules. For most users the default iptables-in-wg0.conf approach is simpler and works out of the box — only switch if you are already managing nftables elsewhere.

    Step 7: Open UDP 51820 in UFW

    Ubuntu's UFW makes firewall management painless. Allow SSH (so you do not lock yourself out), allow the WireGuard port, then enable the firewall.

    bash
    sudo ufw allow 22/tcp
    sudo ufw allow 51820/udp
    sudo ufw enable
    sudo ufw status verbose

    Expected output:

    text
    Status: active
    Logging: on (low)
    Default: deny (incoming), allow (outgoing), disabled (routed)
    To                         Action      From
    --                         ------      ----
    22/tcp                     ALLOW IN    Anywhere
    51820/udp                  ALLOW IN    Anywhere
    22/tcp (v6)                ALLOW IN    Anywhere (v6)
    51820/udp (v6)             ALLOW IN    Anywhere (v6)

    Important: UFW forwarding policy

    UFW defaults to DROP on the FORWARD chain, which will silently kill client traffic even with forwarding enabled in sysctl. Fix it:

    bash
    sudo sed -i 's/^DEFAULT_FORWARD_POLICY="DROP"/DEFAULT_FORWARD_POLICY="ACCEPT"/' /etc/default/ufw
    sudo ufw reload

    Step 8: Start wg0 and Enable at Boot

    Bring the tunnel up for the first time:

    bash
    sudo wg-quick up wg0

    Expected output:

    text
    [#] ip link add wg0 type wireguard
    [#] wg setconf wg0 /dev/fd/63
    [#] ip -4 address add 10.8.0.1/24 dev wg0
    [#] ip link set mtu 1420 up dev wg0
    [#] iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE; iptables -A FORWARD -i wg0 -j ACCEPT; iptables -A FORWARD -o wg0 -j ACCEPT

    Confirm the interface is live:

    bash
    sudo wg show

    Expected output:

    text
    interface: wg0
      public key: H3xL9mN5pQ2rS8tU6wX4yA7bC0dE1fG2hJ8kM3nP6qR=
      private key: (hidden)
      listening port: 51820

    No peers yet — we will add them in Step 9.

    Enable WireGuard at boot via the bundled systemd unit:

    bash
    sudo systemctl enable wg-quick@wg0
    sudo systemctl status wg-quick@wg0

    Expected output:

    text
    ● [email protected] - WireGuard via wg-quick(8) for wg0
         Loaded: loaded (/usr/lib/systemd/system/[email protected]; enabled; preset: enabled)
         Active: active (exited) since Wed 2026-04-16 10:15:00 UTC; 30s ago

    The wg-quick@ template unit reads /etc/wireguard/wg0.conf on boot and runs the same wg-quick up wg0 command you just ran manually.

    Step 9: Generate Client Configs

    Each client gets its own keypair and its own entry in the VPN subnet. Generate a keypair for the first client (we will call it laptop):

    bash
    cd /etc/wireguard
    mkdir -p clients && cd clients
    wg genkey | tee laptop.key | wg pubkey > laptop.pub
    chmod 600 laptop.key

    View the keys:

    bash
    cat laptop.key
    cat laptop.pub

    Build the client config

    Create laptop.conf:

    bash
    sudo nano /etc/wireguard/clients/laptop.conf

    Paste (substituting placeholders):

    ini
    [Interface]
    

    Client private key (from laptop.key)

    PrivateKey = <CLIENT_PRIVATE_KEY>

    Client VPN IP — must be unique within 10.8.0.0/24

    Address = 10.8.0.2/32

    DNS servers used while the tunnel is up (Cloudflare + Google here; use your own if preferred)

    DNS = 1.1.1.1, 8.8.8.8

    [Peer]

    Server public key (from /etc/wireguard/publickey)

    PublicKey = <SERVER_PUBLIC_KEY>

    Full-tunnel: send all traffic through the VPN

    AllowedIPs = 0.0.0.0/0, ::/0

    Public IP:port of the server

    Endpoint = your-server-ip:51820

    Keep NAT mappings open on mobile networks (every 25s)

    PersistentKeepalive = 25

    Register the peer on the server

    Append a [Peer] block to /etc/wireguard/wg0.conf:

    bash
    sudo nano /etc/wireguard/wg0.conf

    Add at the bottom:

    ini
    [Peer]
    

    laptop

    PublicKey = <CLIENT_PUBLIC_KEY> AllowedIPs = 10.8.0.2/32

    Save and exit. Reload the config without disrupting the interface:

    bash
    sudo wg syncconf wg0 <(wg-quick strip wg0)

    Verify the peer is registered:

    bash
    sudo wg show

    Expected output:

    text
    interface: wg0
      public key: H3xL9mN5pQ2rS8tU6wX4yA7bC0dE1fG2hJ8kM3nP6qR=
      private key: (hidden)
      listening port: 51820

    peer: <CLIENT_PUBLIC_KEY> allowed ips: 10.8.0.2/32

    The peer shows no handshake yet — that will happen once the client connects.

    Step 10: Connect a Mobile Device with a QR Code

    Typing a 44-character base64 key into a phone by hand is miserable. The official WireGuard mobile apps (iOS and Android) can scan a QR code containing the entire client config.

    On the server, render laptop.conf as a QR code in the terminal:

    bash
    sudo qrencode -t ansiutf8 < /etc/wireguard/clients/laptop.conf

    A block-art QR code will appear. Open the WireGuard app on your phone, tap Add Tunnel → Create from QR code, and scan the terminal.

    Toggle the tunnel on. Within a second or two, sudo wg show on the server should display a fresh latest handshake timestamp and non-zero transfer bytes:

    text
    peer: <CLIENT_PUBLIC_KEY>
      endpoint: 198.51.100.42:53471
      allowed ips: 10.8.0.2/32
      latest handshake: 3 seconds ago
      transfer: 1.24 KiB received, 892 B sent

    Test that traffic is flowing out through the VPS: on the phone, visit https://ifconfig.me — it should show your server's IP, not the phone's cellular or Wi-Fi IP.

    For desktop clients, copy /etc/wireguard/clients/laptop.conf to the device (over SSH with scp, never email or chat) and import it through the WireGuard GUI or place it in /etc/wireguard/ on Linux and run sudo wg-quick up laptop.

    Split-Tunnel vs Full-Tunnel

    The single most impactful setting on the client is AllowedIPs. It serves double duty: on the wire it tells WireGuard which remote subnets the peer is authorised to send packets into, and locally it also installs routes telling the OS which outbound traffic to send through the tunnel.

    Full-tunnel (privacy VPN)

    ini
    AllowedIPs = 0.0.0.0/0, ::/0

    Every packet leaves the device through the VPN. Use this when you want the VPS to act as your public internet egress — hotel Wi-Fi, public cafes, geo-unblocking, or simply masking your home IP.

    Split-tunnel (private resource access)

    ini
    AllowedIPs = 10.8.0.0/24, 192.168.50.0/24

    Only traffic destined for the VPN subnet (10.8.0.0/24) and your home LAN (192.168.50.0/24) goes through the tunnel. Netflix, YouTube, local printers — everything else — uses the client's normal internet connection. This is ideal for company VPNs, where you want employees to reach internal services without routing their entire browsing history through your server.

    Mix and match

    You can add specific public IPs or CIDRs to a split-tunnel config to selectively route certain destinations. For example, tunneling only traffic to a customer's IP range:

    ini
    AllowedIPs = 10.8.0.0/24, 203.0.113.0/24

    Remember: if you change AllowedIPs you usually do not need to touch the server config. The server's [Peer] AllowedIPs acts as a cryptographic access control list (which source IPs this peer is allowed to claim), while the client's AllowedIPs is a routing directive.

    Adding Multiple Peers

    Scaling from one user to many is a matter of repeating Step 9. Here is a clean, scriptable pattern.

    Create a helper script at /usr/local/sbin/wg-add-peer:

    bash
    sudo nano /usr/local/sbin/wg-add-peer
    bash
    #!/usr/bin/env bash
    set -euo pipefail

    NAME="${1:-}" if [[ -z "$NAME" ]]; then echo "Usage: wg-add-peer <name>" exit 1 fi

    SERVER_PUB=$(cat /etc/wireguard/publickey) SERVER_ENDPOINT="${WG_ENDPOINT:-your-server-ip}:51820" CLIENT_DIR="/etc/wireguard/clients" mkdir -p "$CLIENT_DIR"

    Find next free IP in 10.8.0.0/24 (starts at .2, .1 is server)

    USED=$(grep -Eo 'AllowedIPs = 10\.8\.0\.[0-9]+' /etc/wireguard/wg0.conf | grep -Eo '[0-9]+$' | sort -n || true) NEXT=2 for ip in $USED; do if [[ "$ip" -ge "$NEXT" ]]; then NEXT=$((ip + 1)); fi done CLIENT_IP="10.8.0.$NEXT"

    umask 077 wg genkey | tee "$CLIENT_DIR/$NAME.key" | wg pubkey > "$CLIENT_DIR/$NAME.pub" PRIV=$(cat "$CLIENT_DIR/$NAME.key") PUB=$(cat "$CLIENT_DIR/$NAME.pub")

    cat > "$CLIENT_DIR/$NAME.conf" <<EOF [Interface] PrivateKey = $PRIV Address = $CLIENT_IP/32 DNS = 1.1.1.1, 8.8.8.8

    [Peer] PublicKey = $SERVER_PUB AllowedIPs = 0.0.0.0/0, ::/0 Endpoint = $SERVER_ENDPOINT PersistentKeepalive = 25 EOF

    cat >> /etc/wireguard/wg0.conf <<EOF

    [Peer]

    $NAME

    PublicKey = $PUB AllowedIPs = $CLIENT_IP/32 EOF

    wg syncconf wg0 <(wg-quick strip wg0)

    echo "Peer '$NAME' added with IP $CLIENT_IP" echo "Config: $CLIENT_DIR/$NAME.conf" echo qrencode -t ansiutf8 < "$CLIENT_DIR/$NAME.conf"

    Make it executable and use it:

    bash
    sudo chmod +x /usr/local/sbin/wg-add-peer
    sudo WG_ENDPOINT=your-server-ip wg-add-peer phone
    sudo WG_ENDPOINT=your-server-ip wg-add-peer work-laptop
    sudo WG_ENDPOINT=your-server-ip wg-add-peer partner-mac

    Each invocation picks the next free tunnel IP, generates keys, writes a client config, appends a [Peer] block to the server config, and prints a QR code — all atomically, with no hand-editing.

    wg-easy: A Web UI Alternative

    If hand-editing ini files is not your style, wg-easy wraps everything in this guide behind a clean browser UI. It runs as a single Docker container, exposes an admin dashboard on port 51821, and handles peer creation, QR generation, config downloads, traffic graphs and enable/disable toggles with a few clicks.

    A minimal deploy:

    bash
    docker run -d \
      --name wg-easy \
      --cap-add=NET_ADMIN --cap-add=SYS_MODULE \
      --sysctl="net.ipv4.conf.all.src_valid_mark=1" \
      --sysctl="net.ipv4.ip_forward=1" \
      -e WG_HOST=your-server-ip \
      -e PASSWORD_HASH='<bcrypt-hash>' \
      -p 51820:51820/udp \
      -p 51821:51821/tcp \
      -v ~/.wg-easy:/etc/wireguard \
      --restart unless-stopped \
      ghcr.io/wg-easy/wg-easy

    Under the hood it still writes a wg0.conf compatible with everything in this guide, so you can migrate in or out of wg-easy without reinstalling WireGuard. It is a great choice when onboarding non-technical team members, and it pairs well with a reverse proxy + basic auth on the admin port.

    For a full mesh experience with identity provider integration, ACLs and NAT traversal, look at the Tailscale, NetBird or self-hosted Headscale guides — all three are built on top of the WireGuard protocol.

    Troubleshooting

    ProblemCauseSolution
    Handshake never completes (latest handshake stays empty)UDP 51820 blocked upstream or wrong endpointVerify with sudo ss -ulnp \</td><td>grep 51820<code> on the server and </code>nc -u -v your-server-ip 51820 from the client. Check UFW and any cloud firewall in the provider console.
    Handshake succeeds but no internet on the clientIP forwarding or NAT misconfiguredsysctl net.ipv4.ip_forward must be 1. Check sudo iptables -t nat -L POSTROUTING -n -v shows the MASQUERADE rule. Confirm DEFAULT_FORWARD_POLICY=ACCEPT in /etc/default/ufw.
    Websites load slowly / images brokenMTU mismatchSet MTU = 1380 in the client [Interface] block. WireGuard defaults to 1420 but some ISPs drop fragmented packets.
    DNS leaks (client uses local DNS instead of 1.1.1.1)Client DNS not appliedOn Linux, install resolvconf or openresolv. On Windows, the official WireGuard app handles this automatically.
    RTNETLINK answers: Operation not supported on wg-quick upKernel module missingRun sudo modprobe wireguard. If it fails, reboot after apt upgrade — you likely pulled a kernel update without rebooting.
    Two peers cannot reach each other (peer-to-peer within the VPN)Missing routes on peersEach client's AllowedIPs must include the VPN subnet (e.g. 10.8.0.0/24), not just 10.8.0.1/32.
    Second peer using duplicate IP silently breaks bothAllowedIPs in server config overlapsEvery [Peer] AllowedIPs entry on the server must be unique. Use /32 per peer.

    Live debugging

    Stream the WireGuard handshake state in real time:

    bash
    watch -n 1 'sudo wg show'

    Check kernel messages for dropped packets:

    bash
    sudo journalctl -k --since "5 minutes ago" | grep -iE 'wireguard|wg0'

    FAQ

    Is WireGuard really faster than OpenVPN?

    Yes, by a wide margin. WireGuard lives in the Linux kernel and uses a fixed, modern cipher suite (ChaCha20, Curve25519, BLAKE2s), so there is no per-packet context switch between kernel and userspace. Back-to-back benchmarks on identical hardware typically show WireGuard pushing 3-4x the throughput of OpenVPN and handshakes completing in roughly one round-trip. The entire codebase is also ~4,000 lines vs. OpenVPN's 70,000+, which makes audits tractable — WireGuard has passed formal reviews including one commissioned by the French cybersecurity agency ANSSI.

    Do I need a static IP on my VPS for WireGuard?

    A static public IP is strongly recommended because the Endpoint in every client config points at a fixed IP (or DNS name). If the server IP changes you have to re-issue every client config. Every VPS-Server.host plan includes a dedicated static IPv4 by default, so you do not need to configure anything extra. If you use a dynamic IP, point a dynamic DNS name at it and use the DNS name as the endpoint.

    What is the difference between split-tunnel and full-tunnel WireGuard?

    It is entirely controlled by the AllowedIPs line in the client config. Full-tunnel (0.0.0.0/0, ::/0) sends every packet the device generates through the VPN — useful for public Wi-Fi, geo-unblocking, or making your client appear at the VPS IP. Split-tunnel lists only specific subnets (say 10.8.0.0/24, 192.168.1.0/24), so only traffic matching those routes is tunneled and general internet usage stays on the local connection. Split-tunnel is faster and saves VPS bandwidth; full-tunnel is safer on untrusted networks.

    How many peers can a single WireGuard server handle?

    WireGuard itself scales to thousands of peers on commodity hardware — the protocol was designed for this. In practice the bottleneck is almost always bandwidth, not CPU. On a 2 vCPU Starter VPS with a 1 Gbps port you can comfortably support 50-100 concurrent users for general browsing, or 20-30 for heavy streaming. For 500+ peers or a high-throughput corporate deployment, step up to 4-6 vCPU, tune net.core.rmem_max / wmem_max, and consider multiple wgN interfaces bound to separate CPU cores.

    Should I use iptables or nftables for NAT with WireGuard?

    Either works. Ubuntu 24.04 ships nftables as the default backend, and the iptables-nft compatibility layer translates legacy iptables commands to nftables rules on the fly. The PostUp/PostDown lines shown in this guide take advantage of that — simple and reliable. For new deployments where you are already writing nftables rules for other services, the native nftables table shown in Step 6 is cleaner. Just do not mix both at once, or you will end up with duplicate rules.

    Is wg-easy a good alternative to editing wg0.conf by hand?

    Yes, especially for teams. wg-easy is a lightweight Docker-based web UI that handles peer creation, QR code generation, enable/disable toggles and traffic graphs without touching the terminal. Under the hood it still writes a standard wg0.conf, so you can migrate back to the CLI workflow from this guide at any time without re-provisioning clients. It is ideal when you need to onboard less-technical users or want a dashboard view of who is connected.

    How does WireGuard compare to Tailscale and NetBird?

    Tailscale and NetBird are overlay mesh networks built on top of the WireGuard protocol. They add automatic peer discovery, NAT traversal (so peers behind CGNAT can reach each other), identity-based ACLs, and a managed coordination server that distributes keys. Vanilla WireGuard — what this guide covers — is lower-level: you run one hub server, you control every peer, and there is no external dependency. Choose Tailscale or NetBird when you want zero-config mesh networking for a team. Choose self-hosted Headscale if you like Tailscale's model but want to run the coordination server yourself. Choose vanilla WireGuard when you want a minimal, auditable, single-server setup with no external control plane.

    Next Steps

    You now have a production-quality WireGuard server. Here is where to go from here:

    • Harden SSH on the server — once the VPN is up, you can move SSH to listen only on 10.8.0.1 and firewall off port 22 from the public internet entirely.
    • Monitor with Prometheus — prometheus-wireguard-exporter scrapes wg show dump and gives you per-peer bandwidth graphs in Grafana.
    • Add a kill switch on clients — set PostUp/PostDown on the client interface to block all non-tunnel traffic so a VPN drop fails closed.
    • Try a mesh overlay — see our guides on Tailscale, NetBird and Headscale for zero-config peer-to-peer networking.
    • Compare with OpenVPN — if you are migrating from a legacy setup, our OpenVPN guide walks through the same scenarios so you can benchmark side by side.
    • Read the official docs — the wireguard.com/install/ page lists platform-specific installers and links to the full protocol spec for deeper study.

    Deploy Your WireGuard VPS in 60 Seconds
    >
    The VPS-Server.host Starter plan is purpose-built for personal and small-team VPN workloads:
    >
    - 2 vCPU, 4 GB RAM, 50 GB NVMe
    - Dedicated static IPv4 included
    - 32 TB monthly traffic on a 1 Gbps port
    - Ubuntu 24.04 LTS image ready in under a minute
    >
    Launch a Starter VPS now and follow this guide end to end in about 25 minutes.

    Was this article helpful?

    ← Back to Install GuidesBrowse all categories →

    Still have questions?

    Contact Support →Submit a Ticket