#!/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