How to Deploy a Secure WireGuard VPN Server on Ubuntu 24.04 (With Client Setup)

Why WireGuard and Why Now?

WireGuard has become one of the most practical VPN technologies for modern networks because it is fast, lightweight, and easier to audit than older VPN stacks. For remote work, home labs, or small business admin access, a WireGuard server on Ubuntu 24.04 is a clean way to reach internal services without exposing them directly to the internet. This tutorial walks through a secure, real-world setup: server installation, firewall and forwarding, client configuration, and a few troubleshooting checks.

What You Need Before You Start

You will need an Ubuntu 24.04 server with root or sudo access, a public IPv4 address (or port-forwarding from your router), and a client device (Windows, macOS, Linux, Android, or iOS). Make sure you know your server’s public IP or DNS name. In this guide, we’ll use a private VPN subnet of 10.10.10.0/24 and the server will be 10.10.10.1.

Step 1: Install WireGuard on Ubuntu 24.04

Update packages and install WireGuard and basic firewall tooling:

Commands:
sudo apt update
sudo apt install -y wireguard ufw

Step 2: Generate Server Keys

WireGuard uses public key cryptography. Generate a private/public key pair for the server and protect the private key permissions:

Commands:
sudo umask 077
wg genkey | sudo tee /etc/wireguard/server.key | wg pubkey | sudo tee /etc/wireguard/server.pub

View the public key (you’ll share this with clients):

Command:
sudo cat /etc/wireguard/server.pub

Step 3: Create the WireGuard Interface Configuration

Create /etc/wireguard/wg0.conf. Replace YOUR_SERVER_PRIVATE_KEY with the contents of /etc/wireguard/server.key. If your server’s network interface is not eth0, replace it accordingly (common alternatives are ens3, enp1s0, etc.).

Command:
sudo nano /etc/wireguard/wg0.conf

Example wg0.conf:
[Interface]
Address = 10.10.10.1/24
ListenPort = 51820
PrivateKey = YOUR_SERVER_PRIVATE_KEY

PostUp = ufw route allow in on wg0 out on eth0; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = ufw route delete allow in on wg0 out on eth0; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

This configuration enables NAT so VPN clients can reach the internet or other networks through the server. If you only want access to internal resources and do not need internet tunneling, you can skip the NAT portion and route traffic differently, but NAT is the most common starter setup.

Step 4: Enable IP Forwarding

To route packets between the VPN interface and your main network interface, enable IPv4 forwarding:

Commands:
echo 'net.ipv4.ip_forward=1' | sudo tee /etc/sysctl.d/99-wireguard-forward.conf
sudo sysctl --system

Step 5: Configure the Firewall (UFW)

Allow the WireGuard UDP port and enable the firewall:

Commands:
sudo ufw allow 51820/udp
sudo ufw allow OpenSSH
sudo ufw enable
sudo ufw status

If SSH is not already allowed and you are connected remotely, ensure OpenSSH is permitted before enabling UFW to avoid locking yourself out.

Step 6: Start and Enable the WireGuard Service

Bring up the interface and configure it to start at boot:

Commands:
sudo systemctl enable --now wg-quick@wg0
sudo wg show

The wg show output is your first verification point. At this stage you will not see peers yet, which is normal.

Step 7: Create a Client (Peer) Configuration

On your client device (or on the server if you prefer and then copy files securely), generate client keys. On Linux, you can run:

Commands (client side):
umask 077
wg genkey | tee client1.key | wg pubkey | tee client1.pub

Now add the client as a peer on the server by editing /etc/wireguard/wg0.conf and appending a [Peer] block. Replace CLIENT1_PUBLIC_KEY with the contents of client1.pub:

Server wg0.conf (append):
[Peer]
PublicKey = CLIENT1_PUBLIC_KEY
AllowedIPs = 10.10.10.2/32

Restart WireGuard to apply changes:

Command:
sudo systemctl restart wg-quick@wg0

Step 8: Build the Client VPN Profile

Create a client configuration file (for example client1.conf) and import it into the WireGuard app (Windows/macOS) or WireGuard mobile app (Android/iOS). Replace placeholders with your real values:

Example client1.conf:
[Interface]
PrivateKey = CLIENT1_PRIVATE_KEY
Address = 10.10.10.2/32
DNS = 1.1.1.1

[Peer]
PublicKey = SERVER_PUBLIC_KEY
Endpoint = YOUR_SERVER_PUBLIC_IP_OR_DNS:51820
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25

If you only want access to your internal network and not full tunneling, replace AllowedIPs = 0.0.0.0/0 with only the networks you want to reach (for example 192.168.1.0/24 and 10.10.10.0/24). Keeping AllowedIPs tight is a simple way to reduce risk and avoid routing surprises.

Step 9: Verify the Connection and Troubleshoot

After activating the tunnel on the client, run these checks on the server:

Commands:
sudo wg show
sudo ss -lunp | grep 51820

In wg show, look for a recent latest handshake time and increasing transfer counters. If the handshake never happens, confirm UDP port 51820 is reachable from the internet (cloud security group, router port-forwarding, ISP restrictions). If handshake works but you cannot browse, re-check NAT rules, IP forwarding, and the client’s AllowedIPs. Also confirm your main interface name is correct in the PostUp/PostDown rules.

Security Tips for a Cleaner VPN Deployment

Keep your server updated, use SSH keys instead of passwords, and consider installing Fail2ban for SSH hardening. For WireGuard itself, the strongest control is peer management: only add the peers you need, assign each peer a single /32 address, and remove peers immediately when a device is lost or a user no longer needs access. WireGuard is simple by design, so good operational habits make the biggest difference.

Once this is working, you can expand the setup by adding more peers, routing to additional internal subnets, or placing WireGuard behind a firewall appliance. But even as-is, this Ubuntu 24.04 WireGuard server provides a modern, reliable VPN foundation for secure remote access.

3.

Comments