#!/usr/bin/env bash # Ubuntu client bootstrap for Song's private ZeroTier network. # Usage: curl -fsSL https://aa.songhahaha.com | sudo bash set -Eeuo pipefail NETWORK_ID='2dedafe817ce648f' PLANET_SHA256='8d912c931f373fcc9469fdc35ddbe6ee9f37109b42b4d37eded1cadb280442db' ZT_DIR='/var/lib/zerotier-one' PLANET_BASE64='AQAAAAAI6skKAAABbOPiOVVr1BKS/uRj6EIF8OGvyUtbPfI8Q1mLkG/7uRhdiFA0dSM1XBXoGvNAu3HP5KRg7yGcmJjMIVjnMc9Pw4P4n7pHsncs/oet6EMkmYZSiUpYAhktFyrjWOVUQIA6mQC33TG0JpeCyvMGRnqdL0sjWwd4O3MiXE2bdbocVpWueN4IDLoAHuciGsUfkls8b9TfYJF7LUSzoD22o/k/nFYl08uMAS3tr+gXAKFlaQ3Tu7ZYOzfOKIZ8+OTRWHlzxkX2D7PEQiOYYtFXCdPFioO8K75lzfVnPc0k0S2F7RvCSrw2RAJYUmnm62oAAQQvXxXbJwo=' STAGING='' BACKUP='' PLANET_PENDING=0 HAD_PLANET=0 WAS_ACTIVE=0 log() { printf '\n[ZeroTier] %s\n' "$*"; } die() { printf '\n[ZeroTier] ERROR: %s\n' "$*" >&2; exit 1; } cleanup() { local rc=$? trap - EXIT if (( PLANET_PENDING )); then printf '\n[ZeroTier] Setup failed; restoring the previous planet.\n' >&2 systemctl stop zerotier-one >/dev/null 2>&1 || true if (( HAD_PLANET )); then if ! cp -p -- "$BACKUP" "$ZT_DIR/planet"; then printf '[ZeroTier] RESTORE FAILED. Backup: %s\n' "$BACKUP" >&2 fi else rm -f -- "$ZT_DIR/planet" fi if (( WAS_ACTIVE )); then systemctl start zerotier-one >/dev/null 2>&1 || true fi fi [[ -z "$STAGING" ]] || rm -rf -- "$STAGING" exit "$rc" } main() { if [[ "${1:-}" == '--help' || "${1:-}" == '-h' ]]; then printf 'Usage: curl -fsSL https://aa.songhahaha.com | sudo bash\nNetwork: %s\nPlanet SHA256: %s\nManual authorization in your private controller is required.\n' "$NETWORK_ID" "$PLANET_SHA256" return fi [[ $# -eq 0 ]] || die 'Unsupported argument. Use --help.' [[ "$(id -u)" == 0 ]] || die 'Run as root: curl -fsSL https://aa.songhahaha.com | sudo bash' [[ -r /etc/os-release ]] || die '/etc/os-release is missing.' . /etc/os-release case "${ID:-}" in ubuntu|debian) ;; *) die 'This installer supports Ubuntu and Debian only.' ;; esac command -v systemctl >/dev/null || die 'systemd is required.' [[ -d /run/systemd/system ]] || die 'systemd is not running; ordinary Docker/WSL containers are unsupported.' command -v flock >/dev/null || die 'flock is missing; install the util-linux package first.' exec 9>/run/lock/song-zerotier-setup.lock flock -n 9 || die 'Another ZeroTier setup is already running.' trap cleanup EXIT STAGING=$(mktemp -d /tmp/song-zerotier.XXXXXXXX) chmod 700 "$STAGING" # Validate the embedded file before changing the running service. printf '%s' "$PLANET_BASE64" | base64 --decode > "$STAGING/planet" printf '%s %s\n' "$PLANET_SHA256" "$STAGING/planet" | sha256sum --check --status \ || die 'Embedded planet checksum does not match.' if ! command -v zerotier-cli >/dev/null; then log 'Installing ZeroTier One from the official repository...' if ! command -v curl >/dev/null || [[ ! -s /etc/ssl/certs/ca-certificates.crt ]]; then apt-get update DEBIAN_FRONTEND=noninteractive apt-get install -y curl ca-certificates fi curl --proto '=https' --tlsv1.2 -fSL --retry 2 --connect-timeout 15 --max-time 180 \ https://install.zerotier.com/ -o "$STAGING/zerotier-official.sh" DEBIAN_FRONTEND=noninteractive bash "$STAGING/zerotier-official.sh" command -v zerotier-cli >/dev/null || die 'ZeroTier installation did not provide zerotier-cli.' else log 'Using the existing ZeroTier installation.' fi [[ -d "$ZT_DIR" ]] || install -d -m 700 "$ZT_DIR" if [[ -f "$ZT_DIR/planet" ]] && cmp -s "$STAGING/planet" "$ZT_DIR/planet"; then log 'The private planet is already configured.' systemctl enable --now zerotier-one if ! zerotier-cli info > "$STAGING/info" 2>/dev/null || ! grep -q ' ONLINE$' "$STAGING/info"; then log 'The existing service is offline; reconnecting to the private planet...' systemctl restart zerotier-one fi else systemctl is-active --quiet zerotier-one && WAS_ACTIVE=1 if [[ -e "$ZT_DIR/planet" ]]; then HAD_PLANET=1 BACKUP="$ZT_DIR/planet.bak.$(date -u +%Y%m%dT%H%M%SZ).$$" cp -p -- "$ZT_DIR/planet" "$BACKUP" log "Previous planet backed up to $BACKUP" fi PLANET_PENDING=1 systemctl stop zerotier-one install -o root -g root -m 644 "$STAGING/planet" "$ZT_DIR/planet" systemctl enable zerotier-one systemctl start zerotier-one fi local ready=0 attempt for attempt in {1..15}; do if zerotier-cli info > "$STAGING/info" 2>/dev/null; then ready=1 break fi sleep 1 done (( ready )) || die 'The local ZeroTier API did not become ready. Check: journalctl -u zerotier-one -n 50' log "Joining network $NETWORK_ID..." zerotier-cli join "$NETWORK_ID" # An existing client may have disabled managed addresses for this network. # A controller-assigned IP can still be listed even when it is not applied. zerotier-cli set "$NETWORK_ID" allowManaged=1 > /dev/null PLANET_PENDING=0 # Refresh status after joining; the earlier API-ready snapshot can be OFFLINE. for attempt in {1..5}; do zerotier-cli info > "$STAGING/info" 2>/dev/null || true if grep -q ' ONLINE$' "$STAGING/info"; then break fi sleep 2 done log 'Local configuration complete. Current device status:' cat "$STAGING/info" if ! grep -q ' ONLINE$' "$STAGING/info"; then printf '\nWARNING: The client has not confirmed connectivity to the private planet yet.\n' printf 'A cached virtual IP alone does not confirm current connectivity.\n' printf 'Check: sudo zerotier-cli peers\n' fi printf '\nAuthorize the 10-character node ID above in your PRIVATE management console,\nnetwork %s. Keep this network private.\n' "$NETWORK_ID" printf 'Then check: sudo zerotier-cli listnetworks\n' printf 'OK + an assigned address confirms network configuration was received.\n' printf 'Also verify that IPv4 is present on the actual interface, then test a peer.\n' printf 'ACCESS_DENIED means authorization is still required.\n' printf 'REQUESTING_CONFIGURATION means the controller has not supplied configuration yet.\n' printf '\n' zerotier-cli listnetworks || true if command -v ip >/dev/null; then printf '\nIPv4 addresses actually configured on ZeroTier interfaces:\n' ip -br -4 addr show | awk '$1 ~ /^zt/ {print}' || true fi printf '\nPeers (PLANET should point to your private server):\n' zerotier-cli peers || true } # Keep the entrypoint last so an interrupted download cannot run a partial body. main "$@"