Last active
January 12, 2026 13:05
-
-
Save raveenb/687611354264f5f12741e9a2be9b443a to your computer and use it in GitHub Desktop.
Self-hosted CI runner setup for GitHub Actions + GitLab CI. Cut your CI/CD costs by 90%. MIT License.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # | |
| # ============================================================================= | |
| # Self-Hosted CI Runner Setup Script | |
| # For GitHub Actions + GitLab CI on a Single VM | |
| # ============================================================================= | |
| # | |
| # Author: Luminary Lane (https://luminarylane.app) | |
| # License: MIT | |
| # Version: 1.2.0 | |
| # | |
| # This script sets up a fresh Ubuntu 24.04 VM as a dual CI runner for both | |
| # GitHub Actions and GitLab CI, with built-in maintenance and hygiene. | |
| # | |
| # ----------------------------------------------------------------------------- | |
| # WHY SELF-HOST? | |
| # ----------------------------------------------------------------------------- | |
| # | |
| # THE PROBLEM: GitHub's CI Pricing Changes (January 2026) | |
| # | |
| # GitHub has announced significant pricing changes for private repositories: | |
| # - Increased per-minute costs for hosted runners | |
| # - New charges for self-hosted runner management access | |
| # - Variable costs that scale unpredictably with your build frequency | |
| # | |
| # For startups with active development, this means CI costs can spike | |
| # unexpectedly during crunch time—exactly when you can least afford it. | |
| # | |
| # ----------------------------------------------------------------------------- | |
| # THE SOLUTION: Variable Cost → Fixed Cost | |
| # ----------------------------------------------------------------------------- | |
| # | |
| # Self-hosting transforms your CI expenses from unpredictable variable costs | |
| # to a predictable fixed monthly expense: | |
| # | |
| # BEFORE (Variable - GitHub Hosted): | |
| # - Linux: $0.008/min - you pay only for minutes used | |
| # - Example: 50 builds/day × 10 min × 30 days = 15,000 min = $120/month | |
| # - Costs spike during active development sprints | |
| # - Hard to budget when build frequency varies | |
| # | |
| # AFTER (Fixed - Self-Hosted): | |
| # - 4-core/32GB VM: ~$30-50/month (varies by provider) | |
| # - Same cost whether you run 100 or 1000 builds | |
| # - Serves BOTH GitHub Actions AND GitLab CI | |
| # - Add more runners on same VM for parallelism (both GH + GL support this) | |
| # - Full control, no queue times, predictable expenses | |
| # | |
| # BREAK-EVEN: ~60-100 build hours/month. Above that, self-hosted wins. | |
| # RESULT: For active teams, 70-90% cost reduction + budget predictability | |
| # | |
| # ----------------------------------------------------------------------------- | |
| # USAGE | |
| # ----------------------------------------------------------------------------- | |
| # | |
| # Option 1 - Direct run: | |
| # curl -fsSL https://gist.githubusercontent.com/raveenb/687611354264f5f12741e9a2be9b443a/raw/setup-ci-runner.sh | sudo bash | |
| # | |
| # Option 2 - Download and customize: | |
| # wget https://gist.githubusercontent.com/raveenb/687611354264f5f12741e9a2be9b443a/raw/setup-ci-runner.sh | |
| # # Edit the CONFIGURATION section below | |
| # chmod +x setup-ci-runner.sh | |
| # sudo ./setup-ci-runner.sh | |
| # | |
| # After running, you still need to register the runners: | |
| # 1. GitHub: cd /opt/actions-runner && ./config.sh --url ... --token ... | |
| # 2. GitLab: sudo gitlab-runner register | |
| # | |
| # ----------------------------------------------------------------------------- | |
| # CHANGELOG | |
| # ----------------------------------------------------------------------------- | |
| # | |
| # v1.2.0 (2026-01-12): | |
| # - Added Docker Compose V2 plugin installation (required for modern workflows) | |
| # - Ubuntu's docker.io package doesn't include Compose plugin by default | |
| # | |
| # v1.1.0: | |
| # - Added file descriptor limits configuration | |
| # - Added Playwright browser dependencies option | |
| # | |
| # v1.0.0: | |
| # - Initial release | |
| # | |
| # ----------------------------------------------------------------------------- | |
| # MIT LICENSE | |
| # ----------------------------------------------------------------------------- | |
| # | |
| # Copyright (c) 2026 Luminary Lane | |
| # | |
| # 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. | |
| # | |
| # ============================================================================= | |
| # ============================================================================= | |
| # CONFIGURATION - Customize these values for your setup | |
| # ============================================================================= | |
| # GitHub Actions Runner version (check: https://github.com/actions/runner/releases) | |
| ACTIONS_RUNNER_VERSION="2.321.0" | |
| # Swap file size (recommended: equal to RAM for <32GB, half of RAM for >32GB) | |
| SWAP_SIZE="4G" | |
| # Swap behavior (10 = only swap under memory pressure, default is 60) | |
| SWAPPINESS=10 | |
| # Journal log limits | |
| JOURNAL_MAX_SIZE="500M" | |
| JOURNAL_MAX_AGE="7day" | |
| # Cleanup schedule (cron format: minute hour day month weekday) | |
| CLEANUP_SCHEDULE="0 3 * * *" # Daily at 3 AM | |
| # Disk space alert threshold (percentage) | |
| DISK_ALERT_THRESHOLD=80 | |
| # Docker image retention (hours) - images older than this are pruned | |
| DOCKER_IMAGE_RETENTION_HOURS=168 # 7 days | |
| # Temp file retention (days) | |
| TEMP_FILE_RETENTION_DAYS=7 | |
| # Install Playwright browser dependencies? (true/false) | |
| # Set to false if you don't run browser/E2E tests | |
| INSTALL_PLAYWRIGHT_DEPS=true | |
| # Install GitLab CLI (glab)? (true/false) | |
| INSTALL_GITLAB_CLI=true | |
| # Install GitHub CLI (gh)? (true/false) | |
| INSTALL_GITHUB_CLI=true | |
| # File descriptor limits (important for database connections, browser testing) | |
| # Default Linux limit of 1024 is too low for CI workloads | |
| FILE_DESCRIPTOR_LIMIT=65536 | |
| # ============================================================================= | |
| # END CONFIGURATION - No need to modify below this line | |
| # ============================================================================= | |
| set -euo pipefail | |
| # Colors for output | |
| RED='\033[0;31m' | |
| GREEN='\033[0;32m' | |
| YELLOW='\033[1;33m' | |
| BLUE='\033[0;34m' | |
| NC='\033[0m' # No Color | |
| log_info() { echo -e "${GREEN}[INFO]${NC} $1"; } | |
| log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } | |
| log_error() { echo -e "${RED}[ERROR]${NC} $1"; } | |
| log_step() { echo -e "${BLUE}[STEP]${NC} $1"; } | |
| # Check if running as root or with sudo | |
| if [[ $EUID -ne 0 ]]; then | |
| log_error "This script must be run as root or with sudo" | |
| exit 1 | |
| fi | |
| echo "" | |
| echo "==============================================" | |
| echo " Self-Hosted CI Runner Setup" | |
| echo " GitHub Actions + GitLab CI" | |
| echo "==============================================" | |
| echo "" | |
| log_info "Starting CI Runner setup..." | |
| log_info "This will take 5-10 minutes depending on your connection speed." | |
| echo "" | |
| # ============================================================================= | |
| # 1. System Update | |
| # ============================================================================= | |
| log_step "1/14 - Updating system packages..." | |
| export DEBIAN_FRONTEND=noninteractive | |
| apt-get update -qq | |
| apt-get upgrade -y -qq | |
| # ============================================================================= | |
| # 2. Install Base Build Tools | |
| # ============================================================================= | |
| log_step "2/14 - Installing base build tools..." | |
| apt-get install -y -qq \ | |
| build-essential \ | |
| curl \ | |
| wget \ | |
| git \ | |
| jq \ | |
| unzip \ | |
| ca-certificates \ | |
| gnupg \ | |
| lsb-release \ | |
| software-properties-common | |
| # ============================================================================= | |
| # 3. Install Docker | |
| # ============================================================================= | |
| log_step "3/14 - Installing Docker..." | |
| apt-get install -y -qq docker.io | |
| systemctl enable docker | |
| systemctl start docker | |
| # Add current user to docker group (if not root) | |
| if [ -n "${SUDO_USER:-}" ]; then | |
| usermod -aG docker "$SUDO_USER" | |
| log_info "Added $SUDO_USER to docker group" | |
| fi | |
| # ============================================================================= | |
| # 4. Install Docker Compose V2 Plugin | |
| # ============================================================================= | |
| log_step "4/14 - Installing Docker Compose V2 plugin..." | |
| # Ubuntu's docker.io package doesn't include the Compose plugin. | |
| # Many CI workflows use 'docker compose' (V2 syntax) which requires the plugin. | |
| # Without it, you'll get: "unknown shorthand flag: 'f' in -f" | |
| DOCKER_COMPOSE_URL="https://github.com/docker/compose/releases/latest/download/docker-compose-linux-x86_64" | |
| DOCKER_PLUGINS_DIR="/usr/local/lib/docker/cli-plugins" | |
| mkdir -p "$DOCKER_PLUGINS_DIR" | |
| curl -SL "$DOCKER_COMPOSE_URL" -o "$DOCKER_PLUGINS_DIR/docker-compose" | |
| chmod +x "$DOCKER_PLUGINS_DIR/docker-compose" | |
| # Verify installation | |
| if docker compose version &>/dev/null; then | |
| log_info "Docker Compose V2 installed: $(docker compose version --short)" | |
| else | |
| log_error "Docker Compose V2 installation failed" | |
| exit 1 | |
| fi | |
| # ============================================================================= | |
| # 5. Install GitHub CLI (gh) | |
| # ============================================================================= | |
| if [ "$INSTALL_GITHUB_CLI" = true ]; then | |
| log_step "5/14 - Installing GitHub CLI..." | |
| curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg 2>/dev/null | |
| chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg | |
| echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | tee /etc/apt/sources.list.d/github-cli.list > /dev/null | |
| apt-get update -qq | |
| apt-get install -y -qq gh | |
| else | |
| log_step "5/14 - Skipping GitHub CLI (disabled in config)" | |
| fi | |
| # ============================================================================= | |
| # 6. Install GitLab CLI (glab) | |
| # ============================================================================= | |
| if [ "$INSTALL_GITLAB_CLI" = true ]; then | |
| log_step "6/14 - Installing GitLab CLI..." | |
| snap install glab 2>/dev/null || log_warn "Could not install glab via snap" | |
| else | |
| log_step "6/14 - Skipping GitLab CLI (disabled in config)" | |
| fi | |
| # ============================================================================= | |
| # 7. Install Playwright/Browser Testing Dependencies | |
| # ============================================================================= | |
| if [ "$INSTALL_PLAYWRIGHT_DEPS" = true ]; then | |
| log_step "7/14 - Installing Playwright browser dependencies..." | |
| apt-get install -y -qq --no-install-recommends \ | |
| libasound2t64 \ | |
| libatk-bridge2.0-0t64 \ | |
| libatk1.0-0t64 \ | |
| libatspi2.0-0t64 \ | |
| libcairo2 \ | |
| libcups2t64 \ | |
| libdbus-1-3 \ | |
| libdrm2 \ | |
| libgbm1 \ | |
| libgbm-dev \ | |
| libglib2.0-0t64 \ | |
| libgtk-3-0t64 \ | |
| libgtk2.0-0t64 \ | |
| libnotify-dev \ | |
| libnspr4 \ | |
| libnss3 \ | |
| libpango-1.0-0 \ | |
| libx11-6 \ | |
| libxcb1 \ | |
| libxcomposite1 \ | |
| libxdamage1 \ | |
| libxext6 \ | |
| libxfixes3 \ | |
| libxkbcommon0 \ | |
| libxrandr2 \ | |
| libxss1 \ | |
| libxtst6 \ | |
| xauth \ | |
| xvfb \ | |
| fonts-freefont-ttf \ | |
| fonts-ipafont-gothic \ | |
| fonts-liberation \ | |
| fonts-noto-color-emoji \ | |
| fonts-tlwg-loma-otf \ | |
| fonts-unifont \ | |
| fonts-wqy-zenhei \ | |
| libfontconfig1 \ | |
| libfreetype6 \ | |
| xfonts-cyrillic \ | |
| xfonts-scalable | |
| else | |
| log_step "7/14 - Skipping Playwright dependencies (disabled in config)" | |
| fi | |
| # ============================================================================= | |
| # 8. Install GitHub Actions Runner | |
| # ============================================================================= | |
| log_step "8/14 - Installing GitHub Actions Runner v${ACTIONS_RUNNER_VERSION}..." | |
| mkdir -p /opt/actions-runner | |
| cd /opt/actions-runner | |
| curl -sL -o actions-runner-linux-x64-${ACTIONS_RUNNER_VERSION}.tar.gz \ | |
| https://github.com/actions/runner/releases/download/v${ACTIONS_RUNNER_VERSION}/actions-runner-linux-x64-${ACTIONS_RUNNER_VERSION}.tar.gz | |
| tar xzf ./actions-runner-linux-x64-${ACTIONS_RUNNER_VERSION}.tar.gz | |
| rm -f ./actions-runner-linux-x64-${ACTIONS_RUNNER_VERSION}.tar.gz | |
| # Set ownership if running via sudo | |
| if [ -n "${SUDO_USER:-}" ]; then | |
| chown -R "$SUDO_USER":"$SUDO_USER" /opt/actions-runner | |
| fi | |
| # ============================================================================= | |
| # 9. Install GitLab Runner | |
| # ============================================================================= | |
| log_step "9/14 - Installing GitLab Runner..." | |
| curl -sL https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh | bash | |
| apt-get install -y -qq gitlab-runner | |
| # ============================================================================= | |
| # 10. Configure Journal Log Limits | |
| # ============================================================================= | |
| log_step "10/14 - Configuring systemd journal limits..." | |
| mkdir -p /etc/systemd/journald.conf.d | |
| cat > /etc/systemd/journald.conf.d/size-limit.conf << EOF | |
| [Journal] | |
| SystemMaxUse=${JOURNAL_MAX_SIZE} | |
| SystemKeepFree=1G | |
| MaxRetentionSec=${JOURNAL_MAX_AGE} | |
| EOF | |
| systemctl restart systemd-journald | |
| # ============================================================================= | |
| # 11. Enable Unattended Security Updates | |
| # ============================================================================= | |
| log_step "11/14 - Enabling unattended security updates..." | |
| apt-get install -y -qq unattended-upgrades apt-listchanges | |
| cat > /etc/apt/apt.conf.d/20auto-upgrades << 'EOF' | |
| APT::Periodic::Update-Package-Lists "1"; | |
| APT::Periodic::Unattended-Upgrade "1"; | |
| APT::Periodic::AutocleanInterval "7"; | |
| EOF | |
| cat > /etc/apt/apt.conf.d/50unattended-upgrades << 'EOF' | |
| Unattended-Upgrade::Allowed-Origins { | |
| "${distro_id}:${distro_codename}"; | |
| "${distro_id}:${distro_codename}-security"; | |
| "${distro_id}ESMApps:${distro_codename}-apps-security"; | |
| "${distro_id}ESM:${distro_codename}-infra-security"; | |
| }; | |
| Unattended-Upgrade::AutoFixInterruptedDpkg "true"; | |
| Unattended-Upgrade::Remove-Unused-Kernel-Packages "true"; | |
| Unattended-Upgrade::Remove-Unused-Dependencies "true"; | |
| Unattended-Upgrade::Automatic-Reboot "false"; | |
| EOF | |
| systemctl enable unattended-upgrades | |
| # ============================================================================= | |
| # 12. Setup Swap File | |
| # ============================================================================= | |
| log_step "12/14 - Setting up swap file..." | |
| SWAP_FILE="/swapfile" | |
| if [ ! -f "$SWAP_FILE" ]; then | |
| fallocate -l $SWAP_SIZE $SWAP_FILE | |
| chmod 600 $SWAP_FILE | |
| mkswap $SWAP_FILE | |
| swapon $SWAP_FILE | |
| echo "$SWAP_FILE none swap sw 0 0" >> /etc/fstab | |
| log_info "Created ${SWAP_SIZE} swap file" | |
| else | |
| log_info "Swap file already exists, skipping" | |
| fi | |
| # Set swappiness | |
| sysctl vm.swappiness=${SWAPPINESS} | |
| grep -q "vm.swappiness" /etc/sysctl.conf || echo "vm.swappiness=${SWAPPINESS}" >> /etc/sysctl.conf | |
| # ============================================================================= | |
| # 13. Configure File Descriptor Limits | |
| # ============================================================================= | |
| log_step "13/14 - Configuring file descriptor limits..." | |
| # Default Linux limit of 1024 is too low for CI workloads with: | |
| # - Database connections (MongoDB, PostgreSQL, Redis) | |
| # - Browser testing (Cypress, Playwright) | |
| # - Node.js servers (Next.js, Express) | |
| # - Multiple parallel processes | |
| # When limit is hit, servers hang without error messages | |
| # Add to /etc/security/limits.conf | |
| if ! grep -q "# CI Runner file descriptor limits" /etc/security/limits.conf 2>/dev/null; then | |
| cat >> /etc/security/limits.conf << EOF | |
| # CI Runner file descriptor limits - added by setup-ci-runner.sh | |
| * soft nofile ${FILE_DESCRIPTOR_LIMIT} | |
| * hard nofile ${FILE_DESCRIPTOR_LIMIT} | |
| * soft nproc ${FILE_DESCRIPTOR_LIMIT} | |
| * hard nproc ${FILE_DESCRIPTOR_LIMIT} | |
| runner soft nofile ${FILE_DESCRIPTOR_LIMIT} | |
| runner hard nofile ${FILE_DESCRIPTOR_LIMIT} | |
| runner soft nproc ${FILE_DESCRIPTOR_LIMIT} | |
| runner hard nproc ${FILE_DESCRIPTOR_LIMIT} | |
| EOF | |
| log_info "Added file descriptor limits to /etc/security/limits.conf" | |
| else | |
| log_info "File descriptor limits already configured" | |
| fi | |
| # ============================================================================= | |
| # 14. Setup Automated Cleanup | |
| # ============================================================================= | |
| log_step "14/14 - Setting up automated cleanup..." | |
| # Create the comprehensive cleanup script | |
| cat > /opt/ci-runner-cleanup.sh << CLEANUP_SCRIPT | |
| #!/bin/bash | |
| # | |
| # CI Runner Cleanup Script | |
| # Auto-generated by setup-ci-runner.sh | |
| # Runs daily to prevent disk space issues | |
| # | |
| LOG_FILE="/var/log/ci-runner-cleanup.log" | |
| exec >> "\$LOG_FILE" 2>&1 | |
| echo "==========================================" | |
| echo "CI Runner cleanup started at \$(date)" | |
| echo "==========================================" | |
| echo "" | |
| echo ">>> Disk usage BEFORE cleanup:" | |
| df -h / | tail -1 | |
| # Docker Cleanup | |
| echo "" | |
| echo ">>> Docker cleanup..." | |
| docker container prune -f --filter "until=24h" 2>/dev/null || true | |
| docker image prune -f 2>/dev/null || true | |
| docker image prune -af --filter "until=${DOCKER_IMAGE_RETENTION_HOURS}h" 2>/dev/null || true | |
| docker volume prune -f 2>/dev/null || true | |
| docker network prune -f 2>/dev/null || true | |
| docker builder prune -f --filter "until=${DOCKER_IMAGE_RETENTION_HOURS}h" 2>/dev/null || true | |
| # Temp Files Cleanup | |
| echo "" | |
| echo ">>> Temp files cleanup..." | |
| find /tmp -type f -atime +${TEMP_FILE_RETENTION_DAYS} -delete 2>/dev/null || true | |
| find /var/tmp -type f -atime +${TEMP_FILE_RETENTION_DAYS} -delete 2>/dev/null || true | |
| rm -rf /root/.npm/_cacache/* 2>/dev/null || true | |
| find /root/.cache -type f -atime +14 -delete 2>/dev/null || true | |
| # GitHub Actions workspace | |
| echo "" | |
| echo ">>> GitHub Actions workspace cleanup..." | |
| if [ -d "/opt/actions-runner/_work" ]; then | |
| find "/opt/actions-runner/_work" -type d -name "_temp" -mtime +3 -exec rm -rf {} + 2>/dev/null || true | |
| find "/opt/actions-runner/_work/_tool" -mindepth 2 -maxdepth 2 -type d -mtime +14 -exec rm -rf {} + 2>/dev/null || true | |
| echo "Actions workspace cleaned" | |
| fi | |
| # GitLab Runner builds | |
| echo "" | |
| echo ">>> GitLab Runner builds cleanup..." | |
| if [ -d "/home/gitlab-runner/builds" ]; then | |
| find "/home/gitlab-runner/builds" -mindepth 2 -maxdepth 2 -type d -mtime +7 -exec rm -rf {} + 2>/dev/null || true | |
| echo "GitLab builds cleaned" | |
| fi | |
| # Old logs | |
| echo "" | |
| echo ">>> Old logs cleanup..." | |
| find /var/log -name "*.log" -size +100M -exec sh -c 'tail -1000 "\$1" > "\$1.tmp" && mv "\$1.tmp" "\$1"' _ {} \; 2>/dev/null || true | |
| find /var/log -name "*.gz" -mtime +30 -delete 2>/dev/null || true | |
| find /var/log -name "*.old" -mtime +7 -delete 2>/dev/null || true | |
| # Disk alert | |
| echo "" | |
| echo ">>> Checking disk space..." | |
| DISK_USAGE=\$(df / | tail -1 | awk '{print \$5}' | tr -d '%') | |
| if [ "\$DISK_USAGE" -gt ${DISK_ALERT_THRESHOLD} ]; then | |
| echo "!!! WARNING: Disk usage is \${DISK_USAGE}% (threshold: ${DISK_ALERT_THRESHOLD}%) !!!" | |
| logger -t ci-runner-cleanup -p user.warning "CI Runner disk usage: \${DISK_USAGE}%" | |
| else | |
| echo "Disk usage OK: \${DISK_USAGE}%" | |
| fi | |
| echo "" | |
| echo ">>> Disk usage AFTER cleanup:" | |
| df -h / | tail -1 | |
| echo "" | |
| echo "CI Runner cleanup completed at \$(date)" | |
| echo "==========================================" | |
| CLEANUP_SCRIPT | |
| chmod +x /opt/ci-runner-cleanup.sh | |
| # Create cron job | |
| cat > /etc/cron.d/ci-runner-cleanup << EOF | |
| # CI Runner maintenance - auto-generated | |
| ${CLEANUP_SCHEDULE} root /opt/ci-runner-cleanup.sh | |
| EOF | |
| chmod 644 /etc/cron.d/ci-runner-cleanup | |
| # ============================================================================= | |
| # Cleanup APT | |
| # ============================================================================= | |
| log_info "Cleaning up..." | |
| apt-get autoremove -y -qq | |
| apt-get clean -qq | |
| # ============================================================================= | |
| # Summary | |
| # ============================================================================= | |
| echo "" | |
| echo "==============================================" | |
| echo -e "${GREEN} CI Runner Setup Complete!${NC}" | |
| echo "==============================================" | |
| echo "" | |
| echo "Installed components:" | |
| echo " - Docker: $(docker --version 2>/dev/null | cut -d' ' -f3 | tr -d ',')" | |
| echo " - Docker Compose: $(docker compose version --short 2>/dev/null || echo 'Not installed')" | |
| if [ "$INSTALL_GITHUB_CLI" = true ]; then | |
| echo " - GitHub CLI (gh): $(gh --version 2>/dev/null | head -1 | cut -d' ' -f3)" | |
| fi | |
| if [ "$INSTALL_GITLAB_CLI" = true ]; then | |
| echo " - GitLab CLI (glab): $(glab --version 2>/dev/null | head -1 | awk '{print $2}')" | |
| fi | |
| echo " - GitLab Runner: $(gitlab-runner --version 2>&1 | grep Version | awk '{print $2}')" | |
| echo " - Actions Runner: ${ACTIONS_RUNNER_VERSION}" | |
| if [ "$INSTALL_PLAYWRIGHT_DEPS" = true ]; then | |
| echo " - Playwright deps: Installed" | |
| fi | |
| echo "" | |
| echo "System hygiene:" | |
| echo " - Journal logs: Max ${JOURNAL_MAX_SIZE}, ${JOURNAL_MAX_AGE} retention" | |
| echo " - Security updates: Unattended-upgrades enabled" | |
| echo " - Swap: ${SWAP_SIZE}, swappiness=${SWAPPINESS}" | |
| echo " - File descriptors: ${FILE_DESCRIPTOR_LIMIT} (nofile + nproc)" | |
| echo " - Cleanup cron: ${CLEANUP_SCHEDULE}" | |
| echo " - Disk alert: >${DISK_ALERT_THRESHOLD}% triggers warning" | |
| echo "" | |
| echo "----------------------------------------------" | |
| echo "NEXT STEPS" | |
| echo "----------------------------------------------" | |
| echo "" | |
| echo "1. Register GitHub Actions Runner:" | |
| echo " cd /opt/actions-runner" | |
| echo " ./config.sh --url https://github.com/YOUR_ORG --token YOUR_TOKEN" | |
| echo " sudo ./svc.sh install" | |
| echo " sudo ./svc.sh start" | |
| echo "" | |
| echo "2. Register GitLab Runner:" | |
| echo " sudo gitlab-runner register" | |
| echo " # URL: https://gitlab.com (or your instance)" | |
| echo " # Token: from GitLab Settings > CI/CD > Runners" | |
| echo " # Executor: docker" | |
| echo " # Default image: node:20" | |
| echo "" | |
| echo "3. (Optional) Reboot to apply all changes:" | |
| echo " sudo reboot" | |
| echo "" | |
| echo "----------------------------------------------" | |
| echo "Logs: /var/log/ci-runner-cleanup.log" | |
| echo "Script: /opt/ci-runner-cleanup.sh (run manually to test)" | |
| echo "----------------------------------------------" | |
| echo "" | |
| echo "Happy shipping! - Luminary Lane" | |
| echo "https://luminarylane.app" | |
| echo "" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment