WireGuard Tunnel: Difference between revisions
m (small note) |
No edit summary |
||
(4 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
{{ReadItAll}} |
|||
WIP |
|||
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. |
|||
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 |
These instructions are specifically tailored to Linux machines. |
||
== Prerequisites == |
== Prerequisites == |
||
You'll need: |
You'll need: |
||
*A server machine that |
*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. |
||
== |
== 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 |
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> |
||
}} |
}} |
||
=== |
=== 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. |
|||
As root, do the following. |
|||
{{code|<nowiki> |
|||
# 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 == |
|||
{{code|lang=bash|<nowiki> |
|||
=== Key Setup === |
|||
$ sudo -i |
|||
Now we can begin the actual setup. |
|||
# mkdir -p /etc/wireguard/keys/wg0 # Create a directory for the keys |
|||
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> < |
<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> < |
<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> |
<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> |
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 |
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| |
||
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. |
|||
Run <code>sudo systemctl status wg-quick@wg0</code> to make sure that WireGuard started properly. |
|||
== |
=== 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 |
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 === |
|||
{{Warn|Be very careful doing this if you have no offline access to the client! If something is configured incorrectly, this has a chance of killing the client's internet connection until it is fixed.}} |
|||
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 = |
PrivateKey = /ExampleClientPrivateKey1= |
||
Address = 10.0.32.2/24 |
Address = 10.0.32.2/24 |
||
[Peer] |
[Peer] |
||
PublicKey = |
PublicKey = /ExampleServerPublicKey= |
||
AllowedIPs = 0.0.0.0/0 |
AllowedIPs = 0.0.0.0/0 |
||
Endpoint = server ip:51820 |
Endpoint = server ip:51820 |
||
</nowiki>}} |
|||
Restart the WireGuard tunnel on the client: |
|||
{{code|lang=bash| |
|||
sudo systemctl restart wg-quick@wg0 |
|||
}} |
}} |
||
{{Info|If you were connected to the client via SSH, your connection will probably drop out here, as the client is now routing all of its traffic through the server and is not using its public IP for anything other than connecting to the tunnel. To reconnect to the client, you can use <code>ssh 10.0.32.2</code> from the server or another client on the tunnel. Read below for how to forward this port to the server's public IP.<br><br>If your client is on your LAN and you are accessing it by its private IP, read the below section on Excluding subnets before using this configuration.}} |
|||
If this does in fact work, then you have successfully completed your WireGuard tunnel. |
|||
If all went well, all traffic on the client should now be routed through the server: |
|||
== 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. |
|||
{{code|<nowiki> |
|||
$ 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" |
|||
} |
|||
</nowiki>}} |
|||
=== Excluding subnets === |
|||
If your client is on a LAN, you will probably want to configure your client in a way that it can still access other devices on the LAN directly and not through the tunnel. This can be done by further configuring the AllowedIPs setting. |
|||
For this, we will be using this very nice [https://www.procustodibus.com/blog/2021/03/wireguard-allowedips-calculator/ AllowedIPs calculator tool]. |
|||
For example, let's say your client is on a LAN that uses a subnet of <code>192.168.1.0/24</code>, and you want to route its internet connection to the tunnel, but still be able to access devices on the LAN. To do this, open the tool linked above, and put <code>0.0.0.0/0</code> in the Allowed IPs field. Then, put <code>192.168.1.0/24</code> in the Disallowed IPs field. This will give you a value like this: |
|||
{{code|lang=ini|<nowiki> |
|||
AllowedIPs = 0.0.0.0/1, 128.0.0.0/2, 192.0.0.0/9, 192.128.0.0/11, 192.160.0.0/13, 192.168.0.0/24, 192.168.2.0/23, 192.168.4.0/22, 192.168.8.0/21, 192.168.16.0/20, 192.168.32.0/19, 192.168.64.0/18, 192.168.128.0/17, 192.169.0.0/16, 192.170.0.0/15, 192.172.0.0/14, 192.176.0.0/12, 192.192.0.0/10, 193.0.0.0/8, 194.0.0.0/7, 196.0.0.0/6, 200.0.0.0/5, 208.0.0.0/4, 224.0.0.0/3 |
|||
</nowiki>}} |
|||
Use it in your client's wg0.conf like so: |
|||
{{code|lang=ini|<nowiki> |
|||
[Interface] |
|||
PrivateKey = /ExampleClientPrivateKey1= |
|||
Address = 10.0.32.2/24 |
|||
[Peer] |
|||
PublicKey = /ExampleServerPublicKey= |
|||
AllowedIPs = 0.0.0.0/1, 128.0.0.0/2, 192.0.0.0/9, 192.128.0.0/11, 192.160.0.0/13, 192.168.0.0/24, 192.168.2.0/23, 192.168.4.0/22, 192.168.8.0/21, 192.168.16.0/20, 192.168.32.0/19, 192.168.64.0/18, 192.168.128.0/17, 192.169.0.0/16, 192.170.0.0/15, 192.172.0.0/14, 192.176.0.0/12, 192.192.0.0/10, 193.0.0.0/8, 194.0.0.0/7, 196.0.0.0/6, 200.0.0.0/5, 208.0.0.0/4, 224.0.0.0/3 |
|||
Endpoint = server ip:51820 |
|||
</nowiki>}} |
|||
Restart the tunnel: |
|||
=== 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| |
{{code|lang=bash| |
||
sudo systemctl restart wg-quick@wg0 |
|||
}} |
|||
If all went well, connections to public IPs should now be routed through the tunnel while the LAN subnet is still accessible. |
|||
== 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| |
|||
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 |
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. |
Latest revision as of 21:28, 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
ssh 10.0.32.2
from the server or another client on the tunnel. Read below for how to forward this port to the server's public IP.If your client is on your LAN and you are accessing it by its private IP, read the below section on Excluding subnets before using this configuration.
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"
}
Excluding subnets
If your client is on a LAN, you will probably want to configure your client in a way that it can still access other devices on the LAN directly and not through the tunnel. This can be done by further configuring the AllowedIPs setting.
For this, we will be using this very nice AllowedIPs calculator tool.
For example, let's say your client is on a LAN that uses a subnet of 192.168.1.0/24
, and you want to route its internet connection to the tunnel, but still be able to access devices on the LAN. To do this, open the tool linked above, and put 0.0.0.0/0
in the Allowed IPs field. Then, put 192.168.1.0/24
in the Disallowed IPs field. This will give you a value like this:
AllowedIPs = 0.0.0.0/1, 128.0.0.0/2, 192.0.0.0/9, 192.128.0.0/11, 192.160.0.0/13, 192.168.0.0/24, 192.168.2.0/23, 192.168.4.0/22, 192.168.8.0/21, 192.168.16.0/20, 192.168.32.0/19, 192.168.64.0/18, 192.168.128.0/17, 192.169.0.0/16, 192.170.0.0/15, 192.172.0.0/14, 192.176.0.0/12, 192.192.0.0/10, 193.0.0.0/8, 194.0.0.0/7, 196.0.0.0/6, 200.0.0.0/5, 208.0.0.0/4, 224.0.0.0/3
Use it in your client's wg0.conf like so:
[Interface]
PrivateKey = /ExampleClientPrivateKey1=
Address = 10.0.32.2/24
[Peer]
PublicKey = /ExampleServerPublicKey=
AllowedIPs = 0.0.0.0/1, 128.0.0.0/2, 192.0.0.0/9, 192.128.0.0/11, 192.160.0.0/13, 192.168.0.0/24, 192.168.2.0/23, 192.168.4.0/22, 192.168.8.0/21, 192.168.16.0/20, 192.168.32.0/19, 192.168.64.0/18, 192.168.128.0/17, 192.169.0.0/16, 192.170.0.0/15, 192.172.0.0/14, 192.176.0.0/12, 192.192.0.0/10, 193.0.0.0/8, 194.0.0.0/7, 196.0.0.0/6, 200.0.0.0/5, 208.0.0.0/4, 224.0.0.0/3
Endpoint = server ip:51820
Restart the tunnel:
sudo systemctl restart wg-quick@wg0
If all went well, connections to public IPs should now be routed through the tunnel while the LAN subnet is still accessible.
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
.