Set Up Your Own WireGuard VPN Server on Ubuntu

This tutorial is going to show you how to set up your own WireGuard VPN server on Ubuntu. WireGuard is made specifically for the Linux kernel. It runs inside the Linux kernel and allows you to create fast, modern, and secure VPN tunnel.

Features of WireGuard VPN

  • Lightweight and super fast speed, blowing OpenVPN out of the water.
  • Cross-platform. WireGuard can run on Linux, BSD, macOS, Windows, Android, iOS, and OpenWRT.
  • User authentication is done by exchanging public keys, similar to SSH keys.
  • It assigns static tunnel IP addresses to VPN clients. Some folks may not like it, but it can be useful in some cases.
  • Mobile devices can switch between Wi-Fi and mobile network seamlessly without dropping any connectivity.
  • It aims to replace OpenVPN and IPSec in most use cases.

Prerequisites

This tutorial assumes that the VPN server and VPN client are both running Ubuntu operating system.

Step 1: Install WireGuard on Ubuntu Server and Desktop

Log into your Ubuntu server, then run the following commands to install WireGuard.

Ubuntu 20.04

sudo apt update
sudo apt install wireguard wireguard-tools

Ubuntu 18.04/16.04

sudo apt install software-properties-common
sudo add-apt-repository ppa:wireguard/wireguard -y
sudo apt update
sudo apt install wireguard wireguard-tools wireguard-dkms

Ubuntu 18.04/16.04 will automatically build the wireguard module into the Linux kernel with the help of wireguard-dkms. Ubuntu 20.04 ships with a Linux kernel that has a built-in wireguard module, so you don’t need to install the wireguard-dkms package on Ubuntu 20.04.

Then use the same commands to install WireGuard on your local Ubuntu computer (the VPN client). Note that you also need to install the openresolv package on the client to configure DNS server.

sudo apt install openresolv

Step 2: Generate Public/Private Keypair

Server

Run the following command on the Ubuntu server to create a public/private key pair, which will be saved under /etc/wireguard/ directory.

wg genkey | sudo tee /etc/wireguard/server_private.key | wg pubkey | sudo tee /etc/wireguard/server_public.key

wireguard VPN server generate public private key

Client

Run the following command to create a public/private key pair on the local Ubuntu computer (the VPN client).

wg genkey | sudo tee /etc/wireguard/client_private.key | wg pubkey | sudo tee /etc/wireguard/client_public.key

Step 3: Create WireGuard Configuration File

Server

Use a command-line text editor like Nano to create a WireGuard configuration file on the Ubuntu server. wg0 will be the network interface name.

sudo nano /etc/wireguard/wg0.conf

Copy the following text and paste it to your configuration file. You need to use your own server private key and client public key.

[Interface]
Address = 10.10.10.1/24
SaveConfig = true
PrivateKey = UIFH+XXjJ0g0uAZJ6vPqsbb/o68SYVQdmYJpy/FlGFA=
ListenPort = 51820

[Peer]
PublicKey = 75VNV7HqFh+3QIT5OHZkcjWfbjx8tc6Ck62gZJT/KRA=
AllowedIPs = 10.10.10.2/32

ubuntu wireguard VPN server configuration file

Where:

  • Address: Specify the private IP address of the VPN server. Here I’m using the 10.10.10.0/24 network range, so it won’t conflict with your home network range. (Most home routers use 192.168.0.0/24 or 192.168.1.0/24). 10.10.10.1 is the private IP address for the VPN server.
  • SaveConfig: the configuration should be saved on shutdown using the current status of the interface.
  • PrivateKey: The private key of VPN server, which can be found in the /etc/wireguard/server_private.key file on the server.
  • ListenPort: WireGuard VPN server will be listening on UDP port 51820, which is the default.
  • PublicKey: The public key of VPN client, which can be found in the /etc/wireguard/client_public.key file on the client computer.
  • AllowedIPs: IP addresses the VPN client is allowed to use. In this example, the client can only use the 10.10.10.2 IP address inside the VPN tunnel.

Save and close the file. (To save a file in Nano text editor, press Ctrl+O, then press Enter to confirm. Press Ctrl+X to exit.)

Change the file permission mode so that only root user can read the files.

sudo chmod 600 /etc/wireguard/ -R

Client

Use a command-line text editor like Nano to create a WireGuard configuration file on your local Ubuntu computer. wg-client0 will be the network interface name.

sudo nano /etc/wireguard/wg-client0.conf

Copy the following text and paste it to your configuration file. You need to use your own client private key and server public key.

[Interface]
Address = 10.10.10.2/24
DNS = 10.10.10.1
PrivateKey = cOFA+x5UvHF+a3xJ6enLatG+DoE3I5PhMgKrMKkUyXI=

[Peer]
PublicKey = RaoAdsIEIwgV9DHNSubxWVG+nZ1GP/c3OU6A/efBJ0I=
AllowedIPs = 0.0.0.0/0
Endpoint = 12.34.56.78:51820
PersistentKeepalive = 25

Where:

  • Address: Specify the private IP address of the VPN client.
  • DNS: specify 10.10.10.1 (VPN server) as the DNS server. It will be configured via the resolvconf command.
  • PrivateKey: The client’s private key, which can be found in the /etc/wireguard/client_private.key file on the client computer.
  • PublicKey: The server’s public key, which can be found in the /etc/wireguard/server_public.key file on the server.
  • AllowedIPs: 0.0.0.0/0 represents the whole Internet, which means all traffic to the Internet should be routed via the VPN.
  • Endpoint: The public IP address and port number of VPN server. Replace 12.34.56.78 with your server’s real public IP address.
  • PersistentKeepalive: Send an authenticated empty packet to the peer every 25 seconds to keep the connection alive. If PersistentKeepalive isn’t enabled, the VPN server might not be able to ping the VPN client.

Save and close the file.

Change the file mode so that only root user can read the files.

sudo chmod 600 /etc/wireguard/ -R

Step 4: Enable IP Forwarding on the Server

In order for the VPN server to route packets between VPN clients and the Internet, we need to enable IP forwarding. Edit sysctl.conf file.

sudo nano /etc/sysctl.conf

Add the following line at the end of this file.

net.ipv4.ip_forward = 1

Save and close the file. Then apply the changes with the below command. The -p option will load sysctl settings from /etc/sysctl.conf file. This command will preserve our changes across system reboots.

sudo sysctl -p

Step 5: Configure IP Masquerading on the Server

We need to set up IP masquerading in the server firewall, so that the server becomes a virtual router for VPN clients. I will use UFW, which is a front end to the iptables firewall. Install UFW on Ubuntu with:

sudo apt install ufw

First, you need to allow SSH traffic.

sudo ufw allow 22/tcp

Then edit /etc/default/ufw file.

sudo nano /etc/default/ufw

Change the default forward policy from “DROP” to “ACCEPT”.

DEFAULT_FORWARD_POLICY="ACCEPT"

Save and close the file. Next, find the name of your server’s main network interface.

ip addr

As you can see, it’s named ens3 on my Ubuntu server.

ubuntu wireguard firewall

To configure IP masquerading, we have to add iptables command in a UFW configuration file.

sudo nano /etc/ufw/before.rules

By default, there are some rules for the filter table. Add the following lines at the end of this file. Replace ens3 with your own network interface name.

# NAT table rules
*nat
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING -o ens3 -j MASQUERADE

# End each table with the 'COMMIT' line or these rules won't be processed
COMMIT

In Nano text editor, you can go to the end of the file by pressing Ctrl+W, then pressing Ctrl+V.

UFW NAT table POSTROUTING MASQUERADE

The above lines will append (-A) a rule to the end of of POSTROUTING chain of nat table. It will link your virtual private network with the Internet. And also hide your network from the outside world. So the Internet can only see your VPN server’s IP, but can’t see your VPN client’s IP, just like your home router hides your private home network.

Save and close the file. Then enable UFW.

sudo ufw enable

If you have enabled UFW before, then you can use systemctl to restart UFW.

sudo systemctl restart ufw

Now if you list the rules in the POSTROUTING chain of the NAT table by using the following command:

sudo iptables -t nat -L POSTROUTING

You can see the Masquerade rule.

wireguard-IP-Masquerading-ufw-ubuntu

Step 6: Install a DNS Resolver on the Server

Since we specify the VPN server as the DNS server for client, we need to run a DNS resolver on the VPN server. We can install the bind9 DNS server.

sudo apt install bind9

Once it’s installed, BIND will automatically start. You can check its status with:

systemctl status bind9

Sample output:

 named.service - BIND Domain Name Server
     Loaded: loaded (/lib/systemd/system/named.service; enabled; vendor preset: enabled)
     Active: active (running) since Sun 2020-05-17 08:11:26 UTC; 37s ago
       Docs: man:named(8)
   Main PID: 13820 (named)
      Tasks: 5 (limit: 1074)
     Memory: 14.3M
     CGroup: /system.slice/named.service
             └─13820 /usr/sbin/named -f -u bind

If it’s not running, start it with:

sudo systemctl start bind9

Edit the BIND DNS server’s configuration file.

sudo nano /etc/bind/named.conf.options

Add the following line to allow VPN clients to send recursive DNS queries.

allow-recursion { 127.0.0.1; 10.10.10.0/24; };

wireguard BIND DNS resolver

Save and close the file. Restart BIND9 for the changes to take effect.

sudo systemctl restart bind9

Then you need to run the following command to allow VPN clients to connect to port 53.

sudo ufw insert 1 allow in from 10.10.10.0/24

Step 7: Open WireGuard Port in Firewall

Run the following command to open UDP port 51820 on the server.

sudo ufw allow 51820/udp

Step 8: Start WireGuard

server

Run the following command on the server to start WireGuard.

sudo wg-quick up /etc/wireguard/wg0.conf

To stop it, run

sudo wg-quick down /etc/wireguard/wg0.conf

You can also use systemd service to start WireGuard.

sudo systemctl start [email protected]

Enable auto-start at system boot time.

sudo systemctl enable [email protected]

Check its status with the following command. Its status should be active (exited).

systemctl status [email protected]

Now WireGuard server is ready to accept client connections.

Client

Start WireGuard.

sudo systemctl start [email protected]

Enable auto-start at system boot time.

sudo systemctl enable [email protected]

Check its status:

systemctl status [email protected]

Now go to this website: http://icanhazip.com/ to check your public IP address. If everything went well, it should display your VPN server’s public IP address instead of your client computer’s public IP address.

Policy Routing

By default, all traffic on the VPN client will be routed through the VPN server. Sometimes you may want to route only a specific type of traffic, based on the transport layer protocol and the destination port. This is known as policy routing.

Policy routing is configured on the client computer, and we need to stop the VPN connection first.

sudo systemctl stop [email protected]

Then edit the client configuration file.

sudo nano /etc/wireguard/wg-client0.conf

For example, if you add the following 3 lines in the [interface] section, then WireGuard will create a routing table named “1234” and add the ip rule into the routing table. In this example, traffic will be routed through VPN server only when TCP is used as the transport layer protocol and the destination port is 25, i.e, when the client computer sends emails.

Table = 1234
PostUp = ip rule add ipproto tcp dport 25 table 1234
PreDown = ip rule delete ipproto tcp dport 25 table 1234

wireguard-vpn-policy-routing-ubuntu

Note: The client should be running Ubuntu 20.04 or up in order to configure policy routing. The ip utility on Ubuntu 18.04 doesn’t support the ipproto and dport argument.

Save and close the file. Then start the WireGuard client.

sudo systemctl start [email protected]

VPN Kill Switch

By default, your computer can access the Internet via the normal gateway when the VPN connection is disrupted. You may want to enable the kill switch feature, which prevents the flow of unencrypted packets through non-WireGuard interfaces.

Stop the WireGuard client process.

sudo systemctl stop [email protected]

Edit the client configuration file.

sudo nano /etc/wireguard/wg-client0.conf

Add the following two lines in the [interface] section.

PostUp = iptables -I OUTPUT ! -o %i -m mark ! --mark $(wg show %i fwmark) -m addrtype ! --dst-type LOCAL -j REJECT
PreDown = iptables -D OUTPUT ! -o %i -m mark ! --mark $(wg show %i fwmark) -m addrtype ! --dst-type LOCAL -j REJECT

Like this:

[Interface]
Address = 10.10.10.2/24
DNS = 10.10.10.1
PrivateKey = cOFA+x5UvHF+a3xJ6enLatG+DoE3I5PhMgKrMKkUyXI=
PostUp = iptables -I OUTPUT ! -o %i -m mark ! --mark $(wg show %i fwmark) -m addrtype ! --dst-type LOCAL -j REJECT
PreDown = iptables -D OUTPUT ! -o %i -m mark ! --mark $(wg show %i fwmark) -m addrtype ! --dst-type LOCAL -j REJECT

[Peer]
PublicKey = RaoAdsIEIwgV9DHNSubxWVG+nZ1GP/c3OU6A/efBJ0I=
AllowedIPs = 0.0.0.0/0
Endpoint = 12.34.56.78:51820
PersistentKeepalive = 25

Save and close the file. Then start the WireGuard client.

sudo systemctl start [email protected]

Wrapping Up

That’s it! I hope this tutorial helped you install and configure WireGuard on Ubuntu. As always, if you found this post useful, then subscribe to our free newsletter to get more tips and tricks 🙂

Rate this tutorial
[Total: 6 Average: 5]

20 Responses to “Set Up Your Own WireGuard VPN Server on Ubuntu

  • What if the server uses a dynamic public IP? I would like to build this in my home server but don’t have a static public IP from my isp.

    • You need a domain name and a dynamic DNS service (such as no-ip.com) to translate the domain name into an IP address. Then in the client configuration file, use your domain name instead of an IP address.

      Endpoint = example.com:51820

      You also need to configure port forwarding (UDP 51820) in your router.

  • Ken Wright
    2 weeks ago

    I’m having a problem with the WireGuard client. When I try to restart it after setting up the VPN Kill Switch, I get an error message. Systemctl status [email protected] tells me there’s a bad integer value for option “–mark”. Is there something I’ve missed?

    • Comment out the PostUp and PreDown lines in the client configuration file. Then stop the WireGuard client process.

      sudo systemctl stop [email protected]

      Edit the client configuration file.

      sudo nano /etc/wireguard/wg-client0.conf

      Uncomment the PostUp and PreDown lines. Save and close the file. Then start the WireGuard client.

      sudo systemctl start [email protected]
  • Ken Wright
    2 weeks ago

    Umm, which PostUp and PreDown lines? There are two each. Here’s the file:

    PostUp = iptables -I OUTPUT ! -o %i -m mark ! --mark $(wg show %i fwmark) -m addrtype ! --dst-type LOCAL -j REJECT
    PreDown = iptables -D OUTPUT ! -o %i -m mark ! --mark $(wg show %i fwmark) -m addrtype ! --dst-type LOCAL -j REJECT
    PostUp = ip rule add ipproto tcp dport 25 table 1234
    PreDown = ip rule delete ipproto tcp dport 25 table 1234

    Am I trying to do too much?

    • Yes, I don’t think policy routing and VPN kill switch should be used together. With policy routing, there is traffic that will need to use the usual Internet connection. However, VPN kill switch is meant to stop the flow of the normal Internet traffic.

      • Ken Wright
        1 week ago

        Okay, I deleted the Policy Routing lines and restarted Wireguard Client unsuccessfully. Here’s the output:

        [email protected] - WireGuard via wg-quick(8) for wg/client0
             Loaded: loaded (/lib/systemd/system/[email protected]; enabled; vendor preset: enabled)
             Active: failed (Result: exit-code) since Fri 2020-05-22 13:33:05 EDT; 3min 46s 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: 24409 ExecStart=/usr/bin/wg-quick up wg-client0 (code=exited, status=2)
           Main PID: 24409 (code=exited, status=2)
        
        May 22 13:33:05 Inspiron-3542 wg-quick[24455]: [#] resolvconf -a wg-client0 -m 0 -x
        May 22 13:33:05 Inspiron-3542 wg-quick[24409]: [#] ip -4 route add 0.0.0.0/0 dev wg-client0 table 1234
        May 22 13:33:05 Inspiron-3542 wg-quick[24409]: [#] iptables -I OUTPUT ! -o wg-client0 -m mark ! --mark $(wg show wg-client0 fwmark) -m addrtype ! --dst-type LOCAL -j REJECT
        May 22 13:33:05 Inspiron-3542 wg-quick[24527]: iptables v1.8.4 (legacy): mark: bad integer value for option "--mark", or out of range.
        May 22 13:33:05 Inspiron-3542 wg-quick[24527]: Try `iptables -h' or 'iptables --help' for more information.
        May 22 13:33:05 Inspiron-3542 wg-quick[24409]: [#] resolvconf -d wg-client0 -f
        May 22 13:33:05 Inspiron-3542 wg-quick[24409]: [#] ip link delete dev wg-client0
        May 22 13:33:05 Inspiron-3542 systemd[1]: [email protected]: Main process exited, code=exited, status=2/INVALIDARGUMENT
        May 22 13:33:05 Inspiron-3542 systemd[1]: [email protected]: Failed with result 'exit-code'.
        May 22 13:33:05 Inspiron-3542 systemd[1]: Failed to start WireGuard via wg-quick(8) for wg/client0.

        I wonder about the “bad integer value” that I see. I’ve obviously done something terribly wrong. What can I do to help figure this out?

    • What’s your output of sudo wg show wg-client0 fwmark? Mine is off

      • Ken Wright
        1 week ago

        I get

        Unable to access interface: No such device

        I must’ve missed something in the article, but I can’t tell what.

        • Ken Wright
          3 days ago

          Still unable to start the WireGuard client.

  • Arc System
    1 week ago

    Many thanks for useful tutorials!
    I just configured Wireguard server/client, but on the client I only can communicate to the server and cannot use/browse the internet as usual. I added the ‘Policy Routing’ to the client but I cannot start Wireguard.
    Error:

    May 22 12:28:15 client01 wg-quick[13658]: [#] ip -4 route add 0.0.0.0/0 dev wg-client0 table 1234
    May 22 12:28:15 client01 wg-quick[13658]: [#] ip rule add ipproto tcp dport 25 table 1234
    May 22 12:28:15 client01 wg-quick[13658]: Error: argument "ipproto" is wrong: Failed to parse rule type
    May 22 12:28:15 client01 wg-quick[13658]: [#] resolvconf -d wg-client0 -f
    May 22 12:28:15 client01 wg-quick[13658]: Too few arguments.
    May 22 12:28:15 client01 wg-quick[13658]: Too few arguments.
    May 22 12:28:15 client01 wg-quick[13658]: [#] ip link delete dev wg-client0
    May 22 12:28:15 client01 systemd[1]: [email protected]: Main process exited, code=exited, status=255/n/a
    May 22 12:28:15 client01 systemd[1]: [email protected]: Failed with result 'exit-code'.
    May 22 12:28:15 client01 systemd[1]: Failed to start WireGuard via wg-quick(8) for wg/client0.
    
    • Is the client running Ubuntu 18.04? I just found that the ip utility on Ubuntu 18.04 doesn’t support the ipproto argument.

      On Ubuntu 20.04, I can find the ipproto argument when checking the man page: man ip-rule. It can’t be found on Ubuntu 18.04.

      • Arc System
        2 days ago

        Yes I’m using Ubuntu 18.04. I don’t think I need Policy Routing now, I just gave it a try.
        But I was able to completely install Wireguard and now I’m using it.
        Thank you for the very comprehensive tutorial!

  • I followed your instruction, but on my ubuntu server, 18.04, shows
    [email protected] – WireGuard via wg-quick(8) for wg0
    Loaded: loaded (/lib/systemd/system/[email protected]; disabled; vendor preset: enabled)
    Active: inactive (dead)
    Docs: man:wg-quick(8)

    So, but the wg0.con shows
    Endpoint = :22935

    from my client, ip address, 192.168.0.18, and try to ping server, 192.168.0.16, and it is not working.

    my client network -rn shows

    Destination Gateway Genmask Flags MSS Window irtt Iface
    0.0.0.0 192.168.2.1 0.0.0.0 UG 0 0 0 eth0
    169.254.0.0 0.0.0.0 255.255.0.0 U 0 0 0 eth0
    192.168.0.0 0.0.0.0 255.255.255.0 U 0 0 0 wg-client0
    192.168.2.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0

    show the 192.168.0.0 gateway should be 192.168.0.1 or 16(server)

    Thanks

  • From my client ip, 192.168.0.17, I should be able to ping or telnet into server ip, 192.168.0.16, Right? But I cannot

  • My bad, use the same ip as my internal lan, rather a separated tunnel.

  • Darth Nagar
    1 day ago

    Hi Xiao Guoan,

    Great turorial, precise, clear and easy to follow.

    I still have a couple of questions:
    1- about DNS: is there a way, in WireGuard server configuration, NOT to alter Client’s DNS like we can do in OpenVPN? I use Stubby for encrypted DNS (I followed your tutoral for that) and I surely do NOT want to use the ones on my Server side.

    2- is there a way to ‘see’ that Wireguard is in use (like you can see when you use OpenVPN a little ‘lock’)?

    Thanks in advance,

    • If you don’t want to use the server-side DNS resolver, edit the WireGuard client configuariton file.

      sudo nano /etc/wireguard/wg-client0.conf

      Remove the following line from the file.

      DNS = 10.10.10.1

      Save and close the file. Then restart WireGuard client.

      sudo systemctl restart [email protected]

      Actually, using 10.10.10.1 as DNS resolver will also encrypt your DNS queries. I don’t think you need to stick with Stubby.

      When the VPN client is running in command line mode, there’s no way to indicate that you are using VPN on your desktop environment. The only way to know is to check your current public IP address.

      • Darth Nagar
        20 hours ago

        Thanks for your answers.
        It seems clear if I don’t use the DNS line in the client conf, it does mean then WireGuard on the Server side will use the DNS from my client, right?
        Besides, I keep Stubby for my OpenVPN connection

    • No. The server will use its own DNS resolver.

Leave a Comment

  • Comments with links are moderated by admin before published.
  • Your email address will not be published.
  • Use <pre> ... </pre> HTML tag to quote the output from your terminal/console.
  • Please use the community (https://community.linuxbabe.com) for questions unrelated to this article.
  • I don't have time to answer every question. Making a donation would incentivize me to spend more time answering questions.