#!/usr/bin/env bash # Runs as root - either INSIDE the Graylog LXC container (via # `pct exec -- bash setup-forgejo-runner.sh`, for redeploying # Graylog config) or directly ON the Proxmox host (for a runner that can # do host-level work like create-graylog-lxc.sh - the container can't run # that against itself). Idempotent: safe to re-run after a partial failure. # # Registers a Forgejo Actions self-hosted runner in "host" mode (no Docker - # it runs shell steps directly on the machine it's installed on) and wires # it up as a systemd service so it survives reboots. # # The registration token is a one-time credential from Forgejo itself, not # something this script invents - get it from: # Repo -> Settings -> Actions -> Runners -> "Create new Runner", or # GET /api/v1/repos///actions/runners/registration-token # (requires a personal access token with repo admin rights) set -euo pipefail FORGEJO_URL="${FORGEJO_URL:?Set FORGEJO_URL, e.g. https://git.zotac.keenetic.link}" FORGEJO_RUNNER_TOKEN="${FORGEJO_RUNNER_TOKEN:?Set FORGEJO_RUNNER_TOKEN (registration token from the repo Settings -> Actions -> Runners page)}" RUNNER_NAME="${RUNNER_NAME:-graylog-container-$(hostname)}" RUNNER_LABEL="${RUNNER_LABEL:-self-hosted:host}" RUNNER_VERSION="12.13.1" RUNNER_DIR="${RUNNER_DIR:-/opt/forgejo-runner}" SERVICE_NAME="${SERVICE_NAME:-forgejo-runner}" # Empty (default) = service runs as root, appropriate INSIDE the container # (its root is already scoped to just that container). On the Proxmox HOST # this must be set to an unprivileged account (e.g. claude-deploy) - a # root-owned systemd service with no User= would give every CI job full, # unrestricted root on the host, defeating the whole point of claude-deploy's # narrowly-scoped sudoers rules. RUNNER_USER="${RUNNER_USER:-}" if [ -t 2 ]; then C_RESET=$'\033[0m'; C_CYAN=$'\033[36m'; C_GREEN=$'\033[32m'; C_YELLOW=$'\033[33m'; C_RED=$'\033[1;31m' else C_RESET=''; C_CYAN=''; C_GREEN=''; C_YELLOW=''; C_RED='' fi log() { echo "${C_CYAN}[setup-forgejo-runner]${C_RESET} $*" >&2; } ok() { echo "${C_GREEN}[setup-forgejo-runner] ✓${C_RESET} $*" >&2; } skip() { echo "${C_YELLOW}[setup-forgejo-runner] ⏭${C_RESET} $*" >&2; } die() { echo "${C_RED}[setup-forgejo-runner] ✗ ERROR:${C_RESET} $*" >&2; exit 1; } [ "$(id -u)" -eq 0 ] || die "must run as root inside the container (use pct exec)" step_install_binary() { if [ -x /usr/local/bin/forgejo-runner ] && /usr/local/bin/forgejo-runner --version 2>/dev/null | grep -q "$RUNNER_VERSION"; then skip "forgejo-runner $RUNNER_VERSION already installed" return fi log "Downloading and verifying forgejo-runner $RUNNER_VERSION..." local base="https://code.forgejo.org/forgejo/runner/releases/download/v${RUNNER_VERSION}" local tmp; tmp="$(mktemp -d)" ( cd "$tmp" \ && curl -fsSL -o "forgejo-runner-${RUNNER_VERSION}-linux-amd64" "$base/forgejo-runner-${RUNNER_VERSION}-linux-amd64" \ && curl -fsSL -o "forgejo-runner-${RUNNER_VERSION}-linux-amd64.sha256" "$base/forgejo-runner-${RUNNER_VERSION}-linux-amd64.sha256" \ && sha256sum -c "forgejo-runner-${RUNNER_VERSION}-linux-amd64.sha256" ) chmod +x "$tmp/forgejo-runner-${RUNNER_VERSION}-linux-amd64" mv "$tmp/forgejo-runner-${RUNNER_VERSION}-linux-amd64" /usr/local/bin/forgejo-runner rm -rf "$tmp" ok "installed forgejo-runner $RUNNER_VERSION" } step_register() { mkdir -p "$RUNNER_DIR" if [ -f "$RUNNER_DIR/.runner" ]; then skip "runner already registered ($RUNNER_DIR/.runner exists)" return fi log "Registering runner '$RUNNER_NAME' with $FORGEJO_URL (host mode, label $RUNNER_LABEL)..." ( cd "$RUNNER_DIR" && /usr/local/bin/forgejo-runner register --no-interactive \ --instance "$FORGEJO_URL" \ --token "$FORGEJO_RUNNER_TOKEN" \ --name "$RUNNER_NAME" \ --labels "$RUNNER_LABEL" ) ok "runner registered" } step_config() { if [ -f "$RUNNER_DIR/config.yaml" ]; then skip "config.yaml already exists" return fi ( cd "$RUNNER_DIR" && /usr/local/bin/forgejo-runner generate-config > config.yaml ) ok "generated config.yaml" } step_ownership() { [ -n "$RUNNER_USER" ] || return chown -R "$RUNNER_USER" "$RUNNER_DIR" ok "chowned $RUNNER_DIR to $RUNNER_USER" } step_service() { if systemctl is-active --quiet "$SERVICE_NAME"; then skip "$SERVICE_NAME service already running" return fi local user_line="" [ -n "$RUNNER_USER" ] && user_line="User=$RUNNER_USER" cat > "/etc/systemd/system/${SERVICE_NAME}.service" <