Let's establish the following concrete addressing scheme (since you didn't provided any):
- Server
A
:
eno1
: address 198.51.100.2/24
, gateway 198.51.100.1
gre1
: remote 192.0.2.2
, local 198.51.100.2
, address 10.0.0.1/30
- Server
B
:
eno1
: 192.0.2.2/24
, gateway 192.0.2.1
gre1
: remote 198.51.100.2
, local 192.0.2.2
, address 10.0.0.2/30
Notice that local and remote properties of GRE interfaces are mirror of each other, and their addresses belong to the same /30 subnet. In this case (if everything else is set up properly, e.g. firewalls, IPsec, etc.) servers will be able to ping each other through the tunnel by using 10.0.0.x
addresses. On the physical network you will observe the GRE traffic between their public IP addresses, 198.51.100.2
and 192.0.2.2
.
Routes on the server B
are currently like this:
default via 192.0.2.1
192.0.2.0/24 dev eno1 src 192.0.2.2
10.0.0.0/30 dev gre1 src 192.0.2.2
You only need that 192.0.2.1
is used (directly) to support GRE and nothing more, and everything else is to be routed via GRE tunnel. This could be done by adding a route towards the A
198.51.100.2
through the former gateway, and setting A
's GRE address as the new gateway. The routing table on B
becomes:
default via 10.0.0.1
198.51.100.2 via 192.0.2.1
192.0.2.0/24 dev eno1 src 192.0.2.2
10.0.0.0/30 dev gre1 src 192.0.2.2
For server B
to able to reach Internet now you need to source-NAT it on the host A
, for example:
iptables -t nat -A POSTROUTING -s 10.0.0.2 -o eno1 -j MASQUERADE
And, if there are services on the B
that you want to publish, you need to destination-NAT them on A
, for example:
iptables -t nat -A PREROUTING -i eno1 -p tcp -m multiport --dports 80,443 -j DNAT --to-destination 10.0.0.2
The host B
will be accessible directly from only host A
and hosts in its "local" network, which is 192.0.2.0/24
in this case. All other hosts will see its traffic as coming from A
with address 198.51.100.2
and, if they wish to use any published services, they need to communicate to A
.
It is possible to make B directly accessible too, to force even hosts in its local network to go through A and otherwise augment the system, but that requires much more complicated setup, involving policy routing and finer firewall settings.
Also I must advise you against using plain GRE (and against using GRE at all). It is completely unprotected per se, so at least you must accompany it with IPsec (in transport mode between A
and B
). It will still struggle to work from behind the NAT. Better and much simpler is to replace it with WireGuard, the routing setup will stay the same regardless of the tunnel technology you use. OpenVPN is easiest, because it even has the provision to build this exact configuration automatically once tunnel is established, for which you need A
to be the server and B
to be the client — if enabled, during connection establishment it will determine the "former" gateway and add direct route to the VPN server, then replace the default route with tunnel endpoint, achieving the described routing setup. A disadvantage of OpenVPN against WireGuard is much lower performance.