Skip to content

Instantly share code, notes, and snippets.

@beautyfree
Last active March 24, 2026 16:00
Show Gist options
  • Select an option

  • Save beautyfree/5eb5c60c5da307612fe0d5fbc332b6c6 to your computer and use it in GitHub Desktop.

Select an option

Save beautyfree/5eb5c60c5da307612fe0d5fbc332b6c6 to your computer and use it in GitHub Desktop.
Proxmox LXC Create Github Actions Runner
#!/usr/bin/env bash
# This script automates the creation and registration of a Github self-hosted runner within a Proxmox LXC (Linux Container).
# The runner is based on Ubuntu 23.04. Before running the script, ensure you have your GITHUB_TOKEN
# and the OWNERREPO (github owner/repository) available.
# Creates and sets up a self-hosted GitHub Actions runner in an LXC container on Proxmox:
# Create a new LXC container based on ubuntu 23.04
# Installs apt-get dependencies (git, curl)
# Installs docker
# Installs Github actions (needs GITHUB_TOKEN and OWNERREPO) and sets up service
# NOTE: Since the new container has docker support, it cannot be run unpriviledged. This approach is more insecure than using a full-blown VM, at the benefit of being much faster most times. That being said, make sure you only use this self-hosted runner in contexts that you can control at all times (e.g. careful using with public repositories).
# Instructions
# # Download the script
# curl -O https://gist.githubusercontent.com/beautyfree/5eb5c60c5da307612fe0d5fbc332b6c6/raw/lxc_create_github_actions_runner.sh
# # Inspect script, customize variables
# # Run the script
# bash lxc_create_github_actions_runner.sh
# Warning: make sure you read and understand the code you are running before executing it on your machine.
set -e
# Variables
GITHUB_RUNNER_URL="https://github.com/actions/runner/releases/download/v2.333.0/actions-runner-linux-x64-2.333.0.tar.gz"
TEMPL_URL="http://download.proxmox.com/images/system/ubuntu-22.04-standard_22.04-1_amd64.tar.zst"
PCTSIZE="20G"
PCT_ARCH="amd64"
PCT_CORES="4"
PCT_MEMORY="4096"
PCT_SWAP="4096"
PCT_STORAGE="local-lvm"
DEFAULT_IP_ADDR="192.168.0.123/24"
DEFAULT_GATEWAY="192.168.0.1"
# Ask for GitHub token and owner/repo if they're not set
if [ -z "$GITHUB_TOKEN" ]; then
read -r -p "Enter github token: " GITHUB_TOKEN
echo
fi
if [ -z "$OWNERREPO" ]; then
read -r -p "Enter github owner/repo: " OWNERREPO
echo
fi
# log function prints text in yellow
log() {
local text="$1"
echo -e "\033[33m$text\033[0m"
}
# Prompt for network details
# --- Auto-detect network from vmbr0 ---
HOST_IP_CIDR=$(ip -o -f inet addr show vmbr0 | awk '{print $4}')
HOST_IP=$(echo "$HOST_IP_CIDR" | cut -d/ -f1)
CIDR=$(echo "$HOST_IP_CIDR" | cut -d/ -f2)
# Guess gateway (usually .1)
GATEWAY_GUESS=$(ip route | awk '/default/ {print $3}' | head -n1)
# Generate container IP (same subnet, random last octet)
BASE_NET=$(echo "$HOST_IP" | awk -F. '{print $1"."$2"."$3}')
RANDOM_OCTET=$(( (RANDOM % 200) + 50 ))
DEFAULT_IP_ADDR="$BASE_NET.$RANDOM_OCTET/$CIDR"
DEFAULT_GATEWAY="${GATEWAY_GUESS:-$BASE_NET.1}"
echo
echo "Detected network:"
echo " Host IP: $HOST_IP"
echo " Suggested CT IP: $DEFAULT_IP_ADDR"
echo " Suggested GW: $DEFAULT_GATEWAY"
echo
# Prompt user with defaults
read -r -e -p "Container Address IP (CIDR format) [$DEFAULT_IP_ADDR]: " input_ip_addr
IP_ADDR=${input_ip_addr:-$DEFAULT_IP_ADDR}
read -r -e -p "Container Gateway IP [$DEFAULT_GATEWAY]: " input_gateway
GATEWAY=${input_gateway:-$DEFAULT_GATEWAY}
# Get filename from the URLs
TEMPL_FILE=$(basename $TEMPL_URL)
GITHUB_RUNNER_FILE=$(basename $GITHUB_RUNNER_URL)
# Get the next available ID from Proxmox
PCTID=$(pvesh get /cluster/nextid)
# Download Ubuntu template
log "-- Downloading $TEMPL_FILE template..."
curl -q -C - -o "$TEMPL_FILE" $TEMPL_URL
# Create LXC container
log "-- Creating LXC container with ID:$PCTID"
pct create "$PCTID" "$TEMPL_FILE" \
-arch $PCT_ARCH \
-ostype ubuntu \
-hostname github-runner-proxmox-$(openssl rand -hex 3) \
-cores $PCT_CORES \
-memory $PCT_MEMORY \
-swap $PCT_SWAP \
-storage $PCT_STORAGE \
-features nesting=1,keyctl=1 \
-net0 name=eth0,bridge=vmbr0,gw="$GATEWAY",ip="$IP_ADDR",type=veth
# Resize the container
log "-- Resizing container to $PCTSIZE"
pct resize "$PCTID" rootfs $PCTSIZE
# Start the container & run updates inside it
log "-- Starting container"
pct start "$PCTID"
sleep 10
log "-- Running updates"
pct exec "$PCTID" -- bash -c "apt update -y && apt install -y git curl zip && passwd -d root"
# Install Docker inside the container
log "-- Installing docker"
pct exec "$PCTID" -- bash -c "curl -qfsSL https://get.docker.com | sh"
# Get runner installation token
log "-- Getting runner installation token"
RES=$(curl -s -L -X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer $GITHUB_TOKEN" \
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/repos/$OWNERREPO/actions/runners/registration-token)
RUNNER_TOKEN=$(echo $RES | grep -o '"token": "[^"]*' | grep -o '[^"]*$')
if [ -z "$RUNNER_TOKEN" ]; then
echo "ERROR: Failed to get GitHub runner token. Check GITHUB_TOKEN and OWNERREPO."
echo "Response was: $RES"
exit 1
fi
# Install and start the runner
log "-- Installing runner"
pct exec "$PCTID" -- bash -c "mkdir actions-runner && cd actions-runner &&\
curl -o $GITHUB_RUNNER_FILE -L $GITHUB_RUNNER_URL &&\
tar xzf $GITHUB_RUNNER_FILE &&\
RUNNER_ALLOW_RUNASROOT=1 ./config.sh --unattended --url https://github.com/$OWNERREPO --token $RUNNER_TOKEN &&\
./svc.sh install root &&\
./svc.sh start"
# Delete the downloaded Ubuntu template
rm "$TEMPL_FILE"
@beautyfree
Copy link
Copy Markdown
Author

beautyfree commented Mar 24, 2026

Instructions
Download the script

curl -O https://gist.githubusercontent.com/beautyfree/5eb5c60c5da307612fe0d5fbc332b6c6/raw/lxc_create_github_actions_runner.sh

Inspect script, customize variables
Run the script

GITHUB_TOKEN=token OWNERREPO=owner/project bash lxc_create_github_actions_runner.sh

Warning: make sure you read and understand the code you are running before executing it on your machine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment