#!/usr/bin/env bash # # Deploy the BigBrainParking Forgejo Actions runner on a host (Ubuntu/Debian). # Self-contained: installs Docker if missing, writes the runner compose + env, # registers against git.mowden.top, and starts the runner. # # Usage: # sudo bash deploy-runner.sh [INSTALL_DIR] # # REGISTRATION_TOKEN From Forgejo -> hank/BigBrainParking -> # Settings -> Actions -> Runners -> Create new runner. # INSTALL_DIR Where to place the runner (default /opt/bigbrainparking-runner). # # Re-running is safe: it updates files and restarts. The token is only consumed # on the first registration (stored afterwards in /data/.runner). # # NOTE: this host also runs the Camp Scan runner and several databases on a small # box (20 GB / 4 cores). The BigBrainParking build workflow hard-caps itself to # --cpus=2 --memory=8g, but if a Camp Scan build and a BigBrainParking build run # at the SAME time they'll together want ~4 cores / ~16 GB. Keep an eye on that, # or lower the caps in .forgejo/workflows/build-apk.yml if the box gets tight. set -euo pipefail FORGEJO_INSTANCE="https://git.mowden.top" RUNNER_IMAGE="code.forgejo.org/forgejo/runner:6.3.1" RUNNER_NAME="${RUNNER_NAME:-$(hostname)-bigbrainparking}" JOB_LABEL="docker:docker://node:22-bookworm" TOKEN="${1:-${REGISTRATION_TOKEN:-}}" INSTALL_DIR="${2:-/opt/bigbrainparking-runner}" log() { printf '\033[1;32m==>\033[0m %s\n' "$*"; } err() { printf '\033[1;31mERROR:\033[0m %s\n' "$*" >&2; } if [ "$(id -u)" -ne 0 ]; then err "Run with sudo/root (needs to install packages and access the Docker socket)." exit 1 fi if [ -z "$TOKEN" ] && [ ! -f "$INSTALL_DIR/data/.runner" ]; then err "No registration token given and no existing registration found." echo "Usage: sudo bash deploy-runner.sh [INSTALL_DIR]" >&2 exit 1 fi # --- 1. Docker --------------------------------------------------------------- if ! command -v docker >/dev/null 2>&1; then log "Installing Docker (get.docker.com)..." curl -fsSL https://get.docker.com | sh systemctl enable --now docker else log "Docker already installed: $(docker --version)" fi if ! docker compose version >/dev/null 2>&1; then log "Installing docker compose plugin..." apt-get update -y apt-get install -y docker-compose-plugin fi DOCKER_GID="$(stat -c '%g' /var/run/docker.sock)" log "Docker socket group id: $DOCKER_GID" # --- 2. Files ---------------------------------------------------------------- log "Writing runner files to $INSTALL_DIR" mkdir -p "$INSTALL_DIR/data" # The runner image runs as uid/gid 1000 and must own its config dir. chown -R 1000:1000 "$INSTALL_DIR/data" # Runner config: allow the build workflow to mount the persistent cache volumes # (Gradle home = Maven deps + build cache, npm cache) so APK builds don't # redownload and recompile everything each run. Without valid_volumes listed, # the runner rejects the workflow's `volumes:` and the job fails. # (No android-sdk volume: the build image already ships the Android SDK/NDK.) cat > "$INSTALL_DIR/config.yaml" <<'CONFIG' container: valid_volumes: - bigbrainparking-gradle - bigbrainparking-npm CONFIG chown 1000:1000 "$INSTALL_DIR/config.yaml" # Pre-create the named cache volumes (idempotent). docker volume create bigbrainparking-gradle >/dev/null docker volume create bigbrainparking-npm >/dev/null cat > "$INSTALL_DIR/docker-compose.yml" < "$INSTALL_DIR/.env" <&1 | tail -8 cat <