Table of Contents

GRE – Generic Routing Encapsulation is a protocol developed by Cisco for encapsulating data packets that use one routing protocol inside the packets of another protocol. GRE wraps the data packet within another data packet. GRE is usually configured at router/ISP/DC level but here we are going to route it between two different vps servers.

Scenario:

VM1 is DDoS protected and will serve all traffic originating from VM2

VM2 will run the applications on selected ports

This setup works great when you don’t want your primary server to be out open to public internet. You can block IP/port access by using firewall like ufw. Simple reverse-proxying VM2 with VM1’s traffic.

Prerequisites:

  1. VM1 and VM2 running Debian/Ubuntu/CentOS other OS should also work
  2. Support for ip_gre kernel module
  3. Install iptables and iproute2

Setup:

VM1

Load ip_gre kernel module by running modprobe ip_gre

Check to see if the module loaded successfully lsmod | grep gre

Output:

lsmod | grep gre

ip_gre                 32768  0
ip_tunnel              32768  1 ip_gre
gre                    16384  1 ip_gre
Install `iptables` and `iproute2`
sudo apt install -y iptables iproute2

Enable IP forwarding between VMs,

sudo echo 'net.ipv4.ip_forward=1' | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

net.ipv4.ip_forward = 1

Now edit /etc/rc.local (create if not present already) and paste the below code.

#cat /etc/rc.local
ip tunnel add gre1 mode gre local VM1.IP remote VM2.IP ttl 255
ip addr add 10.0.0.1/30 dev gre1
ip link set gre1 up
iptables -t nat -A POSTROUTING -s 10.0.0.0/30 ! -o gre+ -j SNAT --to-source VM1.IP
iptables -A FORWARD -d 10.0.0.2 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD -s 10.0.0.2 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
iptables -t nat -A PREROUTING -d VM1.IP -p tcp -m tcp --dport 80 -j DNAT --to-destination 10.0.0.2
iptables -t nat -A PREROUTING -d VM1.IP -p tcp -m tcp --dport 443 -j DNAT --to-destination 10.0.0.2
exit 0
  • VM1.IP – VM1’s public IP
  • VM2.IP – VM2’s public IP
  • 10.0.0.1 – internal IP
  • Line 9 --dport 80 create more entries with required port that flows with your application (like shown in line 10)

To have rc.local run during boot time, create a systemd service.

Create a file /etc/systemd/system/rc-local.service

#cat /etc/systemd/system/rc-local.service
[Unit]
Description= rc.local

[Service]
ExecStart=/bin/bash /etc/rc.local

[Install]
WantedBy=multi-user.target

Enable and start the service. Check status for errors.

sudo systemctl enable rc-local.service
sudo systemctl start rc-local.service
sudo systemctl status rc-local.service

Output: (only after setting up VM2, do the testing)

● rc-local.service - rc.local
    Loaded: loaded (/etc/systemd/system/rc-local.service; enabled; vendor preset: enabled)
   Drop-In: /usr/lib/systemd/system/rc-local.service.d
            └─debian.conf
    Active: inactive (dead) since Fri 2022-06-24 07:01:21 EDT; 5 days ago
   Process: 349 ExecStart=/bin/bash /etc/rc.local (code=exited, status=0/SUCCESS)
  Main PID: 349 (code=exited, status=0/SUCCESS)
       CPU: 32ms

Reboot the server and check ip a, you should see the gre interface.

ip a Try pinging VM2,

ping 10.0.0.2

PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.
64 bytes from 10.0.0.2: icmp_seq=1 ttl=64 time=0.955 ms
64 bytes from 10.0.0.2: icmp_seq=2 ttl=64 time=0.759 ms
64 bytes from 10.0.0.2: icmp_seq=3 ttl=64 time=0.575 ms
64 bytes from 10.0.0.2: icmp_seq=4 ttl=64 time=0.900 ms

GRE is successfully setup.

VM2

Follow the same procedure,

sudo apt install -y iptables iproute2
sudo echo 'net.ipv4.ip_forward=1' >> /etc/sysctl.conf
sudo sysctl -p
sudo modprobe ip_gre
lsmod | grep gre
#cat /etc/rc.local
ip tunnel add gre1 mode gre local VM2.IP remote VM1.IP ttl 255
ip addr add 10.0.0.2/30 dev gre1
ip link set gre1 up
echo '100 GRE' >> /etc/iproute2/rt_tables
ip rule add from 10.0.0.0/30 table GRE
ip route add default via 10.0.0.1 table GRE
exit 0
#cat /etc/systemd/system/rc-local.service
[Unit]
Description= rc.local

[Service]
ExecStart=/bin/bash /etc/rc.local

[Install]
WantedBy=multi-user.target
  • 10.0.0.2 – VM2’s internal IP
sudo systemctl enable rc-local.service
sudo systemctl start rc-local.service
sudo systemctl status rc-local.service

Reboot the server and check ip a. Ping 10.0.0.1.

Done.

Testing:

Install nginx/apache/caddy on VM2 and open VM1.IP:80 or VM1.IP:443

You should see a landing page!

Reference:

https://linuxhint.com/use-etc-rc-local-boot/

https://www.cloudflare.com/en-in/learning/network-layer/what-is-gre-tunneling/