Remote Access
This is the classic road-warrior setup where remote peers initiate a connection to the central peer. That central system forwards their traffic onward to the corporate network.
Traffic Handling
The main choice is route or masquerade.
Routing
If you route, the client’s VPN IP address is what other devices see. This is generally preferred as it allows you to log who was doing what at the individual servers. But you must update your network equipment to treat the central server as a router.
Masquerading
Masquerading causes the server to translate all the traffic. This makes everything look like its coming from the server. It’s less secure, but less complicated and much quicker to implement.
For this example, we will masquerade traffic from the server.
Central Server Config
Enable Masquerade
Use sysctl
to enable forwarding on the server and nft
to add masquerade.
# as root
sysctl -w net.ipv4.ip_forward=1
nft flush ruleset
nft add table nat
nft add chain nat postrouting { type nat hook postrouting priority 100\; }
nft add rule nat postrouting masquerade
Persist Changes
It’s best if we add our new rules onto the defaults and enable the nftables service.
# as root
echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf
nft list ruleset >> /etc/nftables.conf
systemctl enable --now nftables.service
Client Config
Your remote peer - the one you created when setting up the server - needs it’s AllowedIPs
adjusted so it knows to send more traffic through the tunnel.
Full Tunnel
This sends all traffic from the client over the VPN.
AllowedIPs = 0.0.0.0/0
Split Tunnel
The most common config is to send specific networks through the tunnel. This keeps netflix and such off the VPN
AllowedIPs = 192.168.100.0/24, 192.168.XXX.XXX, 192.168.XXX.YYY
DNS
In some cases, you’ll need the client to use your internal DNS server to resolve private domain names. Make sure this server is in the AllowedIPs above.
[Interface]
PrivateKey = ....
Address = ...
DNS = 192.168.100.1
Access Control
Limit Peer Access
By default, everything is open and all the peers can talk to each other and the internet at large - even NetFlix! (they can edit their side of the connection at will). So let’s add some rules to the default filter table.
This example prevents peers from from talking to each other but let’s them ping the central server and reach the corporate network.
# Load the base config in case you haven't arleady. This includes the filter table
sudo nft -f /etc/nftables.conf
# Reject any traffic being sent outside the 192.168.100.0/24
sudo nft add rule inet filter forward iifname "wg0" ip daddr != 192.168.100.0/24 reject with icmp type admin-prohibited
# Reject any traffic between peers
sudo nft add rule inet filter forward iifname "wg0" oifname "wg0" reject with icmp type admin-prohibited
Grant Admin Access
You may want to add an exception for one of the addresses so that an administrator can interact with the remote peers. Order matters, so add it before before the other rules above
sudo nft -f /etc/nftables.conf
# Allow an special 'admin' peer full access and others to reply
sudo nft add rule inet filter forward iifname "wg0" ip saddr 192.168.100.2 accept
sudo nft add rule inet filter forward ct state {established, related} accept
# As above
...
...
Save Changes
Since this change is a little more complex, we’ll replace the existing file config file and add notes.
sudo vi /etc/nftables.conf
#!/usr/sbin/nft -f
flush ruleset
table inet filter {
chain input {
type filter hook input priority 0
}
chain forward {
type filter hook forward priority 0
# Accept admin traffic and responses
iifname "wg0" ip saddr 192.168.100.2 accept
iifname "wg0" ct state {established, related} accept
# Reject other traffic between peers
iifname "wg0" oifname "wg0" reject with icmp type admin-prohibited
# Reject traffic outside the desired network
iifname "wg0" ip daddr != 192.168.100.0/24 reject with icmp admin-prohibited
}
chain output {
type filter hook output priority 0
}
}
table ip nat {
chain postrouting {
type nat hook postrouting priority srcnat
masquerade
}
}
Note: The syntax of the file is slightly different than the command. You can use nft list ruleset
to see how nft config and commands translate into running rules. For example - the policy accept
is being appended. You may want to experiment with explicitly adding policy drop
.
The forwarding chain is where routing type rules go (the input chain is traffic sent to the host itself). Prerouting might work as well, though it’s less common and not present by default.
Notes
The default nftable config file in Debian is:
#!/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;
}
}
If you have old iptables rules you want to translate to nft, you can install iptables and add them (they get translated on the fly into nft) and nft list ruleset
to see how to they turn out.
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.