WireGuard VPN Setup on Ubuntu and AlmaLinux VPS

What this WireGuard VPN setup covers
This WireGuard VPN setup walks you through building a private tunnel on a fresh VPS, starting with the first SSH login and ending with firewall rules, routing, and connection tests. It covers Ubuntu, Debian, AlmaLinux, and Rocky Linux, so you can follow the right commands for your server.
If you are moving a small team, a remote admin workflow, or a customer support network onto a Hostperl VPS, WireGuard is easier to manage than older VPN stacks. It keeps the configuration small, uses strong cryptography, and performs well on modest hardware. If you are still choosing a server, a Hostperl VPS is a straightforward place to start because you control the OS, firewall, and routing from top to bottom.
For readers who want a broader background on network decisions, Hostperl’s colocation hosting checklist and shared hosting limits and upgrade triggers help explain when a private VPS is the better fit for remote access and routing control.
Before you begin
- One fresh VPS with Ubuntu 24.04, Ubuntu 22.04, Debian 12, AlmaLinux 9, or Rocky Linux 9.
- Root SSH access for the first login.
- A second terminal on your local computer for testing the new VPN connection.
- At least one public IPv4 address. IPv6 works too, and this guide includes both.
Open your SSH session from your local computer:
ssh root@203.0.113.10Replace 203.0.113.10 with the real public IP assigned to your server. It is a reserved documentation address, not a live host.
If your provider gives you a default non-root account, use that first login instead, then become root with sudo -i after you verify access.
Confirm the operating system
On the VPS as root, detect the distribution before you install anything:
cat /etc/os-releaseYou should see Ubuntu or Debian entries with ID=ubuntu or ID=debian, or AlmaLinux/Rocky Linux with ID=almalinux or ID=rocky. Use the matching command set below.
Create a non-root admin user
Keep your root session open. Create the daily login user first, then test it in a second terminal before changing SSH access rules. This sequencing avoids lockout.
Ubuntu and Debian
On the VPS as root:
apt updateThen create the admin account, set a password, and add it to sudo:
adduser deploy
usermod -aG sudo deployNow prepare SSH access for that user. First create the directory with safe permissions:
mkdir -p /home/deploy/.ssh
chmod 700 /home/deploy/.ssh
chown -R deploy:deploy /home/deploy/.sshFrom your local computer, copy your public key to the VPS. Replace the sample IP with your real server IP if different:
ssh-copy-id deploy@203.0.113.10Back on the VPS, harden ownership and permissions:
chmod 600 /home/deploy/.ssh/authorized_keys
chown deploy:deploy /home/deploy/.ssh/authorized_keysOpen a second terminal on your local computer and test the new login:
ssh deploy@203.0.113.10After you connect, confirm sudo works:
sudo -i
whoamiSuccessful output should show root. Leave the original root session open until this test passes.
AlmaLinux and Rocky Linux
On the VPS as root:
dnf makecacheCreate the admin account, set a password, and add it to the wheel group:
useradd -m deploy
passwd deploy
usermod -aG wheel deployPrepare the SSH directory and permissions:
mkdir -p /home/deploy/.ssh
chmod 700 /home/deploy/.ssh
chown -R deploy:deploy /home/deploy/.sshFrom your local computer, copy the public key:
ssh-copy-id deploy@203.0.113.10Then lock down the key file:
chmod 600 /home/deploy/.ssh/authorized_keys
chown deploy:deploy /home/deploy/.ssh/authorized_keysIn a second local terminal, test the new account:
ssh deploy@203.0.113.10Verify sudo access:
sudo -i
whoamiAgain, expect root. Do not change root SSH access until this works.
Install WireGuard
WireGuard needs the kernel module and userspace tools. Install the packages for your distribution, then confirm the service binary is available.
Ubuntu and Debian
On the VPS as root or the non-root sudo user:
apt update
apt install -y wireguard wireguard-toolsCheck the kernel and tool version:
wg --versionOn modern Ubuntu and Debian kernels, WireGuard is usually ready without extra module work.
AlmaLinux and Rocky Linux
On the VPS as root or the non-root sudo user:
dnf install -y epel-release
dnf install -y wireguard-toolsCheck the tool version:
wg --versionIf the kernel module is not loaded yet, the next step will confirm it. AlmaLinux and Rocky Linux 9 usually support WireGuard directly.
Generate server and client keys
Run these commands on the VPS as root. Keep the private key private. Anyone with it can impersonate the server.
umask 077
wg genkey | tee /etc/wireguard/server.key | wg pubkey > /etc/wireguard/server.pub
wg genkey | tee /etc/wireguard/client1.key | wg pubkey > /etc/wireguard/client1.pubCheck that the files exist:
ls -l /etc/wireguard/*.key /etc/wireguard/*.pubYou should see restrictive permissions and separate key files for server and client.
Find your network interface and local routing details
WireGuard needs the VPS’s public interface for NAT. Detect it now.
ip route show defaultThe output usually shows an interface such as eth0 or ens3. You will use that name in the firewall and forwarding rules below.
Also check whether IPv6 is available:
ip -6 addr show scope globalIf you see a global IPv6 address, you can route IPv6 through the tunnel as well.
Enable IP forwarding safely
WireGuard can carry traffic, but forwarding must be enabled for the VPS to route client packets to the internet. Set this before you add the firewall rule.
Ubuntu and Debian
On the VPS as root:
cat >/etc/sysctl.d/99-wireguard.conf <<'EOF'
net.ipv4.ip_forward=1
net.ipv6.conf.all.forwarding=1
EOF
sysctl --systemSuccessful output shows the new values loaded without errors.
AlmaLinux and Rocky Linux
On the VPS as root:
cat >/etc/sysctl.d/99-wireguard.conf <<'EOF'
net.ipv4.ip_forward=1
net.ipv6.conf.all.forwarding=1
EOF
sysctl --systemOn RHEL-compatible systems, this works the same way. If SELinux is enforcing, no special change is needed for WireGuard itself.
Create the WireGuard server configuration
Now write the tunnel config. Replace eth0 if your default route uses a different interface. Replace the sample tunnel IPs only if you want a different subnet.
cat >/etc/wireguard/wg0.conf <<'EOF'
[Interface]
Address = 10.44.0.1/24, fd42:44:44::1/64
ListenPort = 51820
PrivateKey = REPLACE_WITH_SERVER_PRIVATE_KEY
PostUp = iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE; ip6tables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE; ip6tables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
[Peer]
PublicKey = REPLACE_WITH_CLIENT_PUBLIC_KEY
AllowedIPs = 10.44.0.2/32, fd42:44:44::2/128
EOFOpen the file and replace the two REPLACE_WITH... values with the actual contents of these commands:
cat /etc/wireguard/server.key
cat /etc/wireguard/client1.pubUse nano /etc/wireguard/wg0.conf if you prefer interactive editing. Save and exit after inserting the real keys. The file must not contain the placeholder text when you start the service.
Create the client configuration
On the VPS as root, print the client private key and the server public key. You will paste them into a client file on your local computer or mobile device.
cat /etc/wireguard/client1.key
cat /etc/wireguard/server.pubCreate a client config on your local computer using the real key values. The example below assumes your VPN client will use the private IPs from the server config above.
[Interface]
PrivateKey = CLIENT_PRIVATE_KEY
Address = 10.44.0.2/24, fd42:44:44::2/64
DNS = 1.1.1.1
[Peer]
PublicKey = SERVER_PUBLIC_KEY
Endpoint = 203.0.113.10:51820
AllowedIPs = 0.0.0.0/0, ::/0
PersistentKeepalive = 25Replace 203.0.113.10 with your real VPS IP. If you only want access to the VPN subnet and server, narrow AllowedIPs instead of sending all traffic through the tunnel.
Open the firewall before starting the tunnel
Add the new rule first, then start WireGuard. That avoids a short lockout if the service comes up before the port is open.
Ubuntu and Debian with UFW
On the VPS as root:
apt install -y ufw
ufw allow 22/tcp
ufw allow 51820/udp
ufw enable
ufw status verboseThe status output should list SSH and UDP port 51820 as allowed. If you already use a custom SSH port, allow it before enabling UFW.
AlmaLinux and Rocky Linux with firewalld
On the VPS as root:
dnf install -y firewalld
systemctl enable --now firewalld
firewall-cmd --permanent --add-service=ssh
firewall-cmd --permanent --add-port=51820/udp
firewall-cmd --reload
firewall-cmd --list-allYou should see ssh and 51820/udp in the active zone. If you manage SELinux strictly, WireGuard still works with the standard UDP port.
Start WireGuard and enable it at boot
Before you start the service, check the config syntax and ensure the private key entries are real values.
chmod 600 /etc/wireguard/wg0.conf
systemctl enable --now wg-quick@wg0
systemctl status wg-quick@wg0 --no-pagerA healthy status shows the service as active and running. If it fails, jump to the troubleshooting section below.
Confirm the interface came up and the peer is loaded:
wg show
ip addr show wg0You should see the wg0 interface with the 10.44.0.1 and fd42:44:44::1 addresses.
Test the client connection
On your local computer, import the client config into the WireGuard app or apply it with wg-quick on Linux. Then activate the tunnel and check basic connectivity.
ping 10.44.0.1If IPv6 is enabled, test that too:
ping6 fd42:44:44::1Then confirm internet routing if you set AllowedIPs = 0.0.0.0/0, ::/0:
curl -4 https://ifconfig.me
curl -6 https://ifconfig.meThe returned addresses should match the VPS public IPv4 and IPv6, not your home connection.
Check logs and packet flow
If traffic does not pass, inspect the service and recent journal entries on the VPS as root:
journalctl -u wg-quick@wg0 -n 50 --no-pagerFor live packet counters, run:
wg show wg0The latest handshake and transfer counters should update after the client connects.
Common problems and fixes
The tunnel starts but no internet traffic passes
Run this on the VPS as root to confirm forwarding and NAT rules:
sysctl net.ipv4.ip_forward net.ipv6.conf.all.forwarding
iptables -t nat -S POSTROUTING
ip6tables -t nat -S POSTROUTINGIf forwarding is 0, reapply sysctl --system. If the NAT rule shows the wrong interface name, edit /etc/wireguard/wg0.conf, replace eth0 with the real interface from ip route show default, then restart:
systemctl restart wg-quick@wg0The client cannot handshake
Check the public port and the peer key:
ss -lunp | grep 51820
wg showIf nothing is listening, the service did not start. If it listens but handshake stays empty, the client public key in wg0.conf is probably wrong or the endpoint IP points to the wrong server.
SSH is blocked after enabling the firewall
On the VPS, review the active rules:
UFW
ufw status numberedfirewalld
firewall-cmd --list-services
firewall-cmd --list-portsIf SSH is missing, add it first, then reload the firewall. Never remove the old access path until the new one is confirmed.
Final verification and reboot test
Before you call the setup finished, test persistence. On the VPS as root, reboot once and check that the service returns automatically:
rebootAfter the VPS comes back, reconnect over SSH and run:
systemctl status wg-quick@wg0 --no-pager
wg show
ip addr show wg0You want the interface, the service, and the peer state to survive the reboot. Then run one more client-side smoke test:
curl https://ifconfig.meIf the address is the VPS public IP, the tunnel is routing correctly.
If you want to run WireGuard on infrastructure that you control fully, a Hostperl VPS gives you the routing, firewall, and kernel access you need. For larger teams or higher traffic remote access, a dedicated server can provide more headroom for multiple tunnels and heavier throughput.
Hostperl’s support team is used to real launch-day issues: missing firewall rules, broken NAT, and SSH lockouts. That matters when you are building a production VPN for admins, agencies, or customer operations.
FAQ
Can I use WireGuard on both IPv4 and IPv6?
Yes. The server and client configs above include both address families. If your provider only gives you IPv4, remove the IPv6 lines and keep the IPv4 tunnel addresses.
Which port does WireGuard use?
The default in this guide is UDP 51820. You can change it, but remember to open the new port in UFW or firewalld before restarting the service.
Do I need a public static IP?
For a stable VPN endpoint, yes. Dynamic addresses make client configs break after every change. If your VPS IP changes rarely, update the Endpoint line in every client profile.
How do I remove the tunnel later?
Stop the service, disable it at boot, remove the firewall port, and delete the config files:
systemctl disable --now wg-quick@wg0
rm -f /etc/wireguard/wg0.conf /etc/wireguard/*.key /etc/wireguard/*.pubOnly do this after you have confirmed you no longer need the tunnel.
