Gitea Runner Proxmox LXC setup script following community-scripts conventions

This commit is contained in:
matt committed 2026-09-26 15:51:35 +10:00
commit 174134e678
7 files changed
+868

No files matched your search

+4
View File
@@ -0,0 +1,4 @@
# Logs and temporary files
*.log
*.tmp
.DS_Store
+22
View File
@@ -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.
+158
View File
@@ -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 <CTID> -- gitea-runner-register
```
#### Option B: From Inside Container Console
```bash
gitea-runner-register
```
#### Option C: Non-interactive / Headless Registration
```bash
pct exec <CTID> -- gitea-runner-register \
--instance "https://git.mattway.com.au" \
--token "<YOUR_REGISTRATION_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 <CTID> -- 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/).
+200
View File
@@ -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"
+5
View File
@@ -0,0 +1,5 @@
_______ __ ____
/ ____(_) /____ ____ _ / __ \__ ______ ____ ___ _____
/ / __/ / __/ _ \/ __ `/_____/ /_/ / / / / __ \/ __ \/ _ \/ ___/
/ /_/ / / /_/ __/ /_/ /_____/ _, _/ /_/ / / / / / / / __/ /
\____/_/\__/\___/\__,_/ /_/ |_|\__,_/_/ /_/_/ /_/\___/_/
+8
View File
@@ -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
+471
View File
@@ -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? <y/N>: " 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? <y/N>: " 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