Installing WireGuard-UI to Manage Your WireGuard VPN Server

To manage WireGuard peers (client) on a single server easily, you can use WireGuard-UI, a web-based user interface to manage your WireGuard setup written in Go.

Wireguard-UI is a web-based user interface to manage your WireGuard server setup written by ngoduykhanh using Go programming language. This is an alternative way to install and easily manage your WireGuard VPN server.

If you prefer to install WireGuard server “from scratch” and manage it manually, you can follow my previous article about “How to Set up Your Own WireGuard VPN Server”.

Prerequisites

  • A VPS (Ubuntu 22.04 or 24.04) with Public IP address
  • Comfortable with Linux command-line.
  • Basic knowledge of IPv4 subnetting (to be honest, I’m not familiar with IPv6 subnetting, so this article is for IPv4 only).
  • Able to configure Nginx Virtual Host.

In this guide, our goals:

  • Server run WireGuard daemon listen on port 51822/UDP.
  • WireGuard UI run from 127.0.0.1 on port 5000.
  • Nginx acts as reverse proxy and serve WireGuard UI service using HTTPS.

Note:

  • By default, WireGuard listens on UDP port 51820, and WireGuard-UI follows this configuration by default. If you don’t use port 51822 (like this article does), please adjust your firewall and WireGuard UI Server Settings configuration accordingly.
  • The YouTube videos above are not in the order of this article. They also use different IPs & subnets, so adjust them to your needs.

Prepare Your Server

First, make sure your system is up-to-date and WireGuard is installed on your server.

1sudo apt update && sudo apt upgrade
2sudo apt install wireguard

Edit /etc/sysctl.conf and add net.ipv4.ip_forward=1 to the end of the file, then run sudo sysctl -p to load the new /etc/sysctl.conf values.

1sudo sysctl -p

This is required to allow packet forwarding on your server.

Setting up Firewall

By default, Ubuntu system use comes with UFW to manage system firewall. You need to add WireGuard listen port to firewall allow list.

1sudo ufw allow OpenSSH
2sudo ufw allow 80 comment "allow HTTP" # will be used by Nginx
3sudo ufw allow 443 comment "allow HTTPS" # will be used by Nginx
4sudo ufw allow proto udp to any port 443  comment "allow QUIC" # If your Nginx support QUIC
5# Adjust ufw command below according to your WireGuard listen port
6sudo ufw allow proto udp to any port 51820 comment "WireGuard default listen port"
7sudo ufw allow proto udp to any port 51822 comment "WireGuard tutorial listen port"

Note that I also add OpenSSH to allow list to avoid losing connection to SSH if you didn’t configure / activate it before.

Enable / restart your ufw service using:

1sudo ufw enable # to enable firewall, or
2sudo ufw reload # to reload firewall

Download & Configure WireGuard-UI

Download Wireguard-UI from its latest release page to your server. Choose the one that match with your server OS and CPU architecture.

Extract downloaded .tar.gz file:

1tar -xvzf  wireguard-ui-*.tar.gz

Create new directory /opt/wireguard-ui and move the wireguard-ui binary (from extracted .tar.gz file) to /opt/wireguard-ui.

1mkdir /opt/wireguard-ui
2mv wireguard-ui /opt/wireguard-ui/

Create environment file for WireGuard-UI (This will be loaded using EnvironmentFile from systemd unit file later):

1# /opt/wireguard-ui/.env
2SESSION_SECRET=<YOUR_STRONG_RANDOM_SECRET_KEY>
3WGUI_USERNAME=<YOUR_WIREGUARD_UI_USERNAME>
4WGUI_PASSWORD=<YOUR_WIREGUARD_UI_PASSWORD>

If you want to enable email feature, you need to set up your SMTP_* environment variable. See WireGuard UI Environment Variables details for more information.

Finding Server Default Interface

Then, find out which network interface used by your server as its default route. You can use ip route list default to see that. Example output of my ip route list default command:

1default via 172.xxx.xxx.201 dev eth0 proto static

Write down the word after dev output, that’s your default network interface. We will need that information later. In this example, my default network interface is eth0.

Create /opt/wireguard-ui/postup.sh, and fill with this example config:

1#!/usr/bin/bash
2# /opt/wireguard-ui/postup.sh
3ufw route allow in on wg0 out on eth0
4iptables -t nat -I POSTROUTING -o eth0 -j MASQUERADE

The postup.sh bash script above will be executed when WireGuard service is started.

Create /opt/wireguard-ui/postdown.sh, and fill with this example config:

1#!/usr/bin/bash
2# /opt/wireguard-ui/postdown.sh
3ufw route delete allow in on wg0 out on eth0
4iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

The postdown.sh bash script above will be executed when WireGuard service is stopped.

Replace eth0 value from those two bash script above with your default network interface (see Finding Server Default Interface section above).

Then, make those two bash script (/opt/wireguard-ui/postup.sh and /opt/wireguard-ui/postdown.sh) executable:

1chmod +x /opt/wireguard-ui/post*.sh

WireGuard-UI daemon SystemD

To manage WireGuard-UI daemon (Web UI) using systemd, create /etc/systemd/system/wireguard-ui-daemon.service systemd file, and fill with this following configuration:

 1[Unit]
 2Description=WireGuard UI Daemon
 3Wants=network-online.target
 4After=network-online.target
 5
 6[Service]
 7User=root
 8Group=root
 9Type=simple
10WorkingDirectory=/opt/wireguard-ui
11EnvironmentFile=/opt/wireguard-ui/.env
12ExecStart=/opt/wireguard-ui/wireguard-ui -bind-address "127.0.0.1:5000"
13
14[Install]
15WantedBy=multi-user.target

The systemd configuration will run WireGuard UI daemon on 127.0.0.1:5000.

Now reload your systemd daemon configuration and try to start wireguard-ui-daemon.service.

1sudo systemctl daemon-reload
2sudo systemctl start wireguard-ui-daemon.service

Verify your wireguard-ui-daemon.service is running properly by using systemctl status wireguard-ui-daemon.service:

 1● wireguard-ui-daemon.service - WireGuard UI Daemon
 2     Loaded: loaded (/etc/systemd/system/wireguard-ui-daemon.service; disabled; vendor preset: enabled)
 3     Active: active (running) since Mon 2023-06-05 23:57:47 UTC; 5s ago
 4   Main PID: 4388 (wireguard-ui)
 5      Tasks: 4 (limit: 1115)
 6     Memory: 17.1M
 7        CPU: 1.243s
 8     CGroup: /system.slice/wireguard-ui-daemon.service
 9             └─4388 /opt/wireguard-ui/wireguard-ui -bind-address 127.0.0.1:5000
10
11Jun 05 23:57:47 fra1-do1 wireguard-ui[4388]: Git Ref                : refs/tags/v0.5.1
12Jun 05 23:57:47 fra1-do1 wireguard-ui[4388]: Build Time        : 06-05-2023 23:57:47
13Jun 05 23:57:47 fra1-do1 wireguard-ui[4388]: Git Repo        : https://github.com/ngoduykhanh/wireguard-ui
14Jun 05 23:57:47 fra1-do1 wireguard-ui[4388]: Authentication        : true
15Jun 05 23:57:47 fra1-do1 wireguard-ui[4388]: Bind address        : 127.0.0.1:5000
16Jun 05 23:57:47 fra1-do1 wireguard-ui[4388]: Email from        :
17Jun 05 23:57:47 fra1-do1 wireguard-ui[4388]: Email from name        : WireGuard UI
18Jun 05 23:57:47 fra1-do1 wireguard-ui[4388]: Custom wg.conf        :
19Jun 05 23:57:47 fra1-do1 wireguard-ui[4388]: Base path        : /
20Jun 05 23:57:49 fra1-do1 wireguard-ui[4388]: ⇨ http server started on 127.0.0.1:5000

If everything works well, you can see that WireGuard-UI is listening on 127.0.0.1:5000 (but, for now, you cannot access the web UI from remote machine until you finished the Configuring Nginx for WireGuard-UI section below).

Make wireguard-ui-daemon.service run at start up:

1sudo systemctl enable wireguard-ui-daemon.service

Auto Restart WireGuard Daemon

Because WireGuard-UI only takes care of WireGuard configuration generation, another systemd is required to watch for the changes and restart the WireGuard service. Create /etc/systemd/system/wgui.service and fill with this following example:

 1[Unit]
 2Description=Restart WireGuard
 3After=network.target
 4
 5[Service]
 6Type=oneshot
 7ExecStart=/usr/bin/systemctl restart [email protected]
 8
 9[Install]
10RequiredBy=wgui.path

Then, create /etc/systemd/system/wgui.path:

1[Unit]
2Description=Watch /etc/wireguard/wg0.conf for changes
3
4[Path]
5PathModified=/etc/wireguard/wg0.conf
6
7[Install]
8WantedBy=multi-user.target

Apply systemd configurations changes by issuing this following commands:

1systemctl daemon-reload
2systemctl enable wgui.{path,service}
3systemctl start wgui.{path,service}

Configuring Nginx for WireGuard-UI

If Nginx not installed on your server, you need to install it first. You can use Nginx from Ubuntu default repository or using Nginx official repository for Ubuntu.

After Nginx installed, create Nginx virtual host server block for WireGuard UI:

 1server {
 2    listen 80;
 3    server_name wgui.example.com;
 4    root /usr/share/nginx;
 5    access_log off;
 6    location /.well-known/acme-challenge/ { allow all; }
 7    location / { return 301 https://$host$request_uri; }
 8}
 9
10server {
11    listen 443 ssl http2;
12    server_name wgui.example.com;
13    access_log off;
14
15    ssl_certificate     /path/to/your/ssl/cert/fullchain.pem;
16    ssl_certificate_key /path/to/your/ssl/cert/privkey.pem;
17
18    root /usr/share/nginx;
19    location / {
20        add_header Cache-Control no-cache;
21
22        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
23        proxy_set_header X-Forwarded-Proto $scheme;
24        proxy_set_header X-Real-IP $remote_addr;
25        proxy_set_header Host $http_host;
26        proxy_pass http://127.0.0.1:5000/;
27    }
28}
  • Replace wgui.example.com with your (sub)domain name.
  • Replace ssl_certificate and ssl_certificate_key with your certificate files.

Now restart your nginx configuration sudo systemctl restart nginx.

Please note that Nginx server block configuration above is very basic config. If you need recommended SSL configuration for Nginx, follow this Mozilla SSL Configuration Generator. If you want to use Let’s Encrypt certificate, install python3-certbot-nginx and request your certificate using certbot --nginx -d wgui.example.com.

Using WireGuard-UI

Now after configuring all those required services, it’s time to configure our WireGuard config using WireGuard-UI. Go to your WireGuard-UI (sub)domain and login with username and password you’ve configured before from /etc/wireguard-ui/.env.

Do not press “Apply Config” before you finished configuring your WireGuard setting from WireGuard UI.

Go to “WireGuard Server” page and configure WireGuard config:

  • Server Interface Addresses: 10.10.88.1/24
  • Listen Port: 51822
  • Post Up Script: /opt/wireguard-ui/postup.sh
  • Post Down Script: /opt/wireguard-ui/postdown.sh

WireGuard-UI Server Settings

Then go to “Global Settings”, verify that all your config is correct (especially for “Endpoint Address” and “WireGuard Config File Path”).

After that, try to Apply your configuration.

Verify that everything is running (try to check using wg show or ss -ulnt from command-line).

Creating Peer (client)

Creating peers using WireGuard UI is pretty simple, all you need to do is press "+ New Client" button from the top right of the page and fill required information. You only need to fill “Name” field for most use case.

After adding your peers (clients), press “Apply Config” and try to connect to your WireGuard VPN server from your devices. The configuration file for your devices can be downloaded from WireGuard UI. You can also easily scan configuration for your mobile devices by scanning configuration QR code.

WireGuard UI clients page

What next? How about Configure WireGuard VPN Clients?