WireGuard Tunnel: Difference between revisions

From Computernewb Wiki
Jump to navigation Jump to search
m (small note)
No edit summary
Line 1: Line 1:
This guide will instruct you on how to set up a WireGuard tunnel between a server machine and one or more clients. This establishes a secure tunnel between the machines (connecting them as if they were on the same LAN), and can further be used to route traffic and forward ports.
WIP


These instructions are specifically tailored to Linux machines.
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 ==
== Prerequisites ==
You'll need:
You'll need:
*A server machine that has the IP address you want to use for hosting
*A server machine that will host the WireGuard endpoint
*At least one client machine.
*At least one client machine.
*Basic knowledge of how computers and Linux systems work.
*Basic knowledge of how computers and Linux systems work.


== Preparation ==
== Setting up the tunnel ==

For the purposes of this guide, we are calling our tunnel <code>wg0</code>. If you would like to use a different name, make sure to substitute <code>wg0</code> with the interface name of your choice in all commands and config files.

We will be using <code>10.0.32.0/24</code> as our WireGuard subnet for the purposes of this guide.


=== Install Dependencies ===
=== Install Dependencies ===
First up make sure you have wireguard-tools installed on both your server machine, and your client machines.
First, make sure you have wireguard-tools and nftables installed on both your server machine, and your client machines.
{{code|lang=bash|<nowiki>
{{code|lang=bash|<nowiki>
$ sudo pacman --needed --noconfirm -Sy wireguard-tools # Arch
$ sudo pacman --needed --noconfirm -Sy wireguard-tools nftables # Arch
$ sudo apt-get install -y wireguard-tools # Debian
$ sudo apt-get install -y wireguard-tools nftables # Debian
</nowiki>
</nowiki>
}}
}}


=== Enable IP Forwarding ===
=== Generating the Keys ===
Now, we need to generate a public and private key for each system that will be in the tunnel. You can use these commands on each computer, as root:
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.


{{code|lang=bash|<nowiki>
As root, do the following.
$ sudo -i
{{code|<nowiki>
# mkdir -p /etc/wireguard/keys/wg0 # Create a directory for the keys
# sysctl -w net.ipv4.ip_forward=1
</nowiki>
}}

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 <code>/etc/sysctl.conf</code>

== Setting Up The Tunnel ==

=== Key Setup ===
Now we can begin the actual setup.

On your server machine AND your client machine, as root, do the following steps separately.
{{code|lang=bash|
# mkdir -p /etc/wireguard/keys/wg0
# cd /etc/wireguard/keys/wg
# cd /etc/wireguard/keys/wg
# umask 077 # Temporarily set the default permissions for all files to rwx------
# umask 077
# wg genkey > private.key
# wg genkey</nowiki> > <nowiki>private.key # Generate the private key
# wg pubkey < private.key > public.key
# wg pubkey</nowiki> < <nowiki>private.key</nowiki> > <nowiki>public.key # Derive the public key from the private key
}}


# cat private.key
=== Server wg0.conf ===
/ExampleServerPrivateKey=
For demonstration purposes, we will be using <code>10.0.32.0/24</code> as our subnet. The server will have <code>10.0.32.1</code> assigned on the wg0 interface.
# cat public.key
/ExampleServerPublicKey=
</nowiki>}}


=== Configuring the tunnel (Server) ===
Create <code>/etc/wireguard/wg0.conf</code> and put the following in it.
On your server machine, create <code>/etc/wireguard/wg0.conf</code> and put the following in it.


{{code|lang=ini|
{{code|lang=ini|
[Interface]
[Interface]
<nowiki>PrivateKey = </nowiki> <paste server private.key> <nowiki>
<nowiki>PrivateKey = </nowiki> <Paste your private.key from the SERVER> <nowiki>
Address = 10.0.32.1/32
Address = 10.0.32.1/32
ListenPort = 51820
ListenPort = 51820
</nowiki>
</nowiki>
}}
}}
This will assign your WireGuard server with the IP <code>10.0.32.1</code> on the WireGuard tunnel, and listen on UDP port <code>51820</code>


Next, add the clients. In the server's wg0.conf, add the following for each client:
You can use <code>cat private.key</code> and copy the output of this command to paste in the key.



For every client you will connect, you also want to add this. For demonstration purposes, our first client will have <code>10.0.32.2</code> assigned.
{{code|lang=ini|
{{code|lang=ini|
[Peer]
[Peer]
<nowiki>PublicKey =</nowiki> <paste client's public.key>
<nowiki>PublicKey =</nowiki> <Paste the PUBLIC key from the CLIENT>
<nowiki>AllowedIPs = 10.0.32.2/32</nowiki>
<nowiki>AllowedIPs = 10.0.32.2/32</nowiki>
}}
}}
Repeat for each client, making sure to give each client a different ip address.


This will give the specified client an IP address of <code>10.0.32.2</code> on the WireGuard tunnel. Make sure you increment this for each client and use the correct public keys.
=== 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.
{{code|lang=bash|
# systemctl enable --now wg-quick@wg0
}}


Here is an example of a completed server wg0.conf:
Run <code># journalctl -xeu wg-quick@wg0</code> to make sure that WireGuard started properly.


{{code|lang=ini|<nowiki>
=== Client wg0.conf ===
[Interface]
Now, on your client(s), create <code>/etc/wireguard/wg0.conf</code> as well and put the following in. For demonstration purposes, we are using <code>10.0.32.2</code> once more.
PrivateKey = /ExampleServerPrivateKey=
Address = 10.0.32.1/32
ListenPort = 51820

[Peer]
PublicKey = /ExampleClientPublicKey1=
AllowedIPs = 10.0.32.2/32

[Peer]
PublicKey = /ExampleClientPublicKey2=
AllowedIPs = 10.0.32.3/32

[Peer]
PublicKey = /ExampleClientPublicKey3=
AllowedIPs = 10.0.32.4/32
</nowiki>}}

=== Configuring the tunnel (Client) ===
Now, on your client(s), create <code>/etc/wireguard/wg0.conf</code> as well and put the following in
{{code|lang=ini|
{{code|lang=ini|
[Interface]
[Interface]
<nowiki>PrivateKey =</nowiki> (paste client's private.key)
<nowiki>PrivateKey =</nowiki> <Paste your PRIVATE key from THIS CLIENT>
<nowiki>Address = 10.0.32.2/24</nowiki>
<nowiki>Address = 10.0.32.2/24</nowiki>


<nowiki>[Peer]
<nowiki>[Peer]
PublicKey =</nowiki> (paste server's public.key)
PublicKey =</nowiki> <Paste the PUBLIC key from the SERVER>
<nowiki>AllowedIPs = 10.0.32.0/24
<nowiki>AllowedIPs = 10.0.32.0/24
Endpoint =</nowiki> <server ip>:51820
Endpoint =</nowiki> <Your server's IP address>:51820
}}
}}


Make SURE to use the correct combination of IP address and private key defined in a <code>[Peer]</code> section in the server configuration.
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.
=== Bringing Your WireGuard Tunnel Up ===
Now that we have configured our server and clients, we can start the tunnel. The following command will start the tunnel, and configure it to be started on every boot. Run it on your server and all your clients.

{{code|lang=bash|
{{code|lang=bash|
# systemctl enable --now wg-quick@wg0
sudo 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 <code># wg show</code> to make sure the handshake is successfully established.
Run <code>sudo systemctl status wg-quick@wg0</code> to make sure that WireGuard started properly.


== Traffic Routing ==
=== Test the connection ===


Assuming everything started correctly, each machine should now have a <code>wg0</code> interface with the correct IP assigned to it. Test the connection from one of the clients with ping:
=== 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.


{{code|lang=bash|<nowiki>
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.
$ ping 10.0.32.1
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.
PING 10.0.32.1 (10.0.32.1) 56(84) bytes of data.
{{code|lang=ini|
64 bytes from 10.0.32.1: icmp_seq=1 ttl=64 time=1.99 ms
64 bytes from 10.0.32.1: icmp_seq=2 ttl=64 time=1.81 ms
64 bytes from 10.0.32.1: icmp_seq=3 ttl=64 time=1.76 ms
(...)
</nowiki>}}


If all went well, congratulations! You now have a secure tunnel between your server and all of your WireGuard clients. Continue reading for how to configure it to your liking
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>
}
}


== Routing traffic ==
You may want to set up your WireGuard server as a router, so that all outbound traffic from one or more of your clients goes through the server (the common definition of a VPN). This is very easy to do.

=== Enable IP Forwarding ===
First, we enable IP forwarding on the server machine. This instructs the Linux kernel that when it receives a packet from one of your clients destined to the internet, it should route that packet to its destination.

Run the following command to enable IP forwarding in the sysctl configuration:
{{code|lang=bash|<nowiki>
echo 'net.ipv4.ip_forward = 1' | sudo tee /etc/sysctl.d/router.conf
sudo sysctl --system
</nowiki>
}}
}}


=== Configuring SNAT ===
The following is an example of what <code>/etc/nftables.conf</code> could look like as a result.
With IP forwarding enabled, the next step is to set an SNAT rule. This instructs the server that when it routes a packet from your client to the internet, it should also replace the source IP address (the client's internal WireGuard IP) with its own public IP. This can be accomplished through the NFTables firewall.
{{code|lang=ini|
#!/usr/sbin/nft -f


First, get the name of the server's internet-facing network interface, and it's public IP address. For example, we will use <code>eth0</code> as the interface.
flush ruleset


Now, open <code>/etc/nftables.conf</code> and configure as follows:
table inet filter {
{{code|lang=ini|
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 {
table inet nat {
chain postrouting {
chain postrouting {
type nat hook postrouting priority srcnat; policy accept;
type nat hook postrouting priority srcnat; policy accept;
meta iifname wg0 meta oifname eth0 snat ip to <server ip here>
meta iifname wg0 meta oifname eth0 snat ip to <Enter server's public IP address here>
}
}
}
}

}}
}}


Reload the NFTables configuration:
=== 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 <code>AllowedIPs</code> in <code>/etc/wireguard/wg0.conf</code> to <code>0.0.0.0/0</code>.


{{code|lang=bash|
An example is provided of what this should look like afterward.
sudo nft -f /etc/nftables.conf
}}


Depending on distro and prior configuration, you may already have a <code>table inet nat</code> block, and possibly a <code>chain postrouting</code> inside it. In this case, merge the above configuration with your own. Otherwise, paste the above snippet into the bottom of the file.
{{code|lang=ini|

<nowiki>
=== Configure the client route ===

Now, all you need to do is configure WireGuard on the client to route all traffic through the server. You do this by configuring the <code>[Peer]</code> section on the client to have an <code>AllowedIPs</code> value of <code>0.0.0.0/0</code>. For example:

{{code|lang=ini|<nowiki>
[Interface]
[Interface]
PrivateKey = client private key
PrivateKey = /ExampleClientPrivateKey1=
Address = 10.0.32.2/24
Address = 10.0.32.2/24


[Peer]
[Peer]
PublicKey = server public key
PublicKey = /ExampleServerPublicKey=
AllowedIPs = 0.0.0.0/0
AllowedIPs = 0.0.0.0/0
Endpoint = server ip:51820 </nowiki>
Endpoint = server ip:51820
</nowiki>}}

Restart the WireGuard tunnel on the client:

{{code|lang=bash|
sudo systemctl restart wg-quick@wg0
}}
}}


If all went well, all traffic on the client should now be routed through the server:
If this does in fact work, then you have successfully completed your WireGuard tunnel.


{{code|<nowiki>
== Extras ==
$ curl ipinfo.io/what-is-my-ip
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.
{
"ip": "143.244.47.86",
"hostname": "unn-143-244-47-86.datapacket.com",
"city": "Weehawken",
"region": "New Jersey",
"country": "US",
"loc": "40.7696,-74.0204",
"org": "AS212238 Datacamp Limited",
"postal": "07086",
"timezone": "America/New_York",
"readme": "https://ipinfo.io/missingauth"
}
</nowiki>}}

== Port Forwarding ==
You may want to forward ports on your server's public IP to the guest. This is very easy to do. We will update the server's NFTables configuration to set a DNAT rule. The following example will forward TCP ports 80 and 443 to the client at <code>10.0.32.2</code>.
{{code|lang=ini|


=== 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 <code>6004</code> (Standard CVM server port) and <code>10.0.32.2</code> which is our client machine.
{{code|lang=bash|
table inet nat {
table inet nat {
chain prerouting {
chain prerouting {
type nat hook prerouting priority dstnat; policy accept;
type nat hook prerouting priority dstnat; policy accept;
meta iifname eth0 tcp dport 6004 dnat ip to 10.0.32.2
meta iifname eth0 tcp dport { 80, 443 } dnat ip to 10.0.32.2
}
}
}
}

}}
}}


Make sure to change <code>eth0</code> to your server's public interface if it differs. Note that this rule goes into the <code>prerouting</code> chain, NOT the previously used <code>postrouting</code> chain.
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.
Reload the NFTables configuration:

{{code|lang=bash|
{{code|lang=bash|
sudo nft -f /etc/nftables.conf
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
}
}
}}
}}


If all went well, connections to ports 80 and 443 on the server's public IP should now be forwarded to the HTTP server running on the client at <code>10.0.32.2</code>.
You can test if the port forward is working by running <code>netcat -l -p 6004</code> on the client that you forwarded the port from. If the port forward is working properly, <code>netcat SERVERIPHERE 6004</code> 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.

Revision as of 21:02, 5 January 2025

This guide will instruct you on how to set up a WireGuard tunnel between a server machine and one or more clients. This establishes a secure tunnel between the machines (connecting them as if they were on the same LAN), and can further be used to route traffic and forward ports.

These instructions are specifically tailored to Linux machines.

Prerequisites

You'll need:

  • A server machine that will host the WireGuard endpoint
  • At least one client machine.
  • Basic knowledge of how computers and Linux systems work.

Setting up the tunnel

For the purposes of this guide, we are calling our tunnel wg0. If you would like to use a different name, make sure to substitute wg0 with the interface name of your choice in all commands and config files.

We will be using 10.0.32.0/24 as our WireGuard subnet for the purposes of this guide.

Install Dependencies

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

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

Generating the Keys

Now, we need to generate a public and private key for each system that will be in the tunnel. You can use these commands on each computer, as root:

$ sudo -i
# mkdir -p /etc/wireguard/keys/wg0 # Create a directory for the keys
# cd /etc/wireguard/keys/wg
# umask 077 # Temporarily set the default permissions for all files to rwx------
# wg genkey > private.key # Generate the private key
# wg pubkey < private.key > public.key # Derive the public key from the private key

# cat private.key
/ExampleServerPrivateKey=
# cat public.key
/ExampleServerPublicKey=

Configuring the tunnel (Server)

On your server machine, create /etc/wireguard/wg0.conf and put the following in it.

[Interface]
PrivateKey =  <Paste your private.key from the SERVER> 
Address = 10.0.32.1/32
ListenPort = 51820

This will assign your WireGuard server with the IP 10.0.32.1 on the WireGuard tunnel, and listen on UDP port 51820

Next, add the clients. In the server's wg0.conf, add the following for each client:

[Peer]
PublicKey = <Paste the PUBLIC key from the CLIENT>
AllowedIPs = 10.0.32.2/32

This will give the specified client an IP address of 10.0.32.2 on the WireGuard tunnel. Make sure you increment this for each client and use the correct public keys.

Here is an example of a completed server wg0.conf:

[Interface]
PrivateKey = /ExampleServerPrivateKey=
Address = 10.0.32.1/32
ListenPort = 51820

[Peer]
PublicKey = /ExampleClientPublicKey1=
AllowedIPs = 10.0.32.2/32

[Peer]
PublicKey = /ExampleClientPublicKey2=
AllowedIPs = 10.0.32.3/32

[Peer]
PublicKey = /ExampleClientPublicKey3=
AllowedIPs = 10.0.32.4/32

Configuring the tunnel (Client)

Now, on your client(s), create /etc/wireguard/wg0.conf as well and put the following in

[Interface]
PrivateKey = <Paste your PRIVATE key from THIS CLIENT>
Address = 10.0.32.2/24

[Peer]
PublicKey = <Paste the PUBLIC key from the SERVER>
AllowedIPs = 10.0.32.0/24
Endpoint = <Your server's IP address>:51820

Make SURE to use the correct combination of IP address and private key defined in a [Peer] section in the server configuration.

Bringing Your WireGuard Tunnel Up

Now that we have configured our server and clients, we can start the tunnel. The following command will start the tunnel, and configure it to be started on every boot. Run it on your server and all your clients.

sudo systemctl enable --now wg-quick@wg0

Run sudo systemctl status wg-quick@wg0 to make sure that WireGuard started properly.

Test the connection

Assuming everything started correctly, each machine should now have a wg0 interface with the correct IP assigned to it. Test the connection from one of the clients with ping:

$ ping 10.0.32.1
PING 10.0.32.1 (10.0.32.1) 56(84) bytes of data.
64 bytes from 10.0.32.1: icmp_seq=1 ttl=64 time=1.99 ms
64 bytes from 10.0.32.1: icmp_seq=2 ttl=64 time=1.81 ms
64 bytes from 10.0.32.1: icmp_seq=3 ttl=64 time=1.76 ms
(...)

If all went well, congratulations! You now have a secure tunnel between your server and all of your WireGuard clients. Continue reading for how to configure it to your liking

Routing traffic

You may want to set up your WireGuard server as a router, so that all outbound traffic from one or more of your clients goes through the server (the common definition of a VPN). This is very easy to do.

Enable IP Forwarding

First, we enable IP forwarding on the server machine. This instructs the Linux kernel that when it receives a packet from one of your clients destined to the internet, it should route that packet to its destination.

Run the following command to enable IP forwarding in the sysctl configuration:

echo 'net.ipv4.ip_forward = 1' | sudo tee /etc/sysctl.d/router.conf
sudo sysctl --system

Configuring SNAT

With IP forwarding enabled, the next step is to set an SNAT rule. This instructs the server that when it routes a packet from your client to the internet, it should also replace the source IP address (the client's internal WireGuard IP) with its own public IP. This can be accomplished through the NFTables firewall.

First, get the name of the server's internet-facing network interface, and it's public IP address. For example, we will use eth0 as the interface.

Now, open /etc/nftables.conf and configure as follows:

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

Reload the NFTables configuration:

sudo nft -f /etc/nftables.conf

Depending on distro and prior configuration, you may already have a table inet nat block, and possibly a chain postrouting inside it. In this case, merge the above configuration with your own. Otherwise, paste the above snippet into the bottom of the file.

Configure the client route

Now, all you need to do is configure WireGuard on the client to route all traffic through the server. You do this by configuring the [Peer] section on the client to have an AllowedIPs value of 0.0.0.0/0. For example:

[Interface]
PrivateKey = /ExampleClientPrivateKey1=
Address = 10.0.32.2/24

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

Restart the WireGuard tunnel on the client:

sudo systemctl restart wg-quick@wg0

If all went well, all traffic on the client should now be routed through the server:

$ curl ipinfo.io/what-is-my-ip
{
  "ip": "143.244.47.86",
  "hostname": "unn-143-244-47-86.datapacket.com",
  "city": "Weehawken",
  "region": "New Jersey",
  "country": "US",
  "loc": "40.7696,-74.0204",
  "org": "AS212238 Datacamp Limited",
  "postal": "07086",
  "timezone": "America/New_York",
  "readme": "https://ipinfo.io/missingauth"
}

Port Forwarding

You may want to forward ports on your server's public IP to the guest. This is very easy to do. We will update the server's NFTables configuration to set a DNAT rule. The following example will forward TCP ports 80 and 443 to the client at 10.0.32.2.

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

Make sure to change eth0 to your server's public interface if it differs. Note that this rule goes into the prerouting chain, NOT the previously used postrouting chain.

Reload the NFTables configuration:

sudo nft -f /etc/nftables.conf

If all went well, connections to ports 80 and 443 on the server's public IP should now be forwarded to the HTTP server running on the client at 10.0.32.2.