How to Install and Configure WireGuard VPN Server on Ubuntu: Setting Up a High-Speed Virtual Private Network

Ubuntu tutorial - IT technology blog
Ubuntu tutorial - IT technology blog

Why OpenVPN Is Giving Way to WireGuard

OpenVPN and IPsec have been staples for network administrators for years. However, their inherent drawback is a bloated codebase spanning hundreds of thousands of lines of code, resulting in high CPU usage and noticeable latency. Whenever you switch from Wi-Fi to cellular data, OpenVPN often takes 10–20 seconds to complete a handshake and reconnect.

WireGuard eliminates this hassle entirely. Its entire codebase consists of just under 4,000 lines, built directly into the Linux kernel starting from version 5.6. Real-world benchmarks demonstrate that WireGuard delivers 3–4 times the throughput of OpenVPN while saving around 30% battery on mobile devices. With an Ubuntu 22.04 or 24.04 VPS running on 1 vCPU / 1GB RAM, you can complete the entire setup in less than 10 minutes.

Core Concepts: How Does WireGuard Work?

Understanding how WireGuard operates under the hood will help you troubleshoot network issues rapidly:

  • Cryptokey Routing Model: WireGuard treats every device as an equal Peer. Similar to SSH key authentication, each machine holds its own Public/Private Key pair. The server routes and decrypts packets directly based on the Public Key, eliminating tedious TLS handshakes and authentication steps.
  • Direct Execution in Kernel Space: Data does not need to bounce back and forth between User Space and Kernel Space like OpenVPN’s TUN/TAP mechanism. As a result, latency is kept to a minimum and network interface bandwidth is fully utilized.
  • Stateless Design: WireGuard does not transmit continuous keepalive packets unless there is active data to send. The server remains completely silent in response to random port scans across the Internet.

Step-by-Step Guide: Installing and Configuring WireGuard on Ubuntu

Step 1: Enable IP Forwarding

By default, Linux blocks packet forwarding between network interfaces. You must enable this feature so your VPS can route traffic to the Internet:

sudo sed -i -e '$a\net.ipv4.ip_forward = 1' /etc/sysctl.conf
sudo sed -i -e '$a\net.ipv6.conf.all.forwarding = 1' /etc/sysctl.conf
sudo sysctl -p

If the output shows net.ipv4.ip_forward = 1, the system has successfully applied the new configuration.

Step 2: Install Packages and Generate Server Keys

Install WireGuard along with the QR code generator utility for easy mobile device setup:

sudo apt update && sudo apt install -y wireguard qrencode

Create the working directory and generate the Server’s private/public key pair with secure permissions:

cd /etc/wireguard
umask 077
wg genkey | tee server_private.key | wg pubkey > server_public.key

You can view the key file contents using cat server_private.key. Never expose your Private Key to anyone.

Step 3: Identify Network Interface and Create Server Configuration

Find the primary network interface connected to the Internet by running:

ip -br link

Typically, the network interface is named eth0, ens3, or enp1s0. Be sure to use this exact name in the iptables firewall rules below.

Create the server configuration file at /etc/wireguard/wg0.conf:

sudo nano /etc/wireguard/wg0.conf

Paste the following configuration into the file (replacing the keys and network interface accordingly):

[Interface]
Address = 10.8.0.1/24, fd42:42:42::1/64
ListenPort = 51820
PrivateKey = <CONTENTS_OF_server_private.key>
SaveConfig = false

# Enable NAT when bringing up VPN and remove NAT when bringing down VPN (replace eth0 with your actual interface)
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE; ip6tables -A FORWARD -i wg0 -j ACCEPT; ip6tables -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; ip6tables -D FORWARD -i wg0 -j ACCEPT; ip6tables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

Step 4: Configure Firewall and Start the Service

Open UDP port 51820 in UFW and start WireGuard via systemd:

sudo ufw allow 51820/udp
sudo ufw allow OpenSSH
sudo ufw enable

# Enable WireGuard to start on boot and run immediately
sudo systemctl enable --now wg-quick@wg0

Check the server status with the following command:

sudo wg show

If the terminal displays the wg0 interface along with port 51820 and the public key, your server is ready to accept incoming connections.

Step 5: Generate Client Configuration and QR Code

Generate a key pair for the first client device (for example, client1):

cd /etc/wireguard
wg genkey | tee client1_private.key | wg pubkey > client1_public.key

Add the Client information to the server configuration by editing /etc/wireguard/wg0.conf and appending the following block:

[Peer]
PublicKey = <CONTENTS_OF_client1_public.key>
AllowedIPs = 10.8.0.2/32, fd42:42:42::2/128

Apply the updated server configuration without restarting the service:

sudo wg addconf wg0 <(sudo wg-quick strip wg0)

Next, create the client configuration file client1.conf to import into the device:

[Interface]
PrivateKey = <CONTENTS_OF_client1_private.key>
Address = 10.8.0.2/24, fd42:42:42::2/64
DNS = 1.1.1.1, 8.8.8.8

[Peer]
PublicKey = <CONTENTS_OF_server_public.key>
Endpoint = <SERVER_PUBLIC_IP>:51820
AllowedIPs = 0.0.0.0/0, ::/0
PersistentKeepalive = 25

To import the configuration on a phone, simply output the QR code in the terminal and scan it with the WireGuard mobile app:

qrencode -t ansiutf8 < client1.conf

Production Tips for Operating WireGuard

1. Fix Web Congestion and Stalling with MTU Tuning

If ping works reliably but large websites stall or load sluggishly, the root cause is often packet fragmentation due to an oversized MTU across multiple network hops. Lower the MTU in the Client configuration file:

[Interface]
MTU = 1360

An MTU value between 1360 and 1420 provides solid stability across most fiber-optic and 4G/5G mobile networks.

2. Prevent NAT Connection Drops with PersistentKeepalive

Many Wi-Fi routers and mobile carriers using CGNAT automatically flush idle NAT state tables after 30 seconds of inactivity. Adding PersistentKeepalive = 25 to the Client’s [Peer] section sends a lightweight probe packet every 25 seconds. This keeps the NAT tunnel open and ensures you receive push notifications instantly.

3. Full Tunnel vs. Split Tunnel

Depending on your workflow requirements, adjust the AllowedIPs directive in the Client file:

  • Full Tunnel (AllowedIPs = 0.0.0.0/0, ::/0): All web browsing and file traffic routes through the VPS. This setup is strongly recommended when connected to untrusted public Wi-Fi in cafes or hotels.
  • Split Tunnel (AllowedIPs = 10.8.0.0/24): Only traffic destined for the internal VPN subnet routes through the tunnel, while normal Internet browsing uses your native connection. This saves VPS bandwidth and maintains maximum browsing speeds.

Summary

WireGuard proves that a secure networking solution doesn’t need to be complex or bloated. With just a few commands to generate keys and configure iptables routing, you get a blazingly fast, private encrypted tunnel. Properly tuning your MTU and Keepalive settings right from the start ensures a seamless VPN experience across all your devices.

Share: