Let me begin be saying that Tailscale is awesome, uses Wireguard and is free for personal use last time I checked.
The main problem I have is that I am behind CG Nat as many are nowadays. The problem here is that I do not have a personal IPv4 address and for some reason my ISP does not provide an IPv6 address. Or better, they provide IPv6 but do now allow to configure the firewall on their Modem/Router. This leaves me with no apparent way to connect to my local network from the Internet. Enter Tailscale.
Tailscale is awesome, works great and there is absolutely no need to replace it. But as many I do like tinkering and learning a bit on the way. Tailscale uses Wireguard to connect devices and if Tailscale can, I can as well. Or thats what I thought at least, this ended up becomming a rabbit hole of Wireguard, NF Tables and Networking.
Tailscale is a peer-to-peer VPN that uses WireGuard to create secure, private connections between devices easily.
WireGuard is a lightweight VPN protocol that creates fast, secure, and encrypted connections between devices.
The goal might sound simple: replace Tailscale with Wireguard
Usually getting a Wireguard tunnel between say, a laptop and a device in your local or home network is simple and straight forward: Set up an interface on either device and youre good to go. This however, requires ar least one known IP address to establish a connection between the Wireguard interfaces.
The solution ended up beeing the following: Get a VPS server with a known and static IP address, use this sort of as a middle man.
What we have to do:
Oracle cloud offers a free forever tier, this is what I will be using.
Note:
This diagram should give an idea on how traffic will flow once the configuration is done.
Note:
I will be going over the configuration on a per device basis but in order not to get lost, there will be a quick overview and indications what step I am on.
My VPS will be an instance in Oraclec cloud. It will be running bog standard Ubuntu server, with Linux 6.8.0. Generally, 3 things have to be done:
As always, update the system:
sudo apt update
sudo apt upgrade
And install the requirements:
sudo apt install wireguard nftables
This section will be about setting up Wireguard on the VPS server.
As this computer will have 2 wireguard interfaces, I will need 2 keypairs, use wg genkey
and wg pubkey
to generate a private and public key respectively:
wg genkey
This yields, for example: +P7I5nZR6oGq4wQ0Z2ueyfkkmvmC5Jw2+KhUaC9YTUQ=
, a private key!
echo +P7I5nZR6oGq4wQ0Z2ueyfkkmvmC5Jw2+KhUaC9YTUQ= | wg pubkey
This yields dY+Af2zPdtuMlZmD8/ZGYapG1TPAhHxEnoYectEZoQ8=
, a public key to the private key!
Do this twice, need 2 keypairs
Please do not use this key, generate a new one
I will need 2 interfaces, one to connect to the Local Maschine and one to connect to the clients. I will also be using wg-quick
and not the wg
command line tool.
You will notice MTU specified in the configuration files, this will be explained later.
This will create a tunnel between the VPS and Local Maschine
Create /etc/wireguar/wg-home.conf
and edit it:
[Interface]
Address = 10.192.122.1/32
PrivateKey = +P7I5nZR6oGq4wQ0Z2ueyfkkmvmC5Jw2+KhUaC9YTUQ=
ListenPort = 51820
MTU = 1364
[Peer]
# Local Maschine
PublicKey = It6dAL3MfRJNoYJj0UeTv3Q8aIsNs3jfHH424YufeVw=
AllowedIPs = 10.192.122.2/32,192.168.0.0/24
Note:
PublicKey
of Peer Local Maschine is the public key of the Local Maschine, not the VPS!!!AllowedIPs
details what IP addresses will be sent trough the tunnel. Change for your local network.This specific configuration will encrypt and send packets addressed to 10.192.122.2
and 192.168.0.0/24
(the entire subnet) to Local Maschine. 10.192.122.2
is the Wireguard IP address of the Local Maschine, 192.168.0.0/24
is the IP address range of your local network.
This will create a tunnel between the VPS and the Client computers
Create /etc/wireguar/wg-clients.conf
and edit it:
[Interface]
Address = 10.192.123.1/32
PrivateKey = wE4PJR7Ei2h+XXrwKrRQ6tAXIJxNqTZsMkcJyy1+5FY=
ListenPort = 51821
MTU = 1364
[Peer]
# Client 1
PublicKey = MCFQr/AuSYajRH0D/VH+kP1VvBVgEE0MOY7ohytdokg=
AllowedIPs = 10.192.123.2/32
[Peer]
# Client 2
PublicKey = 6AchgJVUg/WdjYgztQs6q4h/rVA3I794hTsaBCEDqD0=
AllowedIPs = 10.192.123.3/32
Note:
PublicKey
of Peer Client 1 and Client 2 are the public keys of the those Clients, not the VPS!!!Use wg-quick up /etc/wireguard/INTERFACE.conf
or wg-quick down /etc/wireguard/INTERFACE.conf
to start and stop the Wireguard interfaces.
wg-quick up /etc/wireguard/wg-home.conf
wg-quick up /etc/wireguard/wg-clients.conf
You can use wg show
to show the status of the interfaces. Also the ip
can be used to check interfaces and routes.
wg show
ip addr show
ip route
Note:
wg-quick
can also be used to start a systemd service, this allows Wireguard to run in the background and start on system start.sudo systemctl enable --now [email protected]
sudo systemctl enable --now [email protected]
First, check if packet forwarding is enabled:
sysctl -a | grep forward
The following should be equal to 1.
net.ipv4.ip_forward = 1
net.ipv4.conf.all.forwarding = 1
net.ipv6.conf.all.forwarding = 1
net.ipv6.conf.default.forwarding=1
If this is the case, you are likely good to go, if you want to make sure, create and edit /etc/sysctl.d/30-ipforward.conf
.
net.ipv4.ip_forward = 1
net.ipv4.conf.all.forwarding = 1
net.ipv6.conf.all.forwarding = 1
net.ipv6.conf.default.forwarding=1
Reboot and check the configuration again with
sysctl -a | grep forward
Generally, I do recommend reading the official documentation of nftables, they also have a really good getting started in 10 minutes guide. There are a couple of things we need to do:
Sounds like a lot but that is actually only one configuration file at /etc/nftables.conf
. Actually, I do recommend first writing the configuration out in a separat file and loading it manually. /etc/nftables.conf
will get loaded at boot if the nftables service is enabled. So I will be writing the changes to /etc/nftables.rules
flush ruleset
table inet filter {
chain input {
type filter hook input priority filter; policy drop;
# Allow established and related connections
ct state established,related accept
# Accept connections on localhost
iifname "lo" accept
# Accept SSH on TCP port 22
tcp dport 22 accept
# Ratelimit ICMP (ping) requests
icmp type echo-request limit rate 10/minute burst 5 packets log prefix "Icmp rate-limit exceeded: " counter packets 79954 bytes 5550317 accept
icmpv6 type echo-request limit rate 10/minute burst 5 packets log prefix "Icmpv6 rate-limit exceeded: " counter packets 0 bytes 0 accept
# Accept Wireguard traffic
udp dport 51820-51830 accept
}
chain forward {
type filter hook forward priority filter; policy drop;
ct state established,related accept
# Allow forwarding between the Wireguard interfaces
iifname "wg-clients" oifname "wg-home" accept
iifname "wg-home" oifname "wg-clients" accept
}
chain output {
type filter hook output priority filter; policy accept;
}
}
table inet nat {
chain wireguard {
type nat hook postrouting priority srcnat; policy accept;
# Enable NAT ie. IP masquerade
oifname "wg-home" masquerade
}
}
Note:
TCP port 22
and UDP ports 51820-51830
, if you need any other traffic, make sure to add an appropriate rule.Make sure the NFTables systemd service is started / enabled:
sudo systemctl enable --now nftables.service
Now you can flush the current ruleset and load the configuration:
sudo nft flush ruleset
sudo nft -f /etc/nftables.rules
And check afterwards with:
sudo nft list ruleset
If you no longer have access to SSH, just restart the VPS via the cloud providers console / website
Now, you can make the changes persistent:
cp /etc/nftables.rules /etc/nftables.conf
You might need to disable firewall rules the VPS came with
Reboot and check if the configuration is applied.
At this point, you should be done with the VPS server.
My Local Maschine will be anb Arch Linux LXC container in Proxmox, however his can be any Linux computer on your local network. The steps that need to be done are similar to the VPS server but the details change a bit:
As always, update the system:
$ pacman -Syu
And install the requirements:
$ pacman -S wireguard nftables
This section will be about setting up Wireguard on the Local Maschine.
This computer will only have one Wireguard interface, use wg genkey
and wg pubkey
to generate a private and public key respectively:
wg genkey
This yields, for example: OLuZQmfiiJqevDm/8oMJAe9hmk2XXEVItouayQxuTns=
, a private key!
echo OLuZQmfiiJqevDm/8oMJAe9hmk2XXEVItouayQxuTns= | wg pubkey
This yields It6dAL3MfRJNoYJj0UeTv3Q8aIsNs3jfHH424YufeVw=
, a public key to the private key!
Please do not use this key, generate a new one
This computer will only need one Wireguard interface. I will also be using wg-quick
and not the wg
command line tool.
You will notice MTU specified in the configuration files, this will be explained later.
This will create a tunnel between the VPS and Local Maschine
Create /etc/wireguar/wg-oracle.conf
and edit it:
[Interface]
Address = 10.192.122.2/32
PrivateKey = OLuZQmfiiJqevDm/8oMJAe9hmk2XXEVItouayQxuTns=
MTU = 1364
[Peer]
# VPS Server
PublicKey = dY+Af2zPdtuMlZmD8/ZGYapG1TPAhHxEnoYectEZoQ8=
PersistentKeepalive = 25
Endpoint = PUBLIC IP OF VPS:51820
AllowedIPs = 10.192.122.1/32
Note:
PublicKey
of Peer VPS Server is the public key of the VPS Server, not Local Maschine!!!AllowedIPs
details what IP addresses will be sent trough the tunnel. Change for your local network.Endpoint
is set to the IP address of the VPS serverUse wg-quick up /etc/wireguard/INTERFACE.conf
or wg-quick down /etc/wireguard/INTERFACE.conf
to start and stop the Wireguard interfaces.
wg-quick up /etc/wireguard/wg-oracle.conf
You can use wg show
to show the status of the interfaces. Also the ip
can be used to check interfaces and routes.
wg show
ip addr show
ip route
Note:
wg-quick
can also be used to start a systemd service, this allows Wireguard to run in the background and start on system start.$ systemctl enable --now [email protected]
This is the same as in the VPS server, refere to this!
This actually is also pritty similar to the configuration of the VPS server. I will point out the differeces.
To do this, create and edit /etc/nftables.rules
flush ruleset
table inet filter {
chain input {
type filter hook input priority srcnat; policy drop;
# Allow established and related connections
ct state established,related accept
# Accept connections to localhost
iifname "lo" accept
# Accept SSH on TCP port 22
tcp dport 22 accept
# Ratelimit ICMP (ping) requests
icmp type echo-request limit rate 10/minute burst 5 packets log prefix "Icmp rate-limit exceeded: " counter packets 90 bytes 7560 accept
icmpv6 type echo-request limit rate 10/minute burst 5 packets log prefix "Icmp6 rate-limit exceeded: " counter packets 0 bytes 0 accept
# Accept Wireguard traffic
iifname "wg-oracle" accept
}
chain forward {
type filter hook forward priority 100; policy drop;
ct state established,related accept
# Allow forwarding between the Wireguard interface and the inteface connected to the local network
iifname "wg-oracle" oifname "eth0" accept
}
chain output {
type filter hook output priority filter; policy accept;
}
}
table inet nat {
chain wireguard {
type nat hook postrouting priority srcnat; policy accept;
# Enable NAT ie. IP masquerade
oifname "eth0" masquerade
}
}
Note:
TCP port 22
and the Wireguard interface, if you need any other traffic, make sure to add an appropriate rule.Make sure the NFTables systemd service is started / enabled:
$ systemctl enable --now nftables.service
Now you can flush the current ruleset and load the configuration:
$ nft flush ruleset
$ nft -f /etc/nftables.rules
And check afterwards with:
$ nft list ruleset
If you no longer have access to SSH, just restart the Local Maschine
Now, you can make the changes persistent:
cp /etc/nftables.rules /etc/nftables.conf
Reboot and check if the configuration is applied.
At this point, you should be done with the Local Maschine.
The Clients actually only have to configure Wireguard to connect to the VPS server, everything else should be working.
Install Wireguard in any way the Client device accepts it.
This section will be about setting up Wireguard on the on the Clients. You most likely will be able to use the GUI to create the Wireguard interfaces, it should be configured as follows:
[Interface]
PrivateKey = MCFQr/AuSYajRH0D/VH+kP1VvBVgEE0MOY7ohytdokg=
MTU = 1364
[Peer]
# VPS Server
PublicKey = FVb3tZc53wrwX4lJoXNvcn+58ItyNidd/MCll2aMvCo=
AllowedIPs = 10.192.123.0/24, 192.168.0.0/24
Endpoint = VPS IP ADDRESS:51821
PersistentKeepalive = 25
Note:
PublicKey
of Peer VPS Server is the public key of the VPS Server (wg-client interface), not the Client!!!AllowedIPs
details what IP addresses will be sent trough the tunnel. Change for your local network.Endpoint
is set to the IP address of the VPS serverThis specific configuration will encrypt and send packets addressed to 10.192.123.0/24
and 192.168.0.0/24
(the entire subnet) to VPS Server. 192.168.0.0/24
is the IP address range of your local network.
Start the interface and see check if the local network is reachable. At this point you should be done and everything should be working.
It is possible that only certain traffic going through the Wireguard tunnel will appear to be working. This can be a problem with the MTU. The appropriate MTU setting for Wireguard can be determined using the ping
command:
ping -M do IP OF REMOTE WIREGUARD INTERFACE -s 1400
If the response is the following, lower the MTU until you get a response.
ping: local error: message too long, mtu=1364