WireGuard is a communication protocol and free and open-source software that implements encrypted virtual private networks, and was designed with the goals of ease of use, high speed performance, and low attack surface.
It is a lightweight Virtual Private Network (VPN) that supports IPv4 and IPv6 connections. A VPN allows you to traverse untrusted networks as if you were on a private network. It gives you the freedom to access the internet safely and securely from your smartphone or laptop when connected to an untrusted network, like the WiFi at a hotel or coffee shop.
Compared to other popular VPN solutions, such as IPsec and OpenVPN , WireGuard is faster, easier to configure, and has a smaller footprint. It is cross-platform and can run almost anywhere, including Linux, Windows, Android, and macOS.
Wireguard is a peer-to-peer VPN; it does not use the client-server model. Depending on its configuration, a peer can act as a traditional server or client. It works by creating a network interface on each peer device that acts as a tunnel. Peers authenticate each other by exchanging and validating public keys, mimicking the SSH model. Public keys are mapped with a list of IP addresses that are allowed in the tunnel. The VPN traffic is encapsulated in UDP.
On Ubuntu versions: this guide targets Ubuntu 22.04 LTS, whose standard security maintenance runs until May 2027 (after that it needs Ubuntu Pro/ESM). Every command below works unchanged on Ubuntu 24.04 LTS and 26.04 LTS, so if you are building a new server, install the newer LTS and follow along as-is.
Related Posts:
- How to Setup and Secure WireGuard VPN with wg-easy on AlmaLinux 10
- Automate WireGuard VPN Setup on AlmaLinux 10 with SaltStack
- How to install and configure Pritunl in Rocky Linux/ Alma Linux 9
Ensure your Server packages are up to date
Before proceeding, ensure that your os packages are updated. Use this command:
sudo apt update && sudo apt upgrade -y
Optionally set the server hostname
sudo hostnamectl set-hostname vpn.citizix.com
Server Networking and Firewall Configuration
If you are using WireGuard to connect a peer to the WireGuard Server in order to access services on the server only, then you do not need to complete this section. If you would like to route your WireGuard Peer’s Internet traffic through the WireGuard Server then you will need to configure IP forwarding by following this section of the tutorial.
To enable IP Forwarding on the Server, open the file /etc/sysctl.conf with your text editor.
sudo vim /etc/sysctl.conf
Uncomment this line:
net.ipv4.ip_forward=1
If you are using IPv6 with WireGuard, add this line at the bottom of the file:
net.ipv6.conf.all.forwarding=1
Save the file and apply the change:
sudo sysctl -p
Make sure the server is routing traffic from the WireGuard interface to the internet. You may need to configure Network Address Translation (NAT) on the server.
To do this, you can use iptables (replace ens5 with your serverβs main network interface):
sudo iptables -t nat -A POSTROUTING -o ens5 -j MASQUERADE
sudo iptables -A FORWARD -i wg0 -o ens5 -m state --state RELATED,ESTABLISHED -j ACCEPT
sudo iptables -A FORWARD -i ens5 -o wg0 -j ACCEPT
To make the iptables rules persistent, you can install iptables-persistent:
sudo apt install iptables-persistent
The installer prompts you to save the current IPv4 and IPv6 rules β answer yes. Then you can (re-)save the iptables rules at any time using:
sudo iptables-save | sudo tee /etc/iptables/rules.v4
Open the WireGuard port
WireGuard listens on UDP port 51820. Make sure it is reachable, otherwise clients will
handshake forever. If ufw is active on the server, allow the port:
sudo ufw allow 51820/udp
If your server runs at a cloud provider (AWS, GCP, Azure, Hetzner, DigitalOcean), you also have to allow inbound UDP 51820 in the security group or cloud firewall β that is a separate layer from ufw.
Install wireguard vpn
Wireguard is available in default ubuntu repositories. Install it using this command:
sudo apt install wireguard
This will install the WireGuard module and tools.
Configure WireGuard VPN Server
The wg and wg-quick command-line tools allow you to configure and manage the WireGuard interfaces.
Run the following command to create a public/private key pair. The files will be saved under /etc/wireguard/ directory.
sudo mkdir -p /etc/wireguard
sudo chmod 700 /etc/wireguard
umask 077
sudo sh -c 'wg genkey | tee /etc/wireguard/server_private.key | wg pubkey > /etc/wireguard/server_public.key'
The keys are written by a single root shell (sudo sh -c 'β¦') on purpose. If you instead
run sudo wg genkey | β¦ > server_public.key, the final redirect is performed by your
shell, not by sudo, and it fails with Permission denied because /etc/wireguard is
owned by root. The umask 077 makes sure both key files are created readable only by root.
The wg command is WireGuard’s built-in configuration utility for getting and setting WireGuard’s configurations. When you run the command, you will receive a single line of base64 encoded output, the public key (server_public.key) for your WireGuard server.
Remember, the private key (server_private.key) should never be shared with anyone and always be kept secure.
Configure Tunnel Device
We need to create a network interface for WireGuard. The network interface name will be wg0.
sudo vim /etc/wireguard/wg0.conf
Add this:
[Interface]
## Private IP address for the wg0 interface ##
Address = 10.70.0.1/24
## VPN server listening port ##
ListenPort = 51820
## VPN server private key ##
PrivateKey = 2NV6mHFXeN2R25eq9LJag3PiwuxvMrrHBDtZcEiedGU=
## Firewall rules ##
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o ens5 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o ens5 -j MASQUERADE
Replace the PrivateKey with the content of the one you generated, stored in the /etc/wireguard/server_private.key file.
sudo cat /etc/wireguard/server_private.key
Make sure to replace ens5 after -A POSTROUTING -o ... to match the name of your public network interface. You can find it easily with:
ip -o -4 route show to default | awk '{print $5}'
Save and close the wg0.conf file. Additionally, tighten the permissions so that only the root user can read the keys and the config:
sudo chmod 700 /etc/wireguard
sudo chmod 600 /etc/wireguard/*.key /etc/wireguard/wg0.conf
Do not use
chmod -R 600 /etc/wireguard/. The-Rapplies600to the directory too, which strips its execute (traversal) bit β the directory needs700, and only the files inside it should be600.
The interface can be named anything, however it is recommended to use something like wg0 or wgvpn0. The settings in the interface section have the following meaning:
Address- A comma-separated list of v4 or v6 IP addresses for the wg0 interface. Use IPs from a range that is reserved for private networks (10.0.0.0/8, 172.16.0.0/12 or 192.168.0.0/16).ListenPort- The UDP port WireGuard listens on.51820is the convention.PrivateKey- A private key generated by thewg genkeycommand. (To see the contents of the file type:sudo cat /etc/wireguard/server_private.key)SaveConfig- When set to true, the current state of the interface is saved to the configuration file when shutdown. Leave it out (as we do here) if you want to hand-editwg0.conf, because it will overwrite your file β including your comments β every time the interface goes down.PostUp- Command or script that is executed before bringing the interface up. In this example, we’re using iptables to enable masquerading. This allows traffic to leave the server, giving the VPN clients access to the Internet.
Make sure to replace ens5 after -A POSTROUTING to match the name of your public network interface. You can easily find the interface with:
ip -o -4 route show to default | awk '{print $5}'
PostDown- command or script which is executed before bringing the interface down. The iptables rules will be removed once the interface is down.
Enable and Start WireGuard VPN Service
Run the following command on the server to enable auto-start at system boot time and start WireGuard.
sudo systemctl enable wg-quick@wg0
sudo systemctl start wg-quick@wg0
Check its status with the following command. You should see active in the output:
sudo systemctl status [email protected]
Output:
$ sudo systemctl status wg-quick@wg0
β [email protected] - WireGuard via wg-quick(8) for wg0
Loaded: loaded (/usr/lib/systemd/system/[email protected]; enabled; preset: enabled)
Active: active (exited) since Sat 2025-01-18 06:02:04 UTC; 6s ago
Docs: man:wg-quick(8)
man:wg(8)
https://www.wireguard.com/
https://www.wireguard.com/quickstart/
https://git.zx2c4.com/wireguard-tools/about/src/man/wg-quick.8
https://git.zx2c4.com/wireguard-tools/about/src/man/wg.8
Process: 1362 ExecStart=/usr/bin/wg-quick up wg0 (code=exited, status=0/SUCCESS)
Main PID: 1362 (code=exited, status=0/SUCCESS)
CPU: 30ms
Jan 18 06:02:04 vpn.citizix.com systemd[1]: Starting [email protected] - WireGuard via wg-quick(8) for wg0...
Jan 18 06:02:04 vpn.citizix.com wg-quick[1362]: [#] ip link add wg0 type wireguard
Jan 18 06:02:04 vpn.citizix.com wg-quick[1362]: [#] wg setconf wg0 /dev/fd/63
Jan 18 06:02:04 vpn.citizix.com wg-quick[1362]: [#] ip -4 address add 10.70.0.1/24 dev wg0
Jan 18 06:02:04 vpn.citizix.com wg-quick[1362]: [#] ip link set mtu 8921 up dev wg0
Jan 18 06:02:04 vpn.citizix.com wg-quick[1362]: [#] iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o ens5 -j MASQUERADE
Jan 18 06:02:04 vpn.citizix.com systemd[1]: Finished [email protected] - WireGuard via wg-quick(8) for wg0.
To check the interface state and configuration, enter:
sudo wg show wg0
Output:
$ sudo wg show wg0
interface: wg0
public key: Ar+Y1r9bCE9CwM9UgK/fSiFiP9jaNIHt5YGCkVbmZF8=
private key: (hidden)
listening port: 51820
No peers are listed yet β we add the client in the next section.
Set up client
Install the WireGuard package on the client machine
sudo apt install wireguard
You’ll need to generate a public/private key pair on the peer using the exact steps you used on the server.
sudo mkdir -p /etc/wireguard
sudo chmod 700 /etc/wireguard
umask 077
sudo sh -c 'wg genkey | tee /etc/wireguard/client_private.key | wg pubkey > /etc/wireguard/client_public.key'
Open a new /etc/wireguard/wg0.conf file on the WireGuard client machine using your preferred editor:
sudo vim /etc/wireguard/wg0.conf
Add the following lines to the file:
[Interface]
## VPN client private IP address ##
Address = 10.70.0.2/24
## VPN client private key ##
PrivateKey = wP9y5xaw2mwqB2C4ujdVokn8zaxKr/elrNlcgw19snw=
## Resolver to use while the tunnel is up ##
DNS = 1.1.1.1
[Peer]
## VPN server public key ##
PublicKey = Ar+Y1r9bCE9CwM9UgK/fSiFiP9jaNIHt5YGCkVbmZF8=
## VPN server public IP address and port ##
Endpoint = 10.2.11.9:51820
## Route all the traffic through the VPN tunnel ##
AllowedIPs = 0.0.0.0/0
## Key connection alive ##
PersistentKeepalive = 15
The DNS line matters whenever AllowedIPs = 0.0.0.0/0. Without it the client keeps using
whatever resolver the local network handed it, so your DNS queries still go to the untrusted
network you are trying to tunnel out of. On Linux clients wg-quick needs resolvconf (or
openresolv) installed for DNS to take effect:
sudo apt install resolvconf
Replace the PrivateKey with the content of the one you generated, stored in the /etc/wireguard/client_private.key file on the client machine.
Replace the server’s public key, which can be found in the /etc/wireguard/server_public.key file on the server.
Replace the Endpoint value (10.2.11.9:51820) with your server’s public IP address and port.
Finally, save and close the file.
You need to configure the server-side VPN option to allow a connection between the client (Peer) computer and the server. So, go back to the server and edit the /etc/wireguard/wg0.conf file to add client information as follows:
sudo vim /etc/wireguard/wg0.conf
[Peer]
## Client public key ##
PublicKey = ybR/GfG7XBx3XUi3V1wV7IIxCpSaqELtOfIOuGlSij8=
## Client IP address ##
AllowedIPs = 10.70.0.2/32
Note the /32. On the server side, AllowedIPs is a routing table: it tells WireGuard
which source addresses to accept from this peer and which destinations to send down its
tunnel. It must therefore be the single host address of that client. If you write
10.70.0.2/24 here, the server routes the whole 10.70.0.0/24 VPN subnet to this one peer,
and every client you add afterwards will fail to reach the others. Give each peer its own
/32 (10.70.0.3/32, 10.70.0.4/32, and so on), each in its own [Peer] block.
Replace the PublicKey with the file’s content stored in the /etc/wireguard/client_public.key file on the client machine.
Save the file and restart the VPN server to apply the changes:
sudo systemctl restart [email protected]
Connecting the WireGuard Client to the Server
Run the following command on the client machine to connect the VPN client to the VPN server:
sudo systemctl start wg-quick@wg0
Ensure it started
sudo systemctl status wg-quick@wg0
Now you should be connected to the WireGuard VPN server, and the traffic from your client machine should be routed through it.
That’s all! Both client and server must be connected securely using a peer-to-peer WireGuard VPN on Ubuntu.
To test the connection, return to the VPN client and ping from it (10.70.0.2) to the VPN server (10.70.0.1) to see if the tunnel works.
$ ping -c 3 10.70.0.1
PING 10.70.0.1 (10.70.0.1) 56(84) bytes of data.
64 bytes from 10.70.0.1: icmp_seq=1 ttl=64 time=0.095 ms
64 bytes from 10.70.0.1: icmp_seq=2 ttl=64 time=0.085 ms
64 bytes from 10.70.0.1: icmp_seq=3 ttl=64 time=0.068 ms
--- 10.70.0.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2052ms
rtt min/avg/max/mdev = 0.068/0.082/0.095/0.011 ms
Additionally, you can check the connection with:
sudo wg
Or show command
$ sudo wg show wg0
interface: wg0
public key: Ar+Y1r9bCE9CwM9UgK/fSiFiP9jaNIHt5YGCkVbmZF8=
private key: (hidden)
listening port: 51820
peer: ybR/GfG7XBx3XUi3V1wV7IIxCpSaqELtOfIOuGlSij8=
endpoint: 10.2.11.20:49312
allowed ips: 10.70.0.2/32
latest handshake: 34 seconds ago
transfer: 1.94 KiB received, 1.31 KiB sent
The latest handshake line is the one to check: if it is missing or never updates, the peers
are not talking, and the usual cause is UDP 51820 being blocked upstream or a mismatched key.
Or
ip a show wg0
Conclusion
In this guide we managed to set up wireguard as a VPN peer gateway.