Score:0

How to setup routing for a Linux VPN server with separate ingress and egress IPs

ke flag

I am setting up a Linux server as a VPN using Wireguard (previously configured via Algo, now doing it myself). My goal is to have two different public IP addresses: one for ingress (VPN clients connect here, e.g. 192.0.2.10), and one for egress (websites accessed from the VPN will see this as the client's IP address, e.g. 198.51.100.20).

I have tried doing this in various ways, and at one point in the past I had it working flawlessly. However, I have since then deleted that old Algo VPN server and now can't figure out how to get it working again. For context, when it worked before, both IPs were attached to the same NIC, and I don't think I needed to do anything tricky with routing or iptables. I think this was on a pre-netplan Ubuntu distro though, and now getting the interface setup correctly for this situation with netplan is tricky.

I've tried adding both IPs to the same interface (single NIC), with the egress IP as the primary and the ingress as the secondary (so all outbound traffic will use the egress IP by default). I have also tried adding two NICs (eth0 and eth1), where each one uses a different IP.

It sometimes works, but the problem I'm running into is that Wireguard's UDP packets back to the client sometimes go out over the egress IP, meaning the Wireguard client doesn't receive them through NAT. The client logs show messages like these: Handshake did not complete after 5 seconds, retrying (try 4), and using tcpdump I can see that the response packets are sent from the egress source IP instead of the ingress one.

I've tried to setup symmetric routing using a combination of ip route and ip rule commands and using a separate routing table number for each interface/ip, but I've always run into problems trying to do that.

To further complicate things, I'm doing this in Azure, so the VM is on a VNet and only sees an internal IP address (10.10.0.4, for example). So in the dual-NIC setup, the egress IP may be translated to 10.10.0.4, and then ingress IP may be translated to 10.10.0.5. I've also tried having each NIC be on its own /24 subnet, like 10.10.0.4 and 10.10.1.4.

I've tried using iptables to change the source address to the ingress IP when sending UDP traffic to port 51820 (Wireguard). I've also thought about setting up the ingress IP as the default and then having an iptables FORWARD rule to make anything coming from wg0 go out over (the egress NIC / the egress IP).

I'm still learning about networking and routing, so maybe I'm approaching this the wrong way, overcomplicating it, or missing something obvious. My question is what is a "correct" or "proper" solution to solve this problem?

Nikita Kipriyanov avatar
za flag
I edited your question, changing "public" IP addresses to those comply with [RFC 5737](https://www.rfc-editor.org/rfc/rfc5737.html) and used IP addresses reserved there specifically for this documentation and testing purposes. While your 10.20.30.40 address was fine to use too as it came from private block, the other one was not, but I've chose to change them both to look more consistent.
Score:0
za flag

This is quite good idea to use separate public IPs for different classes of services, despite the fact they all may run over the same public network. Some people (like me) learned that the hard way (by running into problems with "single IP for everything" setup), but are good to go around that mistake straight away.

On Azure you need to install NAT rules that translate each public IP into its own private counterpart. Lets assume it is like this:

  • 192.0.2.10 - 10.10.0.4 — for "private" services (VPN, management)
  • 198.51.100.20 - 10.10.0.5 — for "public" services (public web sites, email and so on)

You need to set address translation both way (SNAT and DNAT): you need to both source-translate 10.10.0.4 (and other private services if you have them in Azure) into 192.0.2.10 and destination-translate UDP 192.0.2.10:51820 into 10.10.0.4:51820 (that's for Wireguard, adjust for other services).

On your server you need to bind your services to corresponding private IPs. For each service it is done separately and how to do that depends on the software implementing it.

Nginx: instead of

listen 80
listen 443 ssl

or

listen *:80
listen *:443 ssl

you use

listen 10.10.0.5:80
listen 10.10.0.5:443 ssl

There is similar setting in Apache and I believe in all other servers (e.g. Postfix: inet_interfaces = 10.10.0.5 and so on), and you have to use it, except...

WireGuard: it will answer on all IPs. So set up NAT on Azure carefully. It is hard to find the documentation about this, but you can set up which address it will use when it starts the connection:

[Interface]
Address = 10.10.0.4/32

By default, for IPv4 it uses the routing hint which is present in the routing table for the local route (run ip route and see the src attribute). To stay on safe size, list the IP to use with Wireguard first in the network configuration, so this address will make up into the hint if you went the "single private network" route.

It is not very important whether you use a single private network or multiple networks, but there are configuration caveats. In case of a single network, you need to assign both IP addresses to the same virtual NIC (so you'll have single virtual NIC with two IP addresses); in that case I assume your gateway will be 10.10.0.1 (in line with all previous explanation). In case of multiple networks, you need to setup the routing policy database so it'll use the proper routing table with correct Azure's gateway corresponding to the selected private IP address:

ip route add default via 10.10.0.1 table 100
ip route add default via 10.10.1.1 table 200
ip rule add from 10.10.0.4 lookup 100
ip rule add from 10.10.1.4 lookup 200

There is no need to do this for the single network case because there is only one NIC and one gateway anyway.

Score:-1
ye flag
  1. Configure the IP addresses for each interface on the VPN server.

  2. Install the necessary VPN software and configure it for the desired protocol.

  3. Access the server's routing table and enable IP forwarding by running the following command:

sysctl -w net.ipv4.ip_forward=1

  1. Add a static route for the ingress IP address to the routing table.

  2. Add a static route for the egress IP address to the routing table.

  3. Finally, restart the VPN service and test the connection.

Nikita Kipriyanov avatar
za flag
this simply does not address the problem which was raised in the question
I sit in a Tesla and translated this thread with Ai:

mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.