#!/usr/bin/env bash set -euo pipefail OPS_REPO_PRIMARY_URL="${OPS_REPO_PRIMARY_URL:-https://git.sketchferret.com/sketchferret/ops.git}" OPS_REPO_FALLBACK_URL="${OPS_REPO_FALLBACK_URL:-}" OPS_BUNDLE_PATH="${OPS_BUNDLE_PATH:-/srv/backups/ops/latest/ops.bundle}" TS_HOSTNAME="${TS_HOSTNAME:-vps-edge}" echo "[1/6] Install packages" apt-get update apt-get install -y ca-certificates curl git ufw docker.io docker-compose-plugin age echo "[2/6] Install tailscale" curl -fsSL https://tailscale.com/install.sh | sh echo "[3/6] Configure firewall" ufw allow OpenSSH ufw allow 80/tcp ufw allow 443/tcp ufw --force enable echo "[4/6] Prepare directories" mkdir -p /srv/{ops,secrets,data,backups} chmod 700 /srv/secrets echo "[5/6] Sync ops repo" if [[ ! -d /srv/ops/.git ]]; then if git clone "$OPS_REPO_PRIMARY_URL" /srv/ops; then echo "Cloned ops from primary" elif [[ -n "$OPS_REPO_FALLBACK_URL" ]] && git clone "$OPS_REPO_FALLBACK_URL" /srv/ops; then echo "Cloned ops from fallback mirror" elif [[ -f "$OPS_BUNDLE_PATH" ]]; then rm -rf /srv/ops mkdir -p /srv/ops git clone "$OPS_BUNDLE_PATH" /srv/ops echo "Cloned ops from local bundle: $OPS_BUNDLE_PATH" else echo "Unable to fetch ops repo from primary, fallback, or bundle" exit 1 fi else if ! git -C /srv/ops pull --ff-only; then if [[ -n "$OPS_REPO_FALLBACK_URL" ]]; then git -C /srv/ops remote set-url origin "$OPS_REPO_FALLBACK_URL" git -C /srv/ops pull --ff-only || true fi fi fi echo "[6/6] Bring up tailscale and caddy" if [[ -f /srv/ops/secrets/tailscale_authkey.age ]]; then if [[ ! -f /srv/secrets/ops.agekey ]]; then echo "Missing /srv/secrets/ops.agekey (age private key)" exit 1 fi age -d -i /srv/secrets/ops.agekey -o /srv/secrets/tailscale_authkey /srv/ops/secrets/tailscale_authkey.age chmod 600 /srv/secrets/tailscale_authkey tailscale up --authkey="$(cat /srv/secrets/tailscale_authkey)" --hostname="$TS_HOSTNAME" --ssh else echo "tailscale_authkey.age not found; run tailscale up manually" fi cd /srv/ops/edge/caddy docker compose up -d echo "Done: VPS bootstrap complete"