GRE tunnel between two vps servers
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:
- VM1 and VM2 running Debian/Ubuntu/CentOS other OS should also work
- Support for
ip_gre
kernel module - Install
iptables
andiproute2
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.
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/