thermograph/deploy/forgejo/register-lan-runner.sh
Emi Griffith 0d8fc9f4d0 Add agent VPS access, a 2-node Docker Swarm, and Forgejo CI/CD (#234)
Three additive infrastructure layers on top of the two VPS boxes Terraform
already provisions (prod: new 48 GB/12-core box, thermograph.org; beta: old
VPS, 75.119.132.91). None of this touches backend/, Dockerfile,
docker-compose*.yml, terraform/, or deploy/db/ — that stays owned by the
app-containerization work in flight elsewhere; this is strictly the layer on
top. See INFRA.md for the full runbook and order of operations.

- deploy/provision-agent-access.sh: a dedicated, auditable full-sudo login
  (not raw root) for agent-driven ops — passwordless sudo under a distinct
  username, sshd hardened to key-only auth, auditd logging every
  root-effective command. One line to revoke.

- deploy/swarm/: a 2-node Swarm (prod=manager, beta=worker) joined over a
  WireGuard tunnel rather than trusting the public internet with the
  overlay data plane, which Docker's own guidance says should never face it
  directly. Swarm ports locked to the tunnel interface once joined. This
  cluster's only workload is Forgejo — it does not orchestrate the
  Terraform-managed app deploys, so nothing here can strand the app's
  single-writer database.

- deploy/forgejo/ + .forgejo/workflows/: Forgejo + Traefik + a
  Docker-in-Docker-sandboxed runner as a Swarm stack pinned to beta, plus
  Forgejo Actions workflows mirroring .github/workflows/*.yml. The custom
  auto-merge workflow step is dropped — it existed only to work around
  GitHub's paywalled branch protection on private free-tier repos, which
  Forgejo has no such tier for; native "auto merge when checks succeed"
  replaces it, and as a real git push (unlike GitHub's non-triggering
  token-merge) it fires the LAN deploy naturally with no double-trigger
  logic needed. appleboy/ssh-action is referenced by full URL (not mirrored
  on Forgejo's default action registry); actions/checkout and
  actions/setup-python resolve unchanged.

Migration is mirror-first: the GitHub repo import and workflow files land
here, but cutting deploy secrets over and retiring GitHub happens only after
verification (INFRA.md 3d) — GitHub stays live as a fallback throughout.

One flagged, unresolved mismatch: deploy.yml still triggers on `main`, but
terraform.tfvars.example names prod's deploy branch `release`. Left as a
faithful mirror rather than guessed at — reconcile with whoever's driving
Terraform/deploy.
2026-07-21 00:36:39 +00:00

78 lines
2.7 KiB
Bash
Executable file

#!/usr/bin/env bash
# Re-points the existing LAN dev self-hosted runner from GitHub Actions to
# Forgejo Actions. Run on the SAME machine that already runs the GitHub
# runner (see DEPLOY-DEV.md) — this replaces that runner, it doesn't add a
# second one. Sudo-free, systemd --user, same pattern as the app service.
#
# bash deploy/forgejo/register-lan-runner.sh <forgejo_url> <registration_token>
#
# Get <registration_token> from the Forgejo web UI:
# repo -> Settings -> Actions -> Runners -> Create new Runner
# (or an org/instance-level runner page, if you want it to serve more than
# this one repo — same as the GitHub runner did).
set -euo pipefail
FORGEJO_URL="${1:?usage: $0 <forgejo_url> <registration_token>}"
TOKEN="${2:?}"
RUNNER_DIR="${RUNNER_DIR:-$HOME/forgejo-runner}"
LABELS="${LABELS:-thermograph-lan}"
echo "==> Stopping and disabling the old GitHub Actions runner service, if present"
systemctl --user stop github-actions-runner 2>/dev/null || true
systemctl --user disable github-actions-runner 2>/dev/null || true
echo "==> Installing forgejo-runner into $RUNNER_DIR"
mkdir -p "$RUNNER_DIR"
cd "$RUNNER_DIR"
if [ ! -x ./forgejo-runner ]; then
ARCH="$(uname -m)"
case "$ARCH" in
x86_64) BIN_ARCH=amd64 ;;
aarch64) BIN_ARCH=arm64 ;;
*) echo "Unsupported arch: $ARCH — download the right binary by hand from" \
"https://code.forgejo.org/forgejo/runner/releases" >&2; exit 1 ;;
esac
VER="${FORGEJO_RUNNER_VERSION:-6.3.1}"
curl -fsSL -o forgejo-runner \
"https://code.forgejo.org/forgejo/runner/releases/download/v${VER}/forgejo-runner-${VER}-linux-${BIN_ARCH}"
chmod +x forgejo-runner
fi
echo "==> Registering with $FORGEJO_URL (label: $LABELS)"
./forgejo-runner register --no-interactive \
--instance "$FORGEJO_URL" \
--token "$TOKEN" \
--name "thermograph-lan-$(hostname -s)" \
--labels "$LABELS"
echo "==> systemd --user unit"
mkdir -p "$HOME/.config/systemd/user"
cat > "$HOME/.config/systemd/user/forgejo-runner.service" <<EOF
[Unit]
Description=Forgejo Actions runner (thermograph-lan)
After=network-online.target
[Service]
WorkingDirectory=${RUNNER_DIR}
ExecStart=${RUNNER_DIR}/forgejo-runner daemon
Restart=on-failure
RestartSec=5
[Install]
WantedBy=default.target
EOF
systemctl --user daemon-reload
systemctl --user enable --now forgejo-runner
loginctl enable-linger "$USER" 2>/dev/null || true
cat <<EOF
Done. The runner now serves Forgejo, not GitHub.
status: systemctl --user status forgejo-runner
logs: journalctl --user -u forgejo-runner -f
restart: systemctl --user restart forgejo-runner
The old github-actions-runner unit was stopped and disabled but not deleted —
remove ~/actions-runner by hand once you've confirmed Forgejo deploys work.
EOF