From 174134e6786c0cf91d8c3603d8b7cfade5003a0a Mon Sep 17 00:00:00 2001 From: Matt Way Date: Sat, 26 Sep 2026 15:33:43 +1000 Subject: [PATCH] Gitea Runner Proxmox LXC setup script following community-scripts conventions --- .gitignore | 4 + LICENSE | 22 ++ README.md | 158 +++++++++++ ct/gitea-runner.sh | 200 ++++++++++++++ ct/headers/gitea-runner | 5 + gitea-runner.sh | 8 + install/gitea-runner-install.sh | 471 ++++++++++++++++++++++++++++++++ 7 files changed, 868 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 ct/gitea-runner.sh create mode 100644 ct/headers/gitea-runner create mode 100644 gitea-runner.sh create mode 100644 install/gitea-runner-install.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f294024 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +# Logs and temporary files +*.log +*.tmp +.DS_Store diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..3ba6c83 --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2024-2026 Matt Way (mattyway) +Copyright (c) 2021-2026 community-scripts ORG + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..8093964 --- /dev/null +++ b/README.md @@ -0,0 +1,158 @@ +# Gitea Runner Proxmox LXC Script + +A script to deploy an official **Gitea Actions Runner** in an unprivileged Proxmox VE LXC container with **Docker CE** pre-installed and configured, styled and structured following [Community Scripts (Proxmox VE Helper-Scripts)](https://community-scripts.org/). + +```text + _______ __ ____ + / ____(_) /____ ____ _ / __ \__ ______ ____ ___ _____ + / / __/ / __/ _ \/ __ `/_____/ /_/ / / / / __ \/ __ \/ _ \/ ___/ +/ /_/ / / /_/ __/ /_/ /_____/ _, _/ /_/ / / / / / / / __/ / +\____/_/\__/\___/\__,_/ /_/ |_|\__,_/_/ /_/_/ /_/\___/_/ +``` + +--- + +## ⚡ Quick Start + +Run the following command directly in your **Proxmox VE Shell**: + +```bash +bash -c "$(curl -fsSL https://git.mattway.com.au/matt/gitea-runner-script/raw/branch/main/ct/gitea-runner.sh)" +``` + +*(Optional: You can also clone and run locally on the Proxmox host)* +```bash +git clone https://git.mattway.com.au/matt/gitea-runner-script.git +./gitea-runner-script/ct/gitea-runner.sh +``` + +--- + +## ⚙️ Container Default Specifications + +| Setting | Default Value | Notes | +| :--- | :--- | :--- | +| **OS** | Debian 12 / 13 | Alpine is also selectable during setup | +| **CPU** | 2 vCPU | Suitable for concurrent CI tasks and compilation | +| **RAM** | 2048 MB | Sufficient for Docker engine and CI workloads | +| **Disk** | 15 GB | Provides headroom for caching Docker layers | +| **Type** | Unprivileged (`1`) | Enhanced container isolation | +| **Features** | `nesting=1`, `keyctl=1` | Required for running Docker inside an unprivileged LXC | + +--- + +## 🔑 Registering with your Gitea Instance + +### 1. Obtain a Registration Token from Gitea +You can register the runner at the instance level, organization level, or repository level: +* **Instance-wide**: *Site Administration* → *Actions* → *Runners* → **Create new Runner** +* **Organization-level**: *Organization Settings* → *Actions* → *Runners* → **Create new Runner** +* **Repository-level**: *Repository Settings* → *Actions* → *Runners* → **Create new Runner** + +Copy the generated **Registration Token**. + +--- + +### 2. Connect the Runner + +You can register the runner interactively during installation, or anytime afterwards: + +#### Option A: From Proxmox VE Host Shell +```bash +pct exec -- gitea-runner-register +``` + +#### Option B: From Inside Container Console +```bash +gitea-runner-register +``` + +#### Option C: Non-interactive / Headless Registration +```bash +pct exec -- gitea-runner-register \ + --instance "https://git.mattway.com.au" \ + --token "" \ + --name "pve-runner-01" \ + --labels "ubuntu-latest:docker://docker.gitea.com/runner-images:ubuntu-latest,ubuntu-22.04:docker://docker.gitea.com/runner-images:ubuntu-22.04,ubuntu-24.04:docker://docker.gitea.com/runner-images:ubuntu-24.04" +``` + +Once registered, the helper starts and enables the `gitea-runner.service` systemd daemon. The runner will immediately show as **Idle** (green) in your Gitea web interface! + +--- + +## 🛠️ Configuration & Service Management + +* **Configuration file**: `/etc/gitea-runner/config.yaml` (symlinked from `/etc/act_runner/config.yaml`) +* **State file**: `/etc/gitea-runner/.runner` +* **Systemd Service**: `gitea-runner.service` (alias `act_runner.service`) + +### Common Management Commands (Inside Container) + +* **Check service status**: + ```bash + systemctl status gitea-runner + ``` +* **View live logs**: + ```bash + journalctl -u gitea-runner -f + ``` +* **Restart runner daemon**: + ```bash + systemctl restart gitea-runner + ``` +* **Verify Docker**: + ```bash + docker info + ``` + +--- + +## 🔄 Updating the Runner + +Just like other containers created with Community Scripts, you can update this container at any time by simply running the built-in `update` command: + +### Option A: From inside the container console +```bash +update +``` + +### Option B: From the Proxmox VE host shell +```bash +pct exec -- update +``` + +### Option C: Via curl one-liner +```bash +bash -c "$(curl -fsSL https://git.mattway.com.au/matt/gitea-runner-script/raw/branch/main/ct/gitea-runner.sh)" +``` + +When executed, the update process automatically: +1. Runs safe APT OS updates (`apt-get update && apt-get upgrade -y`). +2. Checks for Docker engine updates. +3. Checks for the latest release on the official Gitea repository. +4. Stops the service, safely updates the binary, and restarts the daemon if a new version is detected. + +--- + +## 📁 Repository Structure + +Built following the official Community Scripts architecture: + +```text +├── ct/ +│ ├── gitea-runner.sh # Proxmox host creation and update script +│ └── headers/ +│ └── gitea-runner # ASCII art banner +├── install/ +│ └── gitea-runner-install.sh # In-container provisioning script +├── gitea-runner.sh # Root launcher entrypoint +├── LICENSE # MIT License +└── README.md # Documentation +``` + +--- + +## 📄 License + +This project is licensed under the [MIT License](LICENSE). +Built with the foundation and conventions established by [community-scripts ORG](https://community-scripts.org/). diff --git a/ct/gitea-runner.sh b/ct/gitea-runner.sh new file mode 100644 index 0000000..732845d --- /dev/null +++ b/ct/gitea-runner.sh @@ -0,0 +1,200 @@ +#!/usr/bin/env bash +_CS_DEFAULT_URL="${COMMUNITY_SCRIPTS_URL:-${_CS_DEFAULT_URL:-https://git.mattway.com.au/matt/gitea-runner-script/raw/branch/main}}" +_cs_boot="${COMMUNITY_SCRIPTS_CORE_DIR:-$(dirname "${BASH_SOURCE[0]}")/../../core}/core/build.func" +source "$_cs_boot" 2>/dev/null || source <(curl -fsSL "${COMMUNITY_SCRIPTS_CORE_URL:-https://raw.githubusercontent.com/community-scripts/core/main}/core/build.func") +# Copyright (c) 2021-2026 community-scripts ORG +# Author: mattyway +# License: MIT | https://git.mattway.com.au/matt/gitea-runner-script/raw/branch/main/LICENSE +# Source: https://about.gitea.com/ | Github: https://gitea.com/gitea/act_runner + +APP="Gitea Runner" +var_tags="${var_tags:-gitea;runner;docker;ci-cd}" +var_arm64="${var_arm64:-yes}" +var_unprivileged="${var_unprivileged:-1}" +var_keyctl="${var_keyctl:-1}" + +if [[ -z "${var_os:-}" ]] && command -v pveversion >/dev/null 2>&1; then + var_os=$(msg_menu "Choose the container OS" \ + "debian" "Debian 12/13 (Recommended for Docker actions)" \ + "alpine" "Alpine (Minimal footprint)") +fi + +if [[ "${var_os:-}" == "alpine" ]]; then + var_cpu="${var_cpu:-2}" + var_ram="${var_ram:-1024}" + var_disk="${var_disk:-10}" + var_version="${var_version:-3.24}" +else + var_cpu="${var_cpu:-2}" + var_ram="${var_ram:-2048}" + var_disk="${var_disk:-15}" + var_version="${var_version:-13}" +fi + +header_info "$APP" +variables +NSAPP="gitea-runner" +var_install="${NSAPP}-install" +color +catch_errors + +update_deb_based() { + if [[ ! -f /usr/local/bin/gitea-runner && ! -f /usr/local/bin/act_runner ]]; then + msg_error "No ${APP} installation found!" + exit 1 + fi + + msg_info "Updating base system" + apt_update_safe + $STD apt-get upgrade -y + msg_ok "Base system updated" + + if dpkg-query -W -f='${Status}' docker-ce 2>/dev/null | grep -q "ok installed"; then + USE_DOCKER_REPO="true" setup_docker + fi + + msg_info "Checking for Gitea Runner updates" + local runner_bin + if [[ -f /usr/local/bin/gitea-runner ]]; then + runner_bin="/usr/local/bin/gitea-runner" + else + runner_bin="/usr/local/bin/act_runner" + fi + + local current_version + current_version=$("$runner_bin" --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1 || echo "0.0.0") + + local release_json + release_json=$(curl -fsSL --connect-timeout 10 "https://gitea.com/api/v1/repos/gitea/act_runner/releases/latest" 2>/dev/null || true) + if [[ -z "$release_json" ]]; then + release_json=$(curl -fsSL --connect-timeout 10 "https://gitea.com/api/v1/repos/gitea/runner/releases/latest" 2>/dev/null || true) + fi + + if [[ -n "$release_json" ]]; then + local latest_version + latest_version=$(echo "$release_json" | jq -r '.tag_name // empty' | tr -d 'v') + local clean_current="${current_version#v}" + + if [[ -n "$latest_version" && "$latest_version" != "$clean_current" ]]; then + msg_info "Updating Gitea Runner (${clean_current} -> ${latest_version})" + local arch + case "$(uname -m)" in + x86_64) arch="amd64" ;; + aarch64|arm64) arch="arm64" ;; + armv7l) arch="arm-7" ;; + *) arch="amd64" ;; + esac + + local dl_url + dl_url=$(echo "$release_json" | jq -r --arg a "linux-$arch" '.assets[] | select(.name | endswith($a)) | .browser_download_url' | head -1) + + if [[ -n "$dl_url" && "$dl_url" != "null" ]]; then + systemctl stop gitea-runner 2>/dev/null || systemctl stop act_runner 2>/dev/null || true + curl -fsSL "$dl_url" -o "${runner_bin}.new" + chmod +x "${runner_bin}.new" + mv "${runner_bin}.new" "$runner_bin" + [[ ! -f /usr/local/bin/act_runner ]] && ln -sf "$runner_bin" /usr/local/bin/act_runner + [[ ! -f /usr/local/bin/gitea-runner ]] && ln -sf "$runner_bin" /usr/local/bin/gitea-runner + + systemctl start gitea-runner 2>/dev/null || systemctl start act_runner 2>/dev/null || true + msg_ok "Updated Gitea Runner to v${latest_version}" + else + msg_warn "Could not resolve release download URL for architecture: linux-$arch" + fi + else + msg_ok "Gitea Runner is up to date (v${clean_current})" + fi + else + msg_warn "Could not reach Gitea API to check for updates" + fi + + msg_ok "Updated successfully!" +} + +update_alpine() { + msg_info "Updating Alpine packages" + $STD apk -U upgrade + msg_ok "Updated Alpine packages" + + if command -v docker &>/dev/null; then + msg_info "Updating Docker" + $STD apk add --upgrade docker + msg_ok "Docker updated" + fi + + msg_info "Checking for Gitea Runner updates" + local runner_bin + if [[ -f /usr/local/bin/gitea-runner ]]; then + runner_bin="/usr/local/bin/gitea-runner" + else + runner_bin="/usr/local/bin/act_runner" + fi + + local current_version + current_version=$("$runner_bin" --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1 || echo "0.0.0") + + local release_json + release_json=$(curl -fsSL --connect-timeout 10 "https://gitea.com/api/v1/repos/gitea/act_runner/releases/latest" 2>/dev/null || true) + if [[ -z "$release_json" ]]; then + release_json=$(curl -fsSL --connect-timeout 10 "https://gitea.com/api/v1/repos/gitea/runner/releases/latest" 2>/dev/null || true) + fi + + if [[ -n "$release_json" ]]; then + local latest_version + latest_version=$(echo "$release_json" | jq -r '.tag_name // empty' | tr -d 'v') + local clean_current="${current_version#v}" + + if [[ -n "$latest_version" && "$latest_version" != "$clean_current" ]]; then + msg_info "Updating Gitea Runner (${clean_current} -> ${latest_version})" + local arch + case "$(uname -m)" in + x86_64) arch="amd64" ;; + aarch64|arm64) arch="arm64" ;; + armv7l) arch="arm-7" ;; + *) arch="amd64" ;; + esac + + local dl_url + dl_url=$(echo "$release_json" | jq -r --arg a "linux-$arch" '.assets[] | select(.name | endswith($a)) | .browser_download_url' | head -1) + + if [[ -n "$dl_url" && "$dl_url" != "null" ]]; then + rc-service gitea-runner stop 2>/dev/null || true + curl -fsSL "$dl_url" -o "${runner_bin}.new" + chmod +x "${runner_bin}.new" + mv "${runner_bin}.new" "$runner_bin" + [[ ! -f /usr/local/bin/act_runner ]] && ln -sf "$runner_bin" /usr/local/bin/act_runner + [[ ! -f /usr/local/bin/gitea-runner ]] && ln -sf "$runner_bin" /usr/local/bin/gitea-runner + + rc-service gitea-runner start 2>/dev/null || true + msg_ok "Updated Gitea Runner to v${latest_version}" + else + msg_warn "Could not resolve release download URL for architecture: linux-$arch" + fi + else + msg_ok "Gitea Runner is up to date (v${clean_current})" + fi + else + msg_warn "Could not reach Gitea API to check for updates" + fi + + msg_ok "Updated successfully!" +} + +function update_script() { + header_info + check_container_storage + check_container_resources + run_os_update +} + +start +build_container +description + +msg_ok "Completed successfully!\n" +echo -e "${CREATING}${GN}${APP} LXC container has been successfully created!${CL}" +echo -e "${INFO}${YW}Container IP: ${GN}${IP}${CL}\n" +echo -e "${TAB}To register the runner with your Gitea instance:" +echo -e "${TAB}${TAB}${GN}pct exec ${CTID} -- gitea-runner-register${CL}" +echo -e "${TAB}Or open the container console and execute:" +echo -e "${TAB}${TAB}${GN}gitea-runner-register${CL}\n" diff --git a/ct/headers/gitea-runner b/ct/headers/gitea-runner new file mode 100644 index 0000000..5e34971 --- /dev/null +++ b/ct/headers/gitea-runner @@ -0,0 +1,5 @@ + _______ __ ____ + / ____(_) /____ ____ _ / __ \__ ______ ____ ___ _____ + / / __/ / __/ _ \/ __ `/_____/ /_/ / / / / __ \/ __ \/ _ \/ ___/ +/ /_/ / / /_/ __/ /_/ /_____/ _, _/ /_/ / / / / / / / __/ / +\____/_/\__/\___/\__,_/ /_/ |_|\__,_/_/ /_/_/ /_/\___/_/ diff --git a/gitea-runner.sh b/gitea-runner.sh new file mode 100644 index 0000000..ed8b5e9 --- /dev/null +++ b/gitea-runner.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +# Quick launcher for Gitea Runner LXC creation +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)" +if [[ -f "${SCRIPT_DIR}/ct/gitea-runner.sh" ]]; then + exec bash "${SCRIPT_DIR}/ct/gitea-runner.sh" "$@" +else + exec bash -c "$(curl -fsSL https://git.mattway.com.au/matt/gitea-runner-script/raw/branch/main/ct/gitea-runner.sh)" "$@" +fi diff --git a/install/gitea-runner-install.sh b/install/gitea-runner-install.sh new file mode 100644 index 0000000..af42440 --- /dev/null +++ b/install/gitea-runner-install.sh @@ -0,0 +1,471 @@ +#!/usr/bin/env bash + +# Copyright (c) 2021-2026 community-scripts ORG +# Author: mattyway +# License: MIT | https://git.mattway.com.au/matt/gitea-runner-script/raw/branch/main/LICENSE +# Source: https://about.gitea.com/ | Github: https://gitea.com/gitea/act_runner + +source /dev/stdin <<<"$FUNCTIONS_FILE_PATH" +color +verb_ip6 +catch_errors +setting_up_container +network_check +update_os + +setup_deb_based() { + msg_info "Installing Dependencies" + $STD apt-get install -y \ + curl \ + sudo \ + git \ + jq \ + tar \ + xz-utils \ + ca-certificates \ + gnupg + msg_ok "Installed Dependencies" + + msg_info "Setting up Docker" + if declare -f setup_docker &>/dev/null; then + setup_docker + else + install -m 0755 -d /etc/apt/keyrings + curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc + chmod a+r /etc/apt/keyrings/docker.asc + echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian $(. /etc/os-release && echo "$VERSION_CODENAME") stable" > /etc/apt/sources.list.d/docker.list + $STD apt-get update + $STD apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin + systemctl enable --now docker + fi + msg_ok "Configured Docker" + + msg_info "Installing Gitea Runner" + local arch + case "$(dpkg --print-architecture 2>/dev/null || uname -m)" in + amd64|x86_64) arch="amd64" ;; + arm64|aarch64) arch="arm64" ;; + armhf|armv7l) arch="arm-7" ;; + *) arch="amd64" ;; + esac + + local release_json + release_json=$(curl -fsSL --connect-timeout 10 "https://gitea.com/api/v1/repos/gitea/act_runner/releases/latest" 2>/dev/null || true) + if [[ -z "$release_json" ]]; then + release_json=$(curl -fsSL --connect-timeout 10 "https://gitea.com/api/v1/repos/gitea/runner/releases/latest" 2>/dev/null || true) + fi + + local tag_name dl_url + tag_name=$(echo "$release_json" | jq -r '.tag_name // empty') + dl_url=$(echo "$release_json" | jq -r --arg a "linux-$arch" '.assets[] | select(.name | endswith($a)) | .browser_download_url' | head -1) + + if [[ -z "$dl_url" || "$dl_url" == "null" ]]; then + tag_name="${tag_name:-v4.0.0}" + local ver="${tag_name#v}" + dl_url="https://gitea.com/gitea/runner/releases/download/${tag_name}/gitea-runner-${ver}-linux-${arch}" + fi + + curl -fsSL "$dl_url" -o /usr/local/bin/gitea-runner + chmod +x /usr/local/bin/gitea-runner + ln -sf /usr/local/bin/gitea-runner /usr/local/bin/act_runner + msg_ok "Installed Gitea Runner ($(/usr/local/bin/gitea-runner --version | head -1))" + + msg_info "Configuring Gitea Runner" + mkdir -p /etc/gitea-runner + /usr/local/bin/gitea-runner config generate > /etc/gitea-runner/config.yaml + ln -sf /etc/gitea-runner /etc/act_runner + msg_ok "Configured Gitea Runner (/etc/gitea-runner/config.yaml)" + + msg_info "Creating Systemd Service" + cat <<'EOF' >/etc/systemd/system/gitea-runner.service +[Unit] +Description=Gitea Actions Runner +After=network.target docker.service +Requires=docker.service + +[Service] +Type=simple +WorkingDirectory=/etc/gitea-runner +ExecStart=/usr/local/bin/gitea-runner daemon --config /etc/gitea-runner/config.yaml +Restart=always +RestartSec=5 +TimeoutSec=30 +User=root + +[Install] +WantedBy=multi-user.target +EOF + ln -sf /etc/systemd/system/gitea-runner.service /etc/systemd/system/act_runner.service + systemctl daemon-reload + msg_ok "Created Service (gitea-runner.service)" + + msg_info "Creating Registration Helper" + cat <<'EOF' >/usr/local/bin/gitea-runner-register +#!/usr/bin/env bash +set -euo pipefail + +RD='\033[0;31m' +GN='\033[0;32m' +YW='\033[0;33m' +BL='\033[0;34m' +BOLD='\033[1m' +CL='\033[0m' + +RUNNER_BIN="" +if command -v gitea-runner &>/dev/null; then + RUNNER_BIN="gitea-runner" +elif command -v act_runner &>/dev/null; then + RUNNER_BIN="act_runner" +elif [[ -f /usr/local/bin/gitea-runner ]]; then + RUNNER_BIN="/usr/local/bin/gitea-runner" +else + echo -e "${RD}Error: Gitea Runner binary not found.${CL}" >&2 + exit 1 +fi + +CONFIG_DIR="/etc/gitea-runner" +CONFIG_FILE="${CONFIG_DIR}/config.yaml" + +mkdir -p "$CONFIG_DIR" +cd "$CONFIG_DIR" + +if [[ ! -f "$CONFIG_FILE" ]]; then + "$RUNNER_BIN" config generate > "$CONFIG_FILE" 2>/dev/null || true +fi + +echo -e "\n${BOLD}${BL}=== Gitea Actions Runner Registration ===${CL}\n" + +INSTANCE_URL="" +REG_TOKEN="" +RUNNER_NAME="" +RUNNER_LABELS="" +EPHEMERAL="" + +while [[ $# -gt 0 ]]; do + case "$1" in + --instance|-i) INSTANCE_URL="$2"; shift 2 ;; + --token|-t) REG_TOKEN="$2"; shift 2 ;; + --name|-n) RUNNER_NAME="$2"; shift 2 ;; + --labels|-l) RUNNER_LABELS="$2"; shift 2 ;; + --ephemeral) EPHEMERAL="--ephemeral"; shift ;; + --help|-h) + echo "Usage: gitea-runner-register [options]" + echo "" + echo "Options:" + echo " -i, --instance URL Gitea instance address (e.g. https://gitea.example.com)" + echo " -t, --token TOKEN Runner registration token" + echo " -n, --name NAME Runner name (default: $(hostname))" + echo " -l, --labels LABELS Comma-separated labels" + echo " --ephemeral Configure runner to accept only a single job" + echo " -h, --help Show this help message" + exit 0 + ;; + *) + echo -e "${RD}Unknown option: $1${CL}" >&2 + exit 1 + ;; + esac +done + +if [[ -z "$INSTANCE_URL" ]]; then + echo -e "${YW}Enter your Gitea instance address${CL}" + read -r -p " Instance URL (e.g. https://gitea.example.com): " INSTANCE_URL +fi + +if [[ -z "$INSTANCE_URL" ]]; then + echo -e "${RD}Error: Instance URL cannot be empty.${CL}" >&2 + exit 1 +fi +INSTANCE_URL="${INSTANCE_URL%/}" + +if [[ -z "$REG_TOKEN" ]]; then + echo -e "\n${YW}Enter the Runner Registration Token${CL}" + echo -e " (Find this in Gitea > Site Administration / Org / Repo > Actions > Runners)" + read -r -p " Registration Token: " REG_TOKEN +fi + +if [[ -z "$REG_TOKEN" ]]; then + echo -e "${RD}Error: Registration token cannot be empty.${CL}" >&2 + exit 1 +fi + +if [[ -z "$RUNNER_NAME" ]]; then + DEFAULT_NAME="$(hostname)" + read -r -p " Runner Name [default: ${DEFAULT_NAME}]: " RUNNER_NAME + RUNNER_NAME="${RUNNER_NAME:-$DEFAULT_NAME}" +fi + +if [[ -z "$RUNNER_LABELS" ]]; then + DEFAULT_LABELS="ubuntu-latest:docker://docker.gitea.com/runner-images:ubuntu-latest,ubuntu-22.04:docker://docker.gitea.com/runner-images:ubuntu-22.04,ubuntu-24.04:docker://docker.gitea.com/runner-images:ubuntu-24.04" + echo -e "\n${YW}Runner Labels${CL} [default: ${DEFAULT_LABELS}]" + read -r -p " Labels (press Enter for default): " RUNNER_LABELS + RUNNER_LABELS="${RUNNER_LABELS:-$DEFAULT_LABELS}" +fi + +echo -e "\n${BL}Registering runner with ${INSTANCE_URL}...${CL}" + +CMD=("$RUNNER_BIN" "register" "--no-interactive" \ + "--instance" "$INSTANCE_URL" \ + "--token" "$REG_TOKEN" \ + "--name" "$RUNNER_NAME" \ + "--labels" "$RUNNER_LABELS" \ + "--config" "$CONFIG_FILE") + +if [[ -n "$EPHEMERAL" ]]; then + CMD+=("$EPHEMERAL") +fi + +if "${CMD[@]}"; then + echo -e "${GN}✓ Runner registered successfully!${CL}" +else + echo -e "${RD}✗ Registration failed. Please check the URL and token.${CL}" >&2 + exit 1 +fi + +echo -e "\n${BL}Starting runner daemon service...${CL}" +if command -v systemctl &>/dev/null; then + systemctl daemon-reload + systemctl enable --now gitea-runner.service 2>/dev/null || systemctl enable --now act_runner.service 2>/dev/null || true + sleep 1 + if systemctl is-active --quiet gitea-runner.service 2>/dev/null || systemctl is-active --quiet act_runner.service 2>/dev/null; then + echo -e "${GN}✓ Service is running!${CL}" + else + echo -e "${YW}! Service enabled. Check 'systemctl status gitea-runner' or 'journalctl -u gitea-runner -f' for logs.${CL}" + fi +elif command -v rc-service &>/dev/null; then + rc-update add gitea-runner default 2>/dev/null || true + rc-service gitea-runner restart 2>/dev/null || rc-service gitea-runner start 2>/dev/null || true + echo -e "${GN}✓ Service started!${CL}" +fi + +echo -e "\n${GN}${BOLD}Registration complete!${CL}" +echo -e "You should now see the runner '${RUNNER_NAME}' in your Gitea Actions dashboard.\n" +EOF + chmod +x /usr/local/bin/gitea-runner-register + ln -sf /usr/local/bin/gitea-runner-register /usr/local/bin/act-runner-register + msg_ok "Created Registration Helper (/usr/local/bin/gitea-runner-register)" + + if [[ -t 0 ]] && [[ -z "${var_unattended:-}" ]]; then + read -r -p "${TAB3}Would you like to register this runner with Gitea now? : " register_choice + if [[ "${register_choice,,}" =~ ^(y|yes)$ ]]; then + /usr/local/bin/gitea-runner-register || msg_warn "Registration incomplete. Run 'gitea-runner-register' anytime to complete." + else + msg_info "Registration deferred. Run 'gitea-runner-register' when ready." + fi + else + msg_info "Run 'gitea-runner-register' inside the container to connect to Gitea." + fi +} + +setup_alpine() { + msg_info "Installing Dependencies" + $STD apk add --no-cache tzdata openssl curl jq bash docker + $STD rc-update add docker default + $STD rc-service docker start + msg_ok "Installed Dependencies & Docker" + + msg_info "Installing Gitea Runner" + local arch + case "$(uname -m)" in + amd64|x86_64) arch="amd64" ;; + arm64|aarch64) arch="arm64" ;; + armhf|armv7l) arch="arm-7" ;; + *) arch="amd64" ;; + esac + + local release_json + release_json=$(curl -fsSL --connect-timeout 10 "https://gitea.com/api/v1/repos/gitea/act_runner/releases/latest" 2>/dev/null || true) + if [[ -z "$release_json" ]]; then + release_json=$(curl -fsSL --connect-timeout 10 "https://gitea.com/api/v1/repos/gitea/runner/releases/latest" 2>/dev/null || true) + fi + + local tag_name dl_url + tag_name=$(echo "$release_json" | jq -r '.tag_name // empty') + dl_url=$(echo "$release_json" | jq -r --arg a "linux-$arch" '.assets[] | select(.name | endswith($a)) | .browser_download_url' | head -1) + + if [[ -z "$dl_url" || "$dl_url" == "null" ]]; then + tag_name="${tag_name:-v4.0.0}" + local ver="${tag_name#v}" + dl_url="https://gitea.com/gitea/runner/releases/download/${tag_name}/gitea-runner-${ver}-linux-${arch}" + fi + + curl -fsSL "$dl_url" -o /usr/local/bin/gitea-runner + chmod +x /usr/local/bin/gitea-runner + ln -sf /usr/local/bin/gitea-runner /usr/local/bin/act_runner + msg_ok "Installed Gitea Runner ($(/usr/local/bin/gitea-runner --version | head -1))" + + msg_info "Configuring Gitea Runner" + mkdir -p /etc/gitea-runner + /usr/local/bin/gitea-runner config generate > /etc/gitea-runner/config.yaml + ln -sf /etc/gitea-runner /etc/act_runner + msg_ok "Configured Gitea Runner (/etc/gitea-runner/config.yaml)" + + msg_info "Creating OpenRC Service" + cat <<'EOF' >/etc/init.d/gitea-runner +#!/sbin/openrc-run +name="Gitea Action Runner" +description="Gitea Action Runner daemon" +command="/usr/local/bin/gitea-runner" +command_args="daemon --config /etc/gitea-runner/config.yaml" +command_background="yes" +pidfile="/run/gitea-runner.pid" +directory="/etc/gitea-runner" + +depend() { + need net docker +} +EOF + chmod +x /etc/init.d/gitea-runner + rc-update add gitea-runner default + msg_ok "Created Service (gitea-runner)" + + msg_info "Creating Registration Helper" + cat <<'EOF' >/usr/local/bin/gitea-runner-register +#!/usr/bin/env bash +set -euo pipefail + +RD='\033[0;31m' +GN='\033[0;32m' +YW='\033[0;33m' +BL='\033[0;34m' +BOLD='\033[1m' +CL='\033[0m' + +RUNNER_BIN="" +if command -v gitea-runner &>/dev/null; then + RUNNER_BIN="gitea-runner" +elif command -v act_runner &>/dev/null; then + RUNNER_BIN="act_runner" +elif [[ -f /usr/local/bin/gitea-runner ]]; then + RUNNER_BIN="/usr/local/bin/gitea-runner" +else + echo -e "${RD}Error: Gitea Runner binary not found.${CL}" >&2 + exit 1 +fi + +CONFIG_DIR="/etc/gitea-runner" +CONFIG_FILE="${CONFIG_DIR}/config.yaml" + +mkdir -p "$CONFIG_DIR" +cd "$CONFIG_DIR" + +if [[ ! -f "$CONFIG_FILE" ]]; then + "$RUNNER_BIN" config generate > "$CONFIG_FILE" 2>/dev/null || true +fi + +echo -e "\n${BOLD}${BL}=== Gitea Actions Runner Registration ===${CL}\n" + +INSTANCE_URL="" +REG_TOKEN="" +RUNNER_NAME="" +RUNNER_LABELS="" +EPHEMERAL="" + +while [[ $# -gt 0 ]]; do + case "$1" in + --instance|-i) INSTANCE_URL="$2"; shift 2 ;; + --token|-t) REG_TOKEN="$2"; shift 2 ;; + --name|-n) RUNNER_NAME="$2"; shift 2 ;; + --labels|-l) RUNNER_LABELS="$2"; shift 2 ;; + --ephemeral) EPHEMERAL="--ephemeral"; shift ;; + --help|-h) + echo "Usage: gitea-runner-register [options]" + echo "" + echo "Options:" + echo " -i, --instance URL Gitea instance address (e.g. https://gitea.example.com)" + echo " -t, --token TOKEN Runner registration token" + echo " -n, --name NAME Runner name (default: $(hostname))" + echo " -l, --labels LABELS Comma-separated labels" + echo " --ephemeral Configure runner to accept only a single job" + echo " -h, --help Show this help message" + exit 0 + ;; + *) + echo -e "${RD}Unknown option: $1${CL}" >&2 + exit 1 + ;; + esac +done + +if [[ -z "$INSTANCE_URL" ]]; then + echo -e "${YW}Enter your Gitea instance address${CL}" + read -r -p " Instance URL (e.g. https://gitea.example.com): " INSTANCE_URL +fi + +if [[ -z "$INSTANCE_URL" ]]; then + echo -e "${RD}Error: Instance URL cannot be empty.${CL}" >&2 + exit 1 +fi +INSTANCE_URL="${INSTANCE_URL%/}" + +if [[ -z "$REG_TOKEN" ]]; then + echo -e "\n${YW}Enter the Runner Registration Token${CL}" + echo -e " (Find this in Gitea > Site Administration / Org / Repo > Actions > Runners)" + read -r -p " Registration Token: " REG_TOKEN +fi + +if [[ -z "$REG_TOKEN" ]]; then + echo -e "${RD}Error: Registration token cannot be empty.${CL}" >&2 + exit 1 +fi + +if [[ -z "$RUNNER_NAME" ]]; then + DEFAULT_NAME="$(hostname)" + read -r -p " Runner Name [default: ${DEFAULT_NAME}]: " RUNNER_NAME + RUNNER_NAME="${RUNNER_NAME:-$DEFAULT_NAME}" +fi + +if [[ -z "$RUNNER_LABELS" ]]; then + DEFAULT_LABELS="ubuntu-latest:docker://docker.gitea.com/runner-images:ubuntu-latest,ubuntu-22.04:docker://docker.gitea.com/runner-images:ubuntu-22.04,ubuntu-24.04:docker://docker.gitea.com/runner-images:ubuntu-24.04" + echo -e "\n${YW}Runner Labels${CL} [default: ${DEFAULT_LABELS}]" + read -r -p " Labels (press Enter for default): " RUNNER_LABELS + RUNNER_LABELS="${RUNNER_LABELS:-$DEFAULT_LABELS}" +fi + +echo -e "\n${BL}Registering runner with ${INSTANCE_URL}...${CL}" + +CMD=("$RUNNER_BIN" "register" "--no-interactive" \ + "--instance" "$INSTANCE_URL" \ + "--token" "$REG_TOKEN" \ + "--name" "$RUNNER_NAME" \ + "--labels" "$RUNNER_LABELS" \ + "--config" "$CONFIG_FILE") + +if [[ -n "$EPHEMERAL" ]]; then + CMD+=("$EPHEMERAL") +fi + +if "${CMD[@]}"; then + echo -e "${GN}✓ Runner registered successfully!${CL}" +else + echo -e "${RD}✗ Registration failed. Please check the URL and token.${CL}" >&2 + exit 1 +fi + +echo -e "\n${BL}Starting runner daemon service...${CL}" +rc-service gitea-runner restart 2>/dev/null || rc-service gitea-runner start 2>/dev/null || true +echo -e "${GN}✓ Service started!${CL}" + +echo -e "\n${GN}${BOLD}Registration complete!${CL}" +echo -e "You should now see the runner '${RUNNER_NAME}' in your Gitea Actions dashboard.\n" +EOF + chmod +x /usr/local/bin/gitea-runner-register + ln -sf /usr/local/bin/gitea-runner-register /usr/local/bin/act-runner-register + msg_ok "Created Registration Helper (/usr/local/bin/gitea-runner-register)" + + if [[ -t 0 ]] && [[ -z "${var_unattended:-}" ]]; then + read -r -p "${TAB3}Would you like to register this runner with Gitea now? : " register_choice + if [[ "${register_choice,,}" =~ ^(y|yes)$ ]]; then + /usr/local/bin/gitea-runner-register || msg_warn "Registration incomplete. Run 'gitea-runner-register' anytime to complete." + else + msg_info "Registration deferred. Run 'gitea-runner-register' when ready." + fi + else + msg_info "Run 'gitea-runner-register' inside the container to connect to Gitea." + fi +} + +run_os_setup +motd_ssh +customize +cleanup_lxc