In enterprise networking, cloud infrastructure, and distributed multi-site architectures, connecting geographically separate local networks over an untrusted intermediate network requires point-to-point virtual tunnelling. Generic Routing Encapsulation (GRE), defined in RFC 2784 and RFC 2890, is one of the most widely adopted tunnelling protocols in existence.
GRE functions by encapsulating arbitrary layer 3 network packets inside standard outer IPv4 or IPv6 delivery packets using IP protocol number 47. Because GRE supports multicast and broadcast traffic, it allows dynamic routing protocols (such as OSPF, BGP, and EIGRP) to establish neighbour relationships across WAN links—capabilities that standalone IPsec cannot deliver without GRE over IPsec. Here is how to create, inspect, route, and persist GRE tunnels in Linux using the native ip tunnel command.
Step 1: Ensure the Kernel GRE Module Is Loaded
Modern Linux kernels handle GRE encapsulation via the ip_gre kernel module. On modern distributions (such as Ubuntu, Debian, Rocky Linux, or Arch), verify and load the module using modprobe:
sudo modprobe ip_gre
lsmod | grep gre
If the command outputs ip_gre and gre, the kernel subsystem is active and ready.
Step 2: Create the GRE Tunnel Interface Using ip tunnel
Suppose you have two Linux routers connecting two private subnets across the public internet:
- Local Host (Router A): Public IP
203.0.113.10, Private Subnet192.168.10.0/24 - Remote Host (Router B): Public IP
198.51.100.20, Private Subnet192.168.20.0/24
On Router A, execute ip tunnel add to instantiate a point-to-point GRE tunnel named gre1:
sudo ip tunnel add gre1 mode gre remote 198.51.100.20 local 203.0.113.10 ttl 255
In this command:
gre1: The name of the virtual network interface created in the Linux kernel.mode gre: Specifies standard layer 3 Generic Routing Encapsulation.remote 198.51.100.20: The public or routable IP address of the peer endpoint (Router B).local 203.0.113.10: The public or routable IP address of your local outgoing interface.ttl 255: Explicitly sets the Time-to-Live on outer transport headers to prevent premature packet drops across multi-hop WAN paths.
Step 3: Assign a Point-to-Point IP Address and MTU
A GRE tunnel requires its own internal point-to-point IP subnet (typically a /30 or /31 CIDR block):
sudo ip addr add 10.0.0.1/30 dev gre1
Adjusting MTU for Tunnel Overhead
GRE encapsulation appends a 20-byte outer IPv4 header and a 4-byte GRE header (24 bytes total) to each packet. If the physical parent NIC has an MTU of 1500 bytes, leaving the tunnel interface at 1500 will cause packet fragmentation. Optimise the tunnel MTU to 1476 bytes:
sudo ip link set dev gre1 mtu 1476
sudo ip link set dev gre1 up
Step 4: Configure the Remote Endpoint (Router B)
Log in to Router B and configure the complementary reverse tunnel parameters:
sudo modprobe ip_gre
sudo ip tunnel add gre1 mode gre remote 203.0.113.10 local 198.51.100.20 ttl 255
sudo ip addr add 10.0.0.2/30 dev gre1
sudo ip link set dev gre1 mtu 1476
sudo ip link set dev gre1 up
Test the point-to-point tunnel link by pinging Router B’s tunnel IP from Router A:
ping -c 4 10.0.0.2
If you receive successful ICMP replies, your encapsulated GRE transport is operating correctly.
Step 5: Route Subnet Traffic Across the GRE Tunnel
To allow workstations on Router A’s private network (192.168.10.0/24) to communicate with workstations on Router B’s network (192.168.20.0/24), add a static route directing the remote subnet through the tunnel device:
sudo ip route add 192.168.20.0/24 dev gre1
On Router B, add the symmetrical return route:
sudo ip route add 192.168.10.0/24 dev gre1
Ensure that IP forwarding is enabled on both Linux hosts by executing sudo sysctl -w net.ipv4.ip_forward=1.
Step 6: Inspect Detailed Tunnel Properties
To inspect active tunnel settings, parameters, and packet counters, use ip tunnel show:
ip -d tunnel show gre1
The console will display the configured endpoints, keying details, checksum status, and interface flags:
gre1: gre/ip remote 198.51.100.20 local 203.0.113.10 ttl 255 ikey 0 okey 0
How to Tear Down a GRE Tunnel
When the tunnel link is no longer needed, shut it down and delete the virtual interface cleanly:
sudo ip link set dev gre1 down
sudo ip tunnel del gre1
Persisting GRE Tunnels Across System Reboots
Commands executed via ip tunnel are volatile and clear on reboot. To make your tunnel permanent, define it in your distribution’s network configuration suite:
Netplan (Ubuntu / Debian)
Add a tunnels block in your Netplan configuration (e.g. /etc/netplan/01-netplan.yaml):
network:
version: 2
tunnels:
gre1:
mode: gre
local: 203.0.113.10
remote: 198.51.100.20
ttl: 255
addresses:
- 10.0.0.1/30
mtu: 1476
routes:
- to: 192.168.20.0/24
via: 10.0.0.2
Apply the settings using sudo netplan apply.
systemd-networkd (Arch Linux, Fedora, Alpine)
Create a netdev file in /etc/systemd/network/25-gre1.netdev:
[NetDev]
Name=gre1
Kind=gre
[GRE]
Local=203.0.113.10
Remote=198.51.100.20
TTL=255
Create the accompanying network file in /etc/systemd/network/25-gre1.network:
[Match]
Name=gre1
[Network]
Address=10.0.0.1/30
[Route]
Destination=192.168.20.0/24
Gateway=10.0.0.2
Restart the network daemon using sudo systemctl restart systemd-networkd to establish the persistent tunnel.