Wireguard VPN – Port Unreachable When Connected

iptablesnetworkingroutingvpnwireguard

I have a server that routes all of its traffic through wireguard. When I start the wireguard, all ports listening on this server's public IP are unavailable – even ssh does not work.

What I want is to allow incoming traffic on a port (ssh for example) from any IP, but use wireguard for any outgoing connection.

Example:

MY_SERVER to any public ip -> use wireguard peer for routing (other servers should see wireguard peer's IP as source). This is working by having AllowedIPs = 0.0.0.0/0 in wireguard conf.

Any public IP to MY_SERVER -> this is not working when wireguard is enabled. If I stop wireguard it works.

Any ideas how can I allow incoming connections on my public IP and route outgoing connections through wireguard?

Update:

The main issue is that I am getting asymmetric routing due to wireguard routing all packets through it. So when incoming connection on public IP for given port comes in, it's reply is routed over wg0 instead of public interface and never makes it back to client.

I was able to somewhat fix it by adding ip rule add sport PORT table main but not sure if there is a better fix so I don't have to 1 by 1 add all ports – I want any port I start listening on to be routed correctly. Also, this fix works for TCP but not for UDP. Would be great if I can have it working for both protocols.

Best Answer

Your routing tables are stateless, they don't have any information about a packet being an answer or your port being bound. So you can use the connection table to add a mark when a connection is made to the server interface (not the wireguard one), and then restoring this mark for every packet of this connection.

You can then use this mark in a routing rule:

iptables -t mangle -A PREROUTING -d <server_address> -m conntrack --ctstate NEW -j CONNMARK --set-mark 51820
iptables -t mangle -A OUTPUT -j CONNMARK --restore-mark
ip rule add fwmark 51820 table main

Or if you use nftables:

nft add rule ip mangle prerouting ip daddr <server_address> meta mark set 51820
nft add rule ip mangle prerouting meta mark 51820 ct mark set mark
nft add rule filter output meta mark set ct mark
ip rule add fwmark 51820 table main

Or you can do it with listing ports in rules, it might be the cleaner. For UDP, you want services to listen on a single IP address (not 0.0.0.0), and then the ip rule should work.