DEV Community

Cover image for How to Set Up a GitHub Actions Self-Hosted Runner on macOS 15+
Tanja Bayer for Cubesoft GmbH

Posted on • Originally published at nocodo.ai

How to Set Up a GitHub Actions Self-Hosted Runner on macOS 15+

Migrating to GitHub offers numerous advantages, but it also presents opportunities to optimize your workflow environment. In our journey, we aimed to reduce operational costs without sacrificing the flexibility required for our continuous integration and deployment (CI/CD) processes. By setting up self-hosted runners on macOS 15+, we gained control over our build environment while managing expenses effectively. This guide will walk you through the steps we took, the challenges we faced, and how you can implement a similar setup.

Introduction

In an effort to optimize costs while maintaining the flexibility of our CI/CD pipelines, we decided to set up self-hosted runners on macOS after migrating from Bitbucket to GitHub. Self-hosted runners allow us to use our own infrastructure (using all the idle capacity of our powerful developer MacBooks) for running GitHub Actions workflows, which can lead to significant cost savings, especially when dealing with resource-intensive tasks or macOS-specific builds.
However, the process wasn't without its hurdles. We encountered several challenges, particularly with setting up the runners as services on macOS 15+. This guide aims to help you navigate these challenges and set up your own self-hosted runners efficiently.

General Setup of a Self-Hosted Runner

Setting up a self-hosted runner involves adding the runner to your GitHub organization and configuring it on your macOS machine.

Adding a Self-Hosted Runner to Your Organization

  1. Navigate to Your Organization on GitHub:
  • Go to the main page of your GitHub organization.
  • Under your organization name, click on Settings.
  1. Access Runners Settings:
    • In the left sidebar, click Actions.
    • Then, click on Runners.
  2. Add a New Runner:
    • Click New runner, then select New self-hosted runner.
  3. Choose Operating System and Architecture:
    • Select macOS as the operating system.
    • Choose the appropriate architecture (usually x64 ).
  4. Follow Setup Instructions:
    • GitHub will provide you with a series of shell commands.
    • Open a terminal on your macOS machine.
    • Run each command in order to download and configure the runner application.

Verifying the Runner

After completing the setup:

  • Ensure the runner is listed under Runners in your organization's settings.
  • The terminal should display:
  • Code kopieren
  • √ Connected to GitHub [Timestamp]: Listening for Jobs This means your runner is active and ready to accept jobs.

Configuring the Runner as a Service on macOS 15+

Running the self-hosted runner as a service ensures it starts automatically and runs in the background.

Installing the Service

Stop the Runner Application:

If the runner is currently running, stop it by pressing Ctrl + C in the terminal.

Install the Service

Navigate to your runner's directory in the terminal.
Run the following command:

./svc.sh install
Enter fullscreen mode Exit fullscreen mode

Starting the Service

Start the service with:

./svc.sh start
Enter fullscreen mode Exit fullscreen mode

Checking the Service Status

Check if the service is running correctly:

./svc.sh status
Enter fullscreen mode Exit fullscreen mode

Stopping and Uninstalling the Service

Stop the Service

./svc.sh stop
Enter fullscreen mode Exit fullscreen mode

Uninstall the Service

./svc.sh uninstall
Enter fullscreen mode Exit fullscreen mode

Prioritizing Self-Hosted Runners in Workflows

To optimize resource usage, you can configure your workflows to prioritize self-hosted runners but fall back to GitHub-hosted runners if none are available.
Modifying Your Workflow YAML
Add the following jobs to your workflow file:

jobs:
  check-runner:
    runs-on: ubuntu-latest
    outputs:
      runner-label: ${{ steps.set-runner.outputs.runner-label }}
    env:
      GH_TOKEN: ${{ secrets.ORG_RUNNER_STATUS_ACCESS_TOKEN }}
    steps:
      - name: Set runner
        id: set-runner
        run: |
          runners=$(gh api -H "Accept: application/vnd.github+json" /orgs/${{ github.repository_owner }}/actions/runners)
          available=$(echo "$runners" | jq '.runners[] | select(.status == "online" and .busy == false and .labels[] .name == "self-hosted")')
          if [ -n "$available" ]; then
            echo "runner-label=self-hosted" >> $GITHUB_OUTPUT
          else
            echo "runner-label=ubuntu-latest" >> $GITHUB_OUTPUT
          fi
  your-job:
    needs: check-runner
    runs-on: ${{ needs.check-runner.outputs.runner-label }}
    steps:
      # Your job steps here
Enter fullscreen mode Exit fullscreen mode

Explanation

Check-Runner Job

Checks if any self-hosted runners are online and not busy. Sets runner-label to self-hosted if available, otherwise ubuntu-latest .

Your-Job :

Specifies runs-on dynamically based on runner-label . Ensures your job uses a self-hosted runner if available.

Setting Up Organization Secrets

Create an Access Token :

Generate a Personal Access Token (PAT) with read access to organization self hosted runners : Github Settings . This token is used to authenticate GitHub CLI commands in your workflow.

Add the Token to Organization Secrets :

Go to your organization settings on GitHub. Navigate to Secrets and variables > Actions > New organization secret . Name it ORG_RUNNER_STATUS_ACCESS_TOKEN and paste your PAT.

Common Pitfalls and Solutions

During our setup, we faced several issues. Here's how to solve them.

1. Permission Issues with Installing the Service

Problem:

Running ./svc.sh install fails due to permission issues with LaunchAgents.

Solution:

Grant read/write permissions to your user for the LaunchAgents directory:

sudo chown -R $(whoami) ~/Library/LaunchAgents/
Enter fullscreen mode Exit fullscreen mode

2. Runner Not Showing as "Online"

Problem :

The runner remains offline, and the stderr.log file shows:

shell-init: error retrieving current directory: getcwd: cannot access parent directories: Operation not permitted /bin/bash: /path/to/actions-runner/runsvc.sh: Operation not permitted
Enter fullscreen mode Exit fullscreen mode

Solution :

Grant Full Disk Access to Bash :

  • Open System Preferences > Security & Privacy > Privacy tab.
  • Scroll down and select Full Disk Access .
  • Click the lock icon to make changes and authenticate.
  • Click the + button to add an application.
  • Press Command + Shift + . to reveal hidden folders.
  • Navigate to /bin and select bash . Reinstall the Service : Stop and uninstall the service:
./svc.sh stop 
./svc.sh uninstall
Enter fullscreen mode Exit fullscreen mode

Reinstall and start the service:

./svc.sh install 
./svc.sh start
Enter fullscreen mode Exit fullscreen mode

Conclusion

By setting up self-hosted runners on macOS 15+, we achieved significant cost savings without compromising on the flexibility of our CI/CD pipelines. This hybrid approach allows us to utilize our own infrastructure when available and seamlessly fall back to GitHub-hosted runners when necessary.

Key takeaways:

  • Cost Optimization : Self-hosted runners reduce reliance on paid GitHub-hosted runners, lowering operational costs.
  • Flexibility : Maintaining the ability to run workflows on GitHub-hosted runners ensures builds are not stalled due to unavailable resources.
  • Control Over Environment : Self-hosted runners provide full control over the software and hardware environment.

Top comments (0)