From c0e80820010cc5b0fdea1eb69bafef7f575e3201 Mon Sep 17 00:00:00 2001 From: Your Name Date: Sun, 8 Feb 2026 20:23:31 +0800 Subject: first --- server.sh | 151 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100755 server.sh (limited to 'server.sh') diff --git a/server.sh b/server.sh new file mode 100755 index 0000000..41b88ce --- /dev/null +++ b/server.sh @@ -0,0 +1,151 @@ +#!/bin/bash +# Install and configure headscale locally +# Copy this directory to a VM and run: sudo ./install.sh +# Example: sudo ./install.sh 37.27.166.244 +# docs: +# this script assumes the ip addresses is pointed to the current machine, and this script runs on 0.0.0.0 +# configuration is kinda manual cuz the official packaging is for .deb and i want rhel based system +# fallback (Designated Encrypted Relay for Packets) is disabled. if NAT traversal fails, there will be no connection +set -e + +die() { echo "Error: $1" >&2; exit 1; } +info() { echo " $1"; } + +[[ $EUID -eq 0 ]] || die "Must run as root" + +SCRIPT_DIR="$(dirname "$(readlink -f "$0")")" +PUBLIC_IP="${1:?Usage: $0 }" + +HEADSCALE_VERSION="0.28.0" +ARCH="amd64" + +echo "=== Installing Headscale ===" +echo "Public IP: $PUBLIC_IP" +echo "" + +# 1. Download and install binary from GitHub releases (no RPM exists, only deb and bare binary) +info "Downloading headscale v${HEADSCALE_VERSION}..." +curl -fsSL -o /var/tmp/headscale "https://github.com/juanfont/headscale/releases/download/v${HEADSCALE_VERSION}/headscale_${HEADSCALE_VERSION}_linux_${ARCH}" +install -m 755 /var/tmp/headscale /usr/local/bin/headscale +rm -f /var/tmp/headscale +info "Installed: $(headscale version 2>/dev/null | head -1)" + +# 2. Create headscale user/group (same as what the deb postinst does) +info "Creating headscale user/group..." +groupadd --force --system headscale +useradd --system --shell /usr/sbin/nologin --gid headscale --home-dir /var/lib/headscale --comment headscale headscale 2>/dev/null || true + +# 3. Create directories: /etc/headscale (config), /var/lib/headscale (data/db), /var/run/headscale (socket) +info "Creating directories..." +mkdir -p /etc/headscale /var/lib/headscale /var/run/headscale +chown headscale:headscale /var/lib/headscale /var/run/headscale + +# 4. Install systemd service (from official packaging/systemd/headscale.service, +# only change: ExecStart points to /usr/local/bin/headscale instead of /usr/bin/headscale) +info "Installing systemd service..." +cat > /etc/systemd/system/headscale.service <<'EOF' +[Unit] +After=network.target +Description=headscale coordination server for Tailscale +X-Restart-Triggers=/etc/headscale/config.yaml + +[Service] +Type=simple +User=headscale +Group=headscale +ExecStart=/usr/local/bin/headscale serve +ExecReload=/usr/bin/kill -HUP $MAINPID +Restart=always +RestartSec=5 + +WorkingDirectory=/var/lib/headscale +ReadWritePaths=/var/lib/headscale + +AmbientCapabilities=CAP_NET_BIND_SERVICE CAP_CHOWN +CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_CHOWN +LockPersonality=true +NoNewPrivileges=true +PrivateDevices=true +PrivateMounts=true +PrivateTmp=true +ProcSubset=pid +ProtectClock=true +ProtectControlGroups=true +ProtectHome=true +ProtectHostname=true +ProtectKernelLogs=true +ProtectKernelModules=true +ProtectKernelTunables=true +ProtectProc=invisible +ProtectSystem=strict +RemoveIPC=true +RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX +RestrictNamespaces=true +RestrictRealtime=true +RestrictSUIDSGID=true +RuntimeDirectory=headscale +RuntimeDirectoryMode=0750 +StateDirectory=headscale +StateDirectoryMode=0750 +SystemCallArchitectures=native +SystemCallFilter=@chown +SystemCallFilter=@system-service +SystemCallFilter=~@privileged +UMask=0077 + +[Install] +WantedBy=multi-user.target +EOF + +# 5. Install config — example config with two changes: +# - server_url: http://:8080 (so clients know the public address) +# - listen_addr: 0.0.0.0:8080 (listen on all interfaces, not just localhost) +info "Downloading example config..." +curl -fsSL -o /var/tmp/config-example.yaml "https://raw.githubusercontent.com/juanfont/headscale/v${HEADSCALE_VERSION}/config-example.yaml" +cp /var/tmp/config-example.yaml /etc/headscale/config.yaml +rm -f /var/tmp/config-example.yaml +sed -i "s|server_url: http://127.0.0.1:8080|server_url: http://${PUBLIC_IP}:8080|" /etc/headscale/config.yaml +sed -i "s|listen_addr: 127.0.0.1:8080|listen_addr: 0.0.0.0:8080|" /etc/headscale/config.yaml +# Disable DERP relays — all nodes have public IPs, force direct WireGuard connections only +sed -i 's| - https://controlplane.tailscale.com/derpmap/default| # - https://controlplane.tailscale.com/derpmap/default|' /etc/headscale/config.yaml +sed -i 's| auto_update_enabled: true| auto_update_enabled: false|' /etc/headscale/config.yaml +chown -R headscale:headscale /etc/headscale + +# 6. Start headscale +info "Enabling and starting headscale..." +systemctl daemon-reload +systemctl enable --now headscale + +# 7. Create default user and reusable auth key +info "Creating default user..." +headscale users create default 2>/dev/null || true +USER_ID=$(headscale users list -o json 2>/dev/null | python3 -c "import json,sys; print(json.load(sys.stdin)[0]['id'])") +info "Creating auth key (reusable, 90 days)..." +AUTH_KEY=$(headscale preauthkeys create --user "$USER_ID" --expiration 2160h --reusable) + +# 8. Register this machine as a tailscale client +info "Installing tailscale client on this machine..." +dnf install -y tailscale +systemctl enable --now tailscaled +tailscale up --login-server "http://${PUBLIC_IP}:8080" --authkey "$AUTH_KEY" + +echo "" +echo "=== Headscale installed ===" +echo "" +echo "Health check:" +echo " curl http://${PUBLIC_IP}:8080/health" +echo "" +echo "Auth key (reusable, 90 days):" +echo " $AUTH_KEY" +echo "" +echo "Connect a client:" +echo " sudo ./client.sh ${PUBLIC_IP} ${AUTH_KEY}" +echo "" +echo "Create a new user:" +echo " headscale users create " +echo "" +echo "Create an auth key:" +echo " headscale preauthkeys create --user --expiration 2160h --reusable" +echo "" +echo "List nodes:" +echo " headscale node list" -- cgit