Logo

Build a GRE tunnel from a Linux client for Remote Transit IP

Build a GRE tunnel from a Linux client for Remote Transit IP

Configure a GRE tunnel between your Linux server and the VeryCloud backbone (AS198825): `ip tunnel` commands, systemd-networkd or Netplan persistence, MTU, troubleshooting IP proto 47 blocked by residential ISPs.

Introduction

GRE (Generic Routing Encapsulation, RFC 2784) is the standard transport for delivering BGP transit at a distance. It's a simple L3 tunnel, no encryption, adding only 24 bytes of header (4 GRE + 20 IPv4) or 44 bytes (4 GRE + 40 IPv6). Light, natively supported by Linux, Cisco, Arista, OPNsense, Mikrotik.

Main limit: GRE uses IP protocol 47, often filtered by residential boxes (notably Bouygues Bbox in France). If that's your case, see the WireGuard or VXLAN tutorial.

Prerequisites

  • A Linux server with a fixed public IP (PUB_CLIENT)
  • VeryCloud's technical email with your addressing plan: PUB_VC (VeryCloud endpoint), 169.254.X.1/30 (VeryCloud tunnel IP), 169.254.X.2/30 (your tunnel IP), 2a0e:XXXX:XXXX::/127 v6
  • Root / sudo
  • Kernel module ip_gre (present in 100% of recent distros)

Step 1: Verify GRE support

sudo modprobe ip_gre
sudo modprobe ip6_gre
lsmod | grep gre

You should see ip_gre and ip6_gre loaded.

Step 2: Create the GRE tunnel (IPv4)

For a standard tunnel (IPv4-in-IPv4):

sudo ip tunnel add gre-vc mode gre \
    remote PUB_VC \
    local PUB_CLIENT \
    ttl 255

sudo ip link set gre-vc up
sudo ip addr add 169.254.X.2/30 dev gre-vc

For a dual-stack tunnel (carry v4 AND v6 in the same GRE tunnel):

sudo ip link add gre-vc type gretap \
    remote PUB_VC \
    local PUB_CLIENT \
    ttl 255

sudo ip link set gre-vc up
sudo ip addr add 169.254.X.2/30 dev gre-vc
sudo ip -6 addr add 2a0e:XXXX:XXXX::1/127 dev gre-vc

💡 gretap is L2 mode. For simple IP transit, mode gre is enough — you address v4+v6 on top.

Step 3: MTU and fragmentation

GRE adds 24 bytes of IPv4 header. On standard Ethernet MTU=1500, your in-tunnel effective MTU is 1476.

sudo ip link set gre-vc mtu 1476

TCP-MSS clamping to avoid TCP sessions breaking:

sudo iptables -t mangle -A FORWARD -o gre-vc -p tcp --tcp-flags SYN,RST SYN \
    -j TCPMSS --clamp-mss-to-pmtu

sudo ip6tables -t mangle -A FORWARD -o gre-vc -p tcp --tcp-flags SYN,RST SYN \
    -j TCPMSS --clamp-mss-to-pmtu

⚠️ Clamping is mandatory in practice. Without it, some sites/services load partially.

Step 4: Test connectivity

ping 169.254.X.1
ping6 2a0e:XXXX:XXXX::0

Step 5: Persistence with systemd-networkd

/etc/systemd/network/10-gre-vc.netdev:

[NetDev]
Name=gre-vc
Kind=gre

[Tunnel]
Local=PUB_CLIENT
Remote=PUB_VC
TTL=255

/etc/systemd/network/10-gre-vc.network:

[Match]
Name=gre-vc

[Network]
Address=169.254.X.2/30
Address=2a0e:XXXX:XXXX::1/127
LinkLocalAddressing=no

[Link]
MTUBytes=1476
sudo systemctl enable --now systemd-networkd
sudo systemctl restart systemd-networkd
networkctl status gre-vc

Step 6: Persistence with Netplan (Ubuntu)

network:
  version: 2
  tunnels:
    gre-vc:
      mode: gre
      local: PUB_CLIENT
      remote: PUB_VC
      mtu: 1476
      addresses:
        - 169.254.X.2/30
        - 2a0e:XXXX:XXXX::1/127

sudo netplan apply.

Step 7: Tunnel routes

ip route show dev gre-vc
ip -6 route show dev gre-vc

Step 8: Prepare for BGP

Authorize TCP/179 between tunnel IPs:

sudo iptables -A INPUT -p tcp --dport 179 -s 169.254.X.1 -j ACCEPT
sudo iptables -A INPUT -p tcp --sport 179 -s 169.254.X.1 -j ACCEPT

sudo ip6tables -A INPUT -p tcp --dport 179 -s 2a0e:XXXX:XXXX::0 -j ACCEPT
sudo ip6tables -A INPUT -p tcp --sport 179 -s 2a0e:XXXX:XXXX::0 -j ACCEPT

Troubleshooting

Ping on tunnel IP doesn't respond

  • Check VeryCloud side that the tunnel is provisioned (technical email received)
  • Your side: ip tunnel show should list gre-vc, ip link show gre-vc should be UP
  • tcpdump -i any proto gre to see if GRE packets arrive

IP proto 47 blocked (residential ISP case)

  • Classic symptom: no GRE packets leave your box, or none come back
  • Bouygues Bbox actively filters proto 47 on consumer plans
  • Solution: switch to WireGuard or VXLAN (dedicated tutorials)
  • Or: host behind a public VPS that relays the GRE

Tunnel up but losing packets

  • MTU wrong: retry lower MTU (1400 then increase)
  • TCP-MSS clamping missing
  • NAT issue in path

Operation not supported when creating the tunnel

  • Module ip_gre not loaded: sudo modprobe ip_gre
  • LXC/Docker: need host kernel with GRE support and NET_ADMIN capability

Tunnel recreated at each reboot

  • Forgot systemd-networkd or Netplan persistence (step 5 or 6)

Useful commands

# List all GRE tunnels
ip -d link show type gre
ip tunnel show

# Stats
ip -s link show gre-vc

# Tcpdump on the tunnel
sudo tcpdump -i gre-vc -nn

# Tcpdump on encapsulated GRE packets
sudo tcpdump -i eth0 proto gre -nn

# Delete a tunnel
sudo ip tunnel del gre-vc

Conclusion

GRE on Linux = 3 commands to create, once forever for persistence. The canonical transport for Remote Transit IP when your ISP doesn't filter proto 47. Combined with a clean firewall, MSS clamping, you have a solid base for your BGP session.

Going further: VXLAN if proto 47 blocked, WireGuard for encryption, BIRD 2 / FRR for the BGP session on top.

Resources

Join our Discord community server

For any questions, suggestions, or just to chat with the community, join us on Discord!

900+Members