Skip to content

Instantly share code, notes, and snippets.

@groundcat
Created June 16, 2026 00:32
Show Gist options
  • Select an option

  • Save groundcat/a88da91d740cfd60aaad0ed431a73a2a to your computer and use it in GitHub Desktop.

Select an option

Save groundcat/a88da91d740cfd60aaad0ed431a73a2a to your computer and use it in GitHub Desktop.
Tailscale exit node optimization

Here’s a Debian/Ubuntu bash script that applies the Tailscale exit-node/subnet-router optimizations, enables IPv4/IPv6 forwarding, enables BBR, and optionally installs the persistent networkd-dispatcher hook when available.

Run it like this:

nano tailscale-exit-node-setup.sh
chmod +x tailscale-exit-node-setup.sh
sudo ./tailscale-exit-node-setup.sh

Then advertise the exit node with Tailscale:

sudo tailscale up --advertise-exit-node

On newer Tailscale setups where you already have flags configured, avoid overwriting them by using:

sudo tailscale set --advertise-exit-node
#!/usr/bin/env bash
set -euo pipefail
# Tailscale exit node / subnet router optimizer for Debian/Ubuntu
# - Enables UDP GRO forwarding optimization on the default network device
# - Persists ethtool settings via networkd-dispatcher when available
# - Enables IPv4 and IPv6 forwarding
# - Enables TCP BBR congestion control
#
# Run as root:
# sudo bash tailscale-exit-node-optimize.sh
if [[ "${EUID}" -ne 0 ]]; then
echo "Please run as root, for example:"
echo " sudo bash $0"
exit 1
fi
echo "==> Detecting default network interface..."
NETDEV="$(
ip -o route get 8.8.8.8 2>/dev/null | awk '{for (i=1;i<=NF;i++) if ($i=="dev") print $(i+1); exit}'
)"
if [[ -z "${NETDEV}" ]]; then
echo "Could not detect default network interface."
echo "Make sure the VM has a default IPv4 route."
exit 1
fi
echo "Default network interface: ${NETDEV}"
echo
echo "==> Installing required tools..."
apt-get update
apt-get install -y ethtool
echo
echo "==> Applying Tailscale network offload optimizations..."
if ethtool -K "${NETDEV}" rx-udp-gro-forwarding on rx-gro-list off; then
echo "Applied ethtool optimizations to ${NETDEV}"
else
echo "Warning: failed to apply one or more ethtool settings."
echo "This can happen if the NIC/driver/kernel does not support them."
fi
echo
echo "==> Persisting ethtool settings across reboot..."
if systemctl list-unit-files networkd-dispatcher.service >/dev/null 2>&1; then
apt-get install -y networkd-dispatcher
mkdir -p /etc/networkd-dispatcher/routable.d
cat > /etc/networkd-dispatcher/routable.d/50-tailscale <<EOF
#!/bin/sh
ethtool -K ${NETDEV} rx-udp-gro-forwarding on rx-gro-list off
EOF
chmod 755 /etc/networkd-dispatcher/routable.d/50-tailscale
systemctl enable --now networkd-dispatcher || true
echo "Testing persistent ethtool hook..."
if /etc/networkd-dispatcher/routable.d/50-tailscale; then
echo "Persistent ethtool hook installed successfully."
else
echo "Warning: persistent ethtool hook test failed."
fi
else
echo "networkd-dispatcher is not available on this system."
echo "Skipping persistent ethtool hook."
echo "The ethtool optimization was applied for the current boot only."
fi
echo
echo "==> Enabling IPv4 and IPv6 forwarding..."
SYSCTL_FILE="/etc/sysctl.d/99-tailscale-exit-node.conf"
cat > "${SYSCTL_FILE}" <<'EOF'
# Tailscale exit node / subnet router forwarding
net.ipv4.ip_forward = 1
net.ipv6.conf.all.forwarding = 1
# TCP BBR
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr
EOF
sysctl -p "${SYSCTL_FILE}"
echo
echo "==> Checking BBR status..."
BBR_STATUS="$(sysctl -n net.ipv4.tcp_congestion_control || true)"
if [[ "${BBR_STATUS}" == "bbr" ]]; then
echo "BBR is enabled."
else
echo "Warning: BBR does not appear to be enabled."
echo "Current congestion control: ${BBR_STATUS}"
fi
echo
echo "==> Checking kernel version..."
KERNEL_VERSION="$(uname -r)"
echo "Kernel: ${KERNEL_VERSION}"
echo
echo "==> Optional firewalld masquerade workaround..."
if command -v firewall-cmd >/dev/null 2>&1 && systemctl is-active --quiet firewalld; then
firewall-cmd --permanent --add-masquerade
firewall-cmd --reload
echo "Enabled firewalld masquerading."
else
echo "firewalld is not active; skipping masquerade workaround."
fi
echo
echo "==> Done."
echo
echo "Recommended next checks:"
echo " ethtool -k ${NETDEV} | grep -E 'rx-udp-gro-forwarding|rx-gro-list'"
echo " sysctl net.ipv4.ip_forward"
echo " sysctl net.ipv6.conf.all.forwarding"
echo " sysctl net.ipv4.tcp_congestion_control"
echo " tailscale status"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment