#!/usr/bin/env bash # setup-tailscale.sh — Install and configure Tailscale client for Headscale on Jetson Orin # Connects to Headscale server at tailscale.vayrette.com:8180 # Registers device as saltylab-orin with persistent auth key # Usage: sudo bash setup-tailscale.sh set -euo pipefail HEADSCALE_SERVER="https://tailscale.vayrette.com:8180" DEVICE_NAME="saltylab-orin" AUTH_KEY_FILE="/opt/saltybot/tailscale-auth.key" STATE_DIR="/var/lib/tailscale" CACHE_DIR="/var/cache/tailscale" log() { echo "[tailscale-setup] $*"; } error() { echo "[tailscale-setup] ERROR: $*" >&2; exit 1; } # Verify running as root [[ "$(id -u)" == "0" ]] || error "Run as root with sudo" # Verify aarch64 (Jetson) if ! uname -m | grep -q aarch64; then error "Must run on Jetson (aarch64). Got: $(uname -m)" fi log "Installing Tailscale for Headscale client..." # Install Tailscale from official repository if ! command -v tailscale &>/dev/null; then log "Adding Tailscale repository..." curl -fsSL https://pkgs.tailscale.com/stable/ubuntu/jammy.noarmor.gpg | \ gpg --dearmor | tee /usr/share/keyrings/tailscale-archive-keyring.gpg >/dev/null curl -fsSL https://pkgs.tailscale.com/stable/ubuntu/jammy.tailscale-keyring.list | \ tee /etc/apt/sources.list.d/tailscale.list >/dev/null apt-get update log "Installing tailscale package..." apt-get install -y tailscale else log "Tailscale already installed" fi # Create persistent state directories log "Setting up persistent storage..." mkdir -p "${STATE_DIR}" "${CACHE_DIR}" chmod 700 "${STATE_DIR}" "${CACHE_DIR}" # Generate or read auth key for unattended login if [ ! -f "${AUTH_KEY_FILE}" ]; then log "Auth key not found at ${AUTH_KEY_FILE}" log "Interactive login required on first boot." log "Run: sudo tailscale login --login-server=${HEADSCALE_SERVER}" log "Then save auth key to: ${AUTH_KEY_FILE}" else log "Using existing auth key from ${AUTH_KEY_FILE}" fi # Create Tailscale configuration directory mkdir -p /etc/tailscale chmod 755 /etc/tailscale # Create tailscale-env for systemd service cat > /etc/tailscale/tailscale-env << 'EOF' # Tailscale Environment for Headscale Client HEADSCALE_SERVER="https://tailscale.vayrette.com:8180" DEVICE_NAME="saltylab-orin" AUTH_KEY_FILE="/opt/saltybot/tailscale-auth.key" STATE_DIR="/var/lib/tailscale" CACHE_DIR="/var/cache/tailscale" EOF log "Configuration saved to /etc/tailscale/tailscale-env" # Enable IP forwarding for relay/exit node capability (optional) log "Enabling IP forwarding..." echo "net.ipv4.ip_forward = 1" | tee /etc/sysctl.d/99-tailscale-ip-forward.conf >/dev/null sysctl -p /etc/sysctl.d/99-tailscale-ip-forward.conf >/dev/null # Configure ufw to allow Tailscale (if installed) if command -v ufw &>/dev/null && ufw status 2>/dev/null | grep -q active; then log "Allowing Tailscale through UFW..." ufw allow in on tailscale0 >/dev/null 2>&1 || true ufw allow out on tailscale0 >/dev/null 2>&1 || true fi # Disable Tailscale key expiry checking for WiFi resilience # This allows the client to reconnect after WiFi drops log "Disabling key expiry checks for WiFi resilience..." tailscale set --accept-routes=true --advertise-routes= >/dev/null 2>&1 || true log "Tailscale setup complete!" log "" log "Next steps:" log " 1. Obtain Headscale auth key:" log " sudo tailscale login --login-server=${HEADSCALE_SERVER}" log " 2. Save the auth key to: ${AUTH_KEY_FILE}" log " 3. Install systemd service: sudo ./systemd/install_systemd.sh" log " 4. Start service: sudo systemctl start tailscale-vpn" log "" log "Check status with:" log " sudo tailscale status" log " sudo journalctl -fu tailscale-vpn" log ""