Living Without Hairpin Routing

From Extremely Corporate Wiki
Jump to navigation Jump to search

This page provides a solution to the problem of having a server on your local network which is also accessible over the public internet at a hostname.

Without hairpin routing, you cannot access the server by its public address while on your local network. For a desktop, this is fine as you can simply include a local override in /etc/hosts, but for a laptop which could be on or off your local network at any given time, this doesn't work. Assuming you use NetworkManager, the following solution will automatically swap out two versions of your /etc/hosts configuration depending on whether or not the server is reachable by its public address.

  1. First, create two files in /etc/, /etc/normal_hosts and /etc/lan_hosts.
  2. In /etc/normal_hosts, place your hosts configuration for when you are off your local network.
  3. In /etc/lan_hosts, place your hosts configuration for when you are on your local network.

Then, create the file, /etc/NetworkManager/dispatcher.d/99-set_hosts.sh, with the following contents:

#!/bin/bash

[ "$2" = "connectivity-change" ] \
    && [ "$CONNECTIVITY_STATE" = "FULL" ] \
    || exit 0

WIFI_DEVICE=YOUR WIFI DEVICE
HOME_NETWORK_UUID=YOUR HOME NETWORK UUID
   
uuid=` \
    nmcli -c no -f device,active,uuid -t connection \
    | grep ^$WIFI_DEVICE:yes: | cut -d: -f 3`
    
case $uuid in
    $HOME_NETWORK_UUID)
        cp /etc/{lan_,}hosts
        ;;
    *)
        cp /etc/{normal_,}hosts
        ;;
esac

Make sure the file is executable! (chmod 744)

Make sure the file is owned by root! (chown root:root)

You can find your home network's UUID with nmcli -f name,uuid connection

You can find your WiFi device ID with ip link show