Wireguard Config
There is a collision between your WG subnet and the external interfaces subnet.
The WG subnet needs to be separate. 10.8.x.0/24 is a common choice. PUtting a random x can make
"sure" it is unique.
Also putting KeepAlive=20 on both sides will ensure that the firewall punch of the tunnel packets from the router to the vps stays open. Otherwise if no communication for some time, the vps may not be able to transmit the first packet through the tunnel.
Server wg0.conf
[Interface]
Address = 10.8.0.1/24
SaveConfig = true
PreUp = iptables -t nat -I PREROUTING -p tcp --dport 50400 -j DNAT --to-destination 10.8.0.2:443
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -A FORWARD -i eth0 -j ACCEPT
PostUp = iptables -t nat -A POSTROUTING -o wg0 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
ListenPort = 51820
PrivateKey = ********************************
Client conf
[Interface]
Address = 10.8.0.2/24
ListenPort = 51820
PrivateKey = ********************************
Routing
On the server (exposed to the internet), check out the following commands output:
ip rule
ip route
Should show something like 10.8.0.0/24 dev wg0 proto kernel scope link src 10.8.0.1
Or the The most restictive 10.8.0.2 dev wg0 proto kernel scope link src 10.8.0.1
.
Ping
server from the router, and the reciprocal via the 10.8.0.0/24 subnet.
If that works, WG is effective and your routes too.
Firewall work
First need to check if your web interface port is open on the router.
Hence from the server, execute:
curl http://10.8.0.2
curl -k https://10.8.0.2 (the -k is to avoid cert verification if you have a self-signed certificate).
If that works, the port to forward to will be 443, avoid exposing 80 as it will go clear on the internet.
(If only plain http works, you'll need to find a way (like another VPN) to your server to avoid anything in clear on the internet. Or stunnel to encapsulate, or a reverse proxy etc.)
Forwarding must be enabled in the kernel
echo 1 > /proc/sys/net/ipv4/ip_forward
Now comes the fun !
Ref. http://www.do1618.com/wp-content/uploads/2016/06/netfilter_pkt_flow.png
The following rules are needed. You can embed them all in the server Wiregard commands run by the config file once confirmed it works.
Let's just follow a packet travelling through the server.
iptables -t nat -I PREROUTING -p tcp --dport 50400 -j DNAT --to-destination 10.8.0.2:443
(this performs the destination nat: any request packet received from the internet will see its destination address and port rewritten, before even reaching the route check.)
iptables -A FORWARD -i eth0 -j ACCEPT
(The kernel routing system will identify at the route check that it goes to an exiting interface and not to be input and delivered to a local process.
Hence the packet will go through the forward hook. This rule will allow any packet coming from the external interface to be forwarded.
iptables -t nat -A POSTROUTING -o wg0 -j MASQUERADE
(The packet will then be sent out via wg0 as per the routing table. However if left as it is, the source ip address remains the one from the requester on the internet. The packet will go to the router and be treated.
BUT the router will reply to the originating source address. Without more info and work on the router, the reply return path may be different. Without even going into the kernel reverse path policy setting story, firewalls may not let the packet reach nor enter the originating machine.
Masquerading NATs with an automagically determined source address using the outgoing interface. And NATs back the other way on the reply packets.
Cf. Gotcha below though)
iptables -A FORWARD -i wg0 -j ACCEPT
(this is to allow reply packets to go through the server from the tunnel to the internet).
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
(this is to make the reply from the router not originate from 10.8.0.2 but rather from the server public address.
So firewalls will let it travel back to your laptop.
Gotchas
Masquerading the wg0 interface is a bit dirty. One may want to tweak the router in marking incoming packets with some meta mark, and have a specific rule to route back the reply marked packets to the WG tunnel. But that's some more work and not sure if the router OS will allow the tweaks.
Here the only disadvantage is that the router cannot log where people logged from, it will always report 10.8.0.1, wherever your connected from.
Security-wise, the wg0 interface on the router lets you access anything on your router. So it seems it went into the Openwrt LAN zone.
Not initially that big a deal when setting up, but one would prefer to set a specific firewall zone, assign the wg0 interface to it, and allow only incoming packets for port 443.
As long as the server is secured, nothing else should go through and that acts as a firewall, but still.
Tip - network analyzer Wireshark on console
Install package "tshark" (Ubuntu) or wireshark-cli (Redhat's) on the server
sudo tshark -i any -Y !ssh
Will show packets through all interfaces, excluding the ssh packets to your laptop/PC which would pollute your output.
- Run this on the server and leave it write.
- Try to access from your browser https://public_ip:50400
With this it should be easy to see packet flowing between interfaces, and see what goes wrong.
You should see the request arriving, the packet going through the vpn interface, and a reply from the vpn interface coming in, and then exiting via eth0 with eth0 source address port 50400, destinated to your browser address on its random port used for the query.