How to Tunnel Public IPs to a Remote Machine Behind NAT Using OpenVPN or GRE


2 views

You have a Linux server (Server A) with a public IP block 8.8.8.122/29, where 8.8.8.122 is assigned to eth0 and 8.8.8.123 to eth0:1. Another machine (Server B) sits behind NAT, and you want it to use 8.8.8.123 as its primary IP. Here's how to achieve this with OpenVPN or GRE.

This is the most flexible solution, allowing multiple clients to share spare IPs securely. Below is a sample OpenVPN configuration for Server A (/etc/openvpn/server.conf):

port 1194
proto udp
dev tun
topology subnet
server 10.8.0.0 255.255.255.0
push "route 8.8.8.123 255.255.255.255"
client-config-dir /etc/openvpn/ccd
route 8.8.8.123 255.255.255.255

Create a client-specific config for Server B in /etc/openvpn/ccd/client1:

ifconfig-push 10.8.0.2 10.8.0.1
iroute 8.8.8.123 255.255.255.255

For a lightweight solution without encryption, set up a GRE tunnel:

On Server A:

ip tunnel add gre1 mode gre remote <Server_B_Public_IP> local 8.8.8.122
ip addr add 10.0.0.1/30 dev gre1
ip link set gre1 up
ip route add 8.8.8.123/32 dev gre1

On Server B:

ip tunnel add gre1 mode gre remote 8.8.8.122 local <Server_B_Local_IP>
ip addr add 10.0.0.2/30 dev gre1
ip link set gre1 up
ip addr add 8.8.8.123/32 dev gre1

For OpenVPN, extend the client-config-dir approach with individual iroute statements. For GRE, create separate tunnels with unique endpoints.

While GRE works, OpenVPN offers better access control via certificates and firewall rules. Restrict access to known IPs:

iptables -A INPUT -p gre -s <Server_B_IP> -j ACCEPT
iptables -A INPUT -p gre -j DROP

After setup, verify the tunnel:

ping 8.8.8.123  # From external hosts
tcpdump -i gre1  # Check tunnel traffic

Let's consider a scenario where:

  • Server A has a public IP block (8.8.8.122/29) with 5 usable addresses
  • 8.8.8.122 is assigned to eth0 (primary interface)
  • 8.8.8.123 is assigned to eth0:1 (secondary IP)
  • Machine B is behind NAT at a remote location

For this use case, we have several options:

1. OpenVPN (with subnet or p2p topology)
2. GRE tunneling (simpler but unencrypted)
3. IPIP tunneling
4. WireGuard (modern alternative)

Here's a sample server configuration (server A):

# /etc/openvpn/server.conf
dev tun
proto udp
port 1194
server 10.8.0.0 255.255.255.0
topology subnet
push "route 8.8.8.123 255.255.255.255"
client-config-dir /etc/openvpn/ccd

Client-specific configuration for machine B:

# /etc/openvpn/ccd/client_b
ifconfig-push 10.8.0.2 10.8.0.1
push "route 8.8.8.123 255.255.255.255"

For a simpler, unencrypted solution:

# On server A:
ip tunnel add gre1 mode gre remote 1.2.3.4 local 8.8.8.122
ip addr add 8.8.8.123 dev gre1
ip link set gre1 up

# On machine B (if it has public IP 1.2.3.4):
ip tunnel add gre1 mode gre remote 8.8.8.122 local 1.2.3.4
ip addr add 8.8.8.123 dev gre1
ip link set gre1 up

You'll need to ensure proper routing:

# On server A:
echo 1 > /proc/sys/net/ipv4/ip_forward
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

For multiple remote machines, use OpenVPN's client-specific configurations:

# /etc/openvpn/ccd/client_c
ifconfig-push 10.8.0.3 10.8.0.1
push "route 8.8.8.124 255.255.255.255"

Even though you mentioned security isn't a priority:

  • Use firewall rules to restrict access
  • Consider IP-based authentication
  • Monitor tunnel traffic

Common issues and solutions:

# Check tunnel status:
ip tunnel show

# Verify routing:
ip route show

# Test connectivity:
ping -I 8.8.8.123 8.8.8.1