WireGuard Tunnel

Revision as of 20:09, 5 January 2025 by Spy (talk | contribs) (Actually write the wireguard tunnel article)

WIP Welcome to the official guide on setting up a WireGuard Tunnel. This is useful if you do not want to directly port forward to the internet (e.g. using your own IP to host UserVMs).

These instructions are specifically tailored to Linux machines, with nftables.

Prerequisites

You'll need:

  • A server machine that has the IP address you want to use for hosting
  • At least one client machine.
  • Basic knowledge of how computers and Linux systems work.

Preparation

Install Dependencies

First up make sure you have wireguard-tools installed on both your server machine, and your client machines.

$ sudo pacman --needed --noconfirm -Sy wireguard-tools # Arch
$ sudo apt-get install -y wireguard-tools # Debian

Enable IP Forwarding

This is only necessary on the server machine, unless you will be hosting UserVMs. In that case, you might want to enable it on your client as well.

As root, do the following.

# sysctl -w net.ipv4.ip_forward=1

To make your changes persistent, you will need to edit your sysctl conf file(s). On Ubuntu, you can find ipv4 forwarding commented out in /etc/sysctl.conf

Key Setup

Now we can begin the actual setup.

On your server machine AND your client machine, as root, do the following steps separately.

# mkdir -p /etc/wireguard/keys/wg0
# cd /etc/wireguard/keys/wg
# umask 077
# wg genkey > private.key
# wg pubkey < private.key > public.key

Server wg0.conf

For demonstration purposes, we will be using 10.0.32.0/24 as our subnet. The server will have 10.0.32.1 assigned on the wg0 interface.

Create /etc/wireguard/wg0.conf and put the following in it.

[Interface]
PrivateKey =  <paste server private.key> 
Address = 10.0.32.1/32
ListenPort = 51820

For every client you will connect, you also want to add this. For demonstration purposes, our first client will have 10.0.32.2 assigned.

[Peer]
PublicKey = <paste client's public.key>
AllowedIPs = 10.0.32.2/32

Repeat for each client, making sure to give each client a different ip address.

Bringing Your WireGuard Server Up

Now that we have configured our server, we can start the WireGuard service. Run the following as root to start the WireGuard service on a systemd machine.

# systemctl enable --now wg-quick@wg0

Run # journalctl -xeu wg-quick@wg0 to make sure that WireGuard started properly.

Client wg0.conf

Now, on your client(s), create /etc/wireguard/wg0.conf as well and put the following in. For demonstration purposes, we are using 10.0.32.2 once more.

[Interface]
PrivateKey = (paste client's private.key)
Address = 10.0.32.2/24

[Peer]
PublicKey = (paste server's public.key)
AllowedIPs = 10.0.32.0/24
Endpoint = <server ip>:51820

Once this is done, start the WireGuard service on the client as well. If everything is set up properly, you should be able to ping 10.0.32.1 on the client machine.

# systemctl enable --now wg-quick@wg0

If the connection isn't properly established, you should check if you have properly opened port 51820 on the server. This port is UDP.

After pinging 10.0.32.1, you should also do # wg show to make sure the handshake is successfully established.

Server nftables Configuration

Now that we have successfully established a link between the WireGuard server and our client, it is time to set up nftables on the server.

We must note first, however, that eth0 in the code snippet below is the interface that is connected to the internet on the server. This may be different between systems, so change it to match. To get internet access working on the client before we route all traffic through the server, we must add this to nftables on the server.

table inet nat {
    chain postrouting {
      type nat hook postrouting priority srcnat; policy accept;
      meta iifname wg0 meta oifname eth0 snat ip to <server ip here>
    }
}

The following is an example of what /etc/nftables.conf could look like as a result.

#!/usr/sbin/nft -f

flush ruleset

table inet filter {
        chain input {
                type filter hook input priority filter;
        }
        chain forward {
                type filter hook forward priority filter;
        }
        chain output {
                type filter hook output priority filter;
        }
}

table inet nat {
    chain postrouting {
      type nat hook postrouting priority srcnat; policy accept;
      meta iifname wg0 meta oifname eth0 snat ip to <server ip here>
    }
}

Final Client Changes

At this point, you are encouraged to test via the client whether you can reach the internet. If you can afford to lose internet on the client, you can change AllowedIPs in /etc/wireguard/wg0.conf to 0.0.0.0/0.

An example is provided of what this should look like afterward.

[Interface]
PrivateKey = client private key
Address = 10.0.32.2/24

[Peer]
PublicKey = server public key
AllowedIPs = 0.0.0.0/0
Endpoint = server ip:51820

If this does in fact work, then you have successfully completed your WireGuard tunnel.

Extras

While by this point you may have already set up the tunnel, there are some things you might want to add on to the setup. For example, you might want to pass through ports from your client to the server.

Port Forwarding

This is what the nftables rule would look like for forwarding a port from a specified client machine to the internet. This is done on the server machine. For this example, we are using port 6004 (Standard CVM server port) and 10.0.32.2 which is our client machine.

table inet nat {
  chain prerouting {
    type nat hook prerouting priority dstnat; policy accept;
    meta iifname eth0 tcp dport 6004 dnat ip to 10.0.32.2
  }
}

This is what the nat table should look like in the end. Your result may be different depending on your setup. Note the new prerouting chain before the postrouting chain.

table inet nat {
        chain prerouting {
                type nat hook prerouting priority dstnat; policy accept;
                meta iifname eth0 tcp dport 6004 dnat ip to 10.0.32.2
        }

        chain postrouting {
                type nat hook postrouting priority srcnat; policy accept;
                meta iifname wg0 meta oifname eth0 snat ip to SERVERIPHERE
        }
}

You can test if the port forward is working by running netcat -l -p 6004 on the client that you forwarded the port from. If the port forward is working properly, netcat SERVERIPHERE 6004 should allow you to send messages back and forth from both machines. You can also test this by setting up a UserVM on your client with the UserVM Handbook.

WIP

I don't really have much else here, feel free to contribute to this page.