Build and Remove a Point-to-Point Tunnel with ip tunnel
ip tunnel creates an IP tunnel device between two Linux hosts, and this guide builds one, inspects it, then removes it cleanly.
The route
Jump straight to the step you need, or tick off Done means at the end.
The examples use a GRE tunnel, but the same workflow applies to IP-in-IP and the other modes the installed iproute2 build supports. Allow about 15 minutes if you already know both endpoint addresses.
- You need: two Linux hosts, root access through
sudo, and an IPv4 address on each host that the other can reach. - Before you run anything: replace every placeholder value below with real addresses from your own network.
What ip tunnel actually changes
A tunnel wraps packets in an outer IP packet and sends that through the ordinary IP network. The remote address is the far endpoint. The optional local address fixes the source address for the outer packet, and dev can pin the tunnel to a physical interface.
This command only configures the tunnel device. It does not create routes for the networks you eventually want to carry through it, and it does not touch firewall rules. A tunnel device can exist while its traffic still has nowhere useful to go.
The installed package here is iproute2 6.1.0-1ubuntu6.4, reporting iproute2-6.1.0. Its IPv4 tunnel modes include gre, ipip, sit, isatap and vti. IPv6 encapsulation uses a separate address-family selection with different modes and defaults, so do not copy an IPv4 example into an IPv6 design without checking the matching documentation.
1. Record the endpoint details
Choose the outer addresses before touching any network configuration. This example uses host A on 198.51.100.10, host B on 198.51.100.20, and a tunnel device on both hosts called gre-lab. These TEST-NET addresses are documentation values; use real addresses from your own network.
- Host A:
198.51.100.10 - Host B:
198.51.100.20 - Device name on both hosts:
gre-lab
First check that the remote outer address is reachable from each host, an ordinary non-privileged diagnostic:
ping -c 3 198.51.100.20
Run the reverse check on host B. If the outer addresses cannot talk to each other, creating the tunnel will not fix that. Check routing, firewalls and any provider policy before continuing.
2. Create the GRE device
Run this on host A. Creating a device changes live kernel networking state, so it needs elevated privileges. mode gre selects GRE over IPv4, and remote/local describe the outer endpoints, not any inner addresses you assign later.
sudo ip tunnel add gre-lab mode gre \
remote 198.51.100.20 \
local 198.51.100.10
Run the matching command on host B, with the endpoints swapped:
sudo ip tunnel add gre-lab mode gre \
remote 198.51.100.10 \
local 198.51.100.20
A successful ip tunnel add normally prints nothing. The most common immediate errors are a device name already in use, a missing tunnel mode, or a local address that is not assigned to another interface on the local host: the manpage requires a fixed local address to already belong to a local interface.
Checkpoint
List the configured tunnels on each host and confirm the device name, GRE mode, and the expected remote and local addresses appear:
ip tunnel show
If it prints nothing, the add command did not leave a tunnel configured in that network namespace.
3. Choose the tunnel defaults deliberately
The basic command uses the manpage's defaults. For an IPv4 tunnel, the outer packet TTL defaults to inherit, so the tunnelled packet's own TTL is copied through, and Path MTU Discovery is enabled by default. The default is usually the sensible starting point: changing it can hide a real MTU problem or make diagnosis harder.
Set a fixed TTL only when you have a reason to:
sudo ip tunnel change gre-lab ttl 64
This changes the existing device and still needs privilege. A fixed TTL is incompatible with nopmtudisc: the manpage says tunnelling with a fixed TTL always performs path MTU discovery. Do not add nopmtudisc just because large packets are failing; investigate the path MTU first.
If you need different input and output GRE keys, use ikey and okey; a single key applies the same key both ways. Keys are security-sensitive configuration, not encryption: a keyed GRE tunnel still gives you no confidentiality. Avoid putting a real key in shell history or a shared transcript.
dev binds the tunnel to a physical device, which stops encapsulated packets escaping through another interface if the route to the remote endpoint changes:
sudo ip tunnel change gre-lab dev eth0
Only use eth0 after checking the actual interface name on that host with the non-changing command ip link show. A wrong device can make the tunnel unusable.
4. Add inner addressing only if you need it
ip tunnel add creates the tunnel object, but it does not assign an inner address or bring the device up. If your design needs a point-to-point inner network, that is a separate interface operation, and it should use addresses and routes reserved for this purpose, not the outer endpoint addresses.
For a lab-only inner network:
sudo ip addr add 192.0.2.1/30 dev gre-lab
sudo ip link set gre-lab up
Use 192.0.2.1/30 on host A and the matching 192.0.2.2/30 on host B only in a controlled example, then test the inner address:
ping -c 3 192.0.2.2
Real networks should use an address range properly allocated for the tunnel. After assigning an address, verify it and the link state:
ip addr show dev gre-lab
ip link show dev gre-lab
If the inner ping fails, separate the layers: confirm ip tunnel show has the right outer endpoints first, then confirm the device is up, the inner addresses are correct, routes exist, and firewalls permit the protocol. GRE is not TCP or UDP, so a firewall rule that only permits familiar transport ports will not necessarily let it through.
5. Remove the test configuration
Warning
Removing a tunnel destroys the device and any inner addresses attached to it, a state-changing and potentially service-disrupting action. Stop dependent traffic and confirm the device name before running the command.
ip tunnel show
sudo ip tunnel del gre-lab
Run the delete command on both hosts. If you added an address or route separately, remove those separately with the command that matches how they were created:
sudo ip addr del 192.0.2.1/30 dev gre-lab
Remove the address before deleting the device if you need to clean up each step explicitly; if the device is already gone, any address attached to it disappears with it. Confirm the tunnel is gone:
ip tunnel show
The expected result is no line for gre-lab. If cleanup reports a "Cannot find device" or equivalent error, inspect the current namespace with ip tunnel show and ip link show rather than repeating commands blindly.
Common traps
- Confusing outer and inner addresses.
remoteandlocalare for encapsulation; they do not replace an inner address or route. - Assuming creation means connectivity. A configured device can still be down, unrouted, blocked by a firewall, or hit by an MTU limit.
- Using a duplicate name. Tunnel names are device names in the current network namespace: check with
ip tunnel showbefore adding one. - Changing defaults without a test. Fixed TTL, disabled PMTU discovery, keys and checksums all alter behaviour. Record the reason for each change so recovery is possible.
- Testing from the wrong namespace. Network devices are namespace-local. Run inspection commands where the tunnel was actually created, especially with containers or network namespaces involved.
Done means
- Reachability confirmed. The two outer endpoint addresses can reach each other.
- Tunnel verified.
ip tunnel showreports the intended mode, name and endpoints on both hosts. - Inner config deliberate. Any inner addresses and routes are separate, deliberate configuration.
- Traffic tested. Firewall and MTU behaviour have been tested for the traffic you actually need.
- Cleanup tracked. The tunnel has been deleted on both hosts when the test is finished, or its owner and rollback command are recorded.