Study guide
7.2 Self-Hosted Runner Setup, Architecture & Communication
GitHub Actions Certification GH-200
Track your progress as you read
Finished sections get a check mark.
1 Chapter 1: Introduction & Exam Overview
1.1 Exam Structure, Format & Scoring 1.2 GitHub Actions Architecture & Core Mental Model 1.3 Hands-On Preparation & Exam Day Strategy
2 Chapter 2: Workflow Triggers & Event Architecture
2.1 Webhook & Code Events: push, pull_request, and pull_request_target 2.2 Scheduled & Manual Triggers: schedule, workflow_dispatch, and repository_dispatch 2.3 Release, Issue, and Dynamic Lifecycle Events 2.4 Branch, Tag, and Path Filtering Patterns
3 Chapter 3: Jobs, Matrix Strategies & Execution Control
3.1 Job Anatomy, Step Execution & Job Dependencies (needs) 3.2 Contexts, Expressions & Functions 3.3 Environment Variables & Workflow Commands 3.4 Matrix Strategies & Multi-Platform Builds 3.5 YAML Anchors, Aliases & Merge Keys
4 Chapter 4: Reusable Workflows & Troubleshooting
4.1 Authoring & Calling Reusable Workflows (workflow_call) 4.2 Comparing Reusable Workflows, Composite Actions & Starter Workflows 4.3 Troubleshooting Workflow Runs & Debug Logging 4.4 Concurrency Controls & Status Check Functions
5 Chapter 5: Authoring Custom Actions
5.1 Action Architecture & action.yml Specification 5.2 Authoring Composite Actions 5.3 Building JavaScript Actions 5.4 Building Docker Container Actions
6 Chapter 6: Action Distribution, Marketplace & Advanced Action Types
6.1 Action Versioning, Semantic Releases & Tagging 6.2 Publishing Actions to GitHub Marketplace 6.3 Service Containers & Network Topology 6.4 actions/github-script & Workflow Tooling
7 Chapter 7: Runner Infrastructure & Self-Hosted Runners
7.1 GitHub-Hosted Runners & Larger Runners 7.2 Self-Hosted Runner Setup, Architecture & Communication 7.3 Self-Hosted Runner Security & Ephemeral Runners 7.4 Runner Groups, Labels & Organization Routing
8 Chapter 8: Enterprise Governance, Policies & Environments
8.1 Enterprise & Organization Action Policies 8.2 Environments, Protection Rules & Deployment Approvals 8.3 Repository Rulesets, Required Status Checks & Governance 8.4 Usage Limits, Billing Multipliers & Usage Metrics
9 Chapter 9: Secrets, Permissions & OIDC Cloud Authentication
9.1 Encrypted Secrets Architecture & Scopes 9.2 GITHUB_TOKEN & Least Privilege Configuration 9.3 OpenID Connect (OIDC) & Workload Identity Federation 9.4 Script Injection Prevention & Secure Workflow Patterns
10 Chapter 10: Supply Chain Hardening & Performance Optimization
10.1 Supply Chain Hardening: SHA Pinning, Dependabot & Artifact Attestations 10.2 Caching Dependencies with `actions/cache` 10.3 Artifacts Management & Job Handoff 10.4 Workflow Performance, Cost Optimization & Architecture Review
7.2 Self-Hosted Runner Setup, Architecture & Communication
Key Takeaways Explain This Topic AI
Self-hosted runners communicate with GitHub exclusively via outbound HTTPS connections over port 443 using long polling and WebSockets, requiring zero inbound ports or public IP addresses.
Registration tokens are short-lived credentials valid for exactly 1 hour, used exclusively during ./config.sh initialization to exchange the token for long-lived cryptographic credentials stored in .runner and .credentials .
The actions-runner package is a cross-platform .NET Core application supporting Linux (x64, ARM64, ARM32), Windows (x64, ARM64), and macOS (x64, Apple Silicon).
Self-hosted runners can be registered at three hierarchical scopes: Repository level (isolated to one repo), Organization level (shared across org repos), and Enterprise level (shared across multiple orgs).
Production self-hosted runners should be installed and managed as continuous OS background daemons using the ./svc.sh wrapper script to integrate with systemd on Linux, launchd on macOS, or Windows Services.
Last updated: August 2026
Self-Hosted Runner Setup, Architecture & Communication
While GitHub-hosted runners offer maintenance-free execution, organizations often require dedicated compute environments to access on-premises databases, leverage custom hardware architectures (such as ARM64, custom GPUs, or Apple Silicon build farms), utilize persistent local caches, or avoid per-minute hosted billing. In these scenarios, organizations deploy self-hosted runners .
A self-hosted runner is a physical server, virtual machine, or containerized environment that you provision, secure, and maintain, on which you install the official GitHub Actions runner application. Mastering the communication architecture, token authentication lifecycle, and daemon management of self-hosted runners is critical for enterprise platform administration and the GH-200 examination.
1. Outbound HTTPS Communication Model
A common security misconception is that GitHub Actions requires an open inbound firewall port to dispatch jobs to on-premises self-hosted runners. In reality, the GitHub Actions runner architecture operates on an outbound-only communication model . +-----------------------------------------------------------------------------+
- | RUNNER POLLING & COMMUNICATION ARCHITECTURE |
- | |
- | +--------------------------+ +----------------------------+ |
- | | GitHub Control Plane | | Corporate Network | |
- | | (api.github.com & | | (On-Premises / VPC) | |
- | | Actions Message Bus) | | | |
- | +--------------------------+ +----------------------------+ |
- | ▲ │ |
- | │ │ |
- | │ 1. Outbound HTTPS (Port 443) Long Poll│ |
- | │ "Any jobs matching my labels?" │ |
- | ├─────────────────────────────────────────┤ |
- | │ ▼ |
- | │ 2. Job Dispatch Payload (HTTPS 443) +----------------+ |
- | │◄───────────────────────────────────────┤ Self-Hosted | |
- | │ | Runner Daemon | |
- | │ 3. Stream Logs & Status (HTTPS 443) | (Runner. | |
- | │◄───────────────────────────────────────┤ Listener) | |
- | +----------------+ |
- | [NO INBOUND PORTS OPEN] [OUTBOUND ONLY THROUGH NAT/PROXY]|
- +-----------------------------------------------------------------------------+
- Network Requirements
No Inbound Open Ports: The host machine running the runner daemon does not require any open inbound ports (port 80, 443, and 22 can remain completely closed to ingress traffic).
Outbound Protocol: All communication occurs over HTTPS (TCP port 443) or Secure WebSockets ( wss:// ).
Long Polling & Message Queue: The Runner.Listener process initiates an outbound HTTPS connection to GitHub's Actions Message Bus, maintaining an active long-poll session. When a workflow job is queued that matches the runner's labels, GitHub delivers the job assignment over the existing established outbound connection.
Proxy Support: In corporate environments where direct outbound internet access is restricted, the runner can be routed through an authenticating forward HTTP/HTTPS proxy by configuring .proxy or environment variables ( HTTP_PROXY , HTTPS_PROXY , and NO_PROXY ).
2. Registration Token Lifecycle & Authentication
To bind a self-hosted runner to a GitHub repository, organization, or enterprise, an administrator must generate a registration token . 1. Admin requests registration token via UI or API (Valid for 60 minutes)
- │
- ▼
- 2. Admin executes: ./config.sh --url <url> --token <registration-token>
- │
- ▼
- 3. Runner daemon exchanges temporary token with GitHub API
- Receives unique Runner ID
- Generates local RSA private/public keypair
- Saves long-lived session credentials into .runner and .credentials
- │
- ▼
- 4. Registration token expires; runner authenticates via saved RSA credentials
- Critical Token Rules
Short-Lived (1-Hour Expiration): Registration tokens generated via the GitHub Web UI or the REST API ( POST /repos/{owner}/{repo}/actions/runners/registration-token or /orgs/{org}/... ) are valid for exactly 60 minutes .
Exchange Mechanism: The registration token is used only once during the initial execution of ./config.sh . The runner daemon presents the token to GitHub, authenticates the registration, and receives a permanent cryptographic identity.
Local Credential Storage: The permanent credentials and configuration are written to hidden files in the runner directory ( .runner containing runner metadata and .credentials containing the cryptographic OAuth tokens/keys). Future daemon restarts use these local credentials directly without needing a new registration token.
Removal Tokens: To decommission a runner gracefully, an administrator generates a short-lived removal token via API/UI and executes ./config.sh remove --token <removal-token> .
3. Supported Operating Systems & Package Structure
The GitHub Actions self-hosted runner application ( actions-runner ) is an open-source .NET Core application supported across major operating systems and CPU architectures:
Linux: x64, ARM64 (e.g., AWS Graviton, Ampere), ARM32 (Raspberry Pi / embedded).
Windows: x64, ARM64 (Windows Server 2019/2022, Windows 10/11).
macOS: x64 (Intel), ARM64 (Apple Silicon M1/M2/M3/M4).
- Directory Layout of actions-runner/ actions-runner/
- ├── bin/ # Core .NET runner binaries (Runner.Listener, Runner.Worker)
- ├── externals/ # Embedded runtimes (Node.js versions used to run JavaScript actions)
- ├── _work/ # Workspace directory where repositories are cloned and jobs execute
- ├── .runner # Local runner configuration, agent ID, pool ID, and server URL
- ├── .credentials # Encrypted RSA keys and credentials for GitHub Actions control plane
- ├── .env # Custom environment variables injected into all workflow jobs
- ├── .path # Custom PATH entries prepended to $PATH for all jobs
- ├── config.sh / config.cmd # Configuration script for initial registration
- ├── run.sh / run.cmd # Interactive foreground execution script
- └── svc.sh / svc.cmd # System service management wrapper (systemd/launchd/WinService)
- 4. Runner Scopes: Repository, Organization & Enterprise
Self-Hosted runners can be registered at three distinct hierarchical levels, determining their visibility and job-sharing boundaries: +-----------------------------------------------------------------------------+
- | RUNNER SCOPE HIERARCHY |
- | |
- | [ENTERPRISE LEVEL] ─── Registered at Enterprise Account |
- | Shared across multiple Organizations |
- | |
- | [ORGANIZATION LEVEL]─── Registered at Organization Account |
- | Shared across multiple Repositories (via Groups) |
- | |
- | [REPOSITORY LEVEL] ─── Registered at Single Repository |
- | Strictly isolated; cannot be shared |
- +-----------------------------------------------------------------------------+
Scope Level Registration Target Best Use Case Governance & Access
Enterprise https://github.com/enterprises/my-corp Shared centralized compute infrastructure across business units. Managed by enterprise administrators; assigned to organizations via Enterprise Runner Groups.
Organization https://github.com/my-org Standard enterprise microservices and shared team CI pools. Managed by org owners; assigned to repositories via Organization Runner Groups.
Repository https://github.com/my-org/my-repo Specialized legacy build machines, dedicated hardware testbeds. Bound exclusively to the single repository; cannot be accessed by other repos.
Loading diagram... Self-Hosted Runner Registration, Service Daemonization, and Polling Architecture
5. Automated Installation & Service Daemonization ( svc.sh )
Running a self-hosted runner interactively in a terminal via ./run.sh is acceptable for initial testing, but production environments require the runner to operate as a continuous background daemon that survives host reboots and restarts automatically upon failure.
The GitHub Actions runner package includes the svc.sh script (on Linux/macOS) and svc.cmd (on Windows) to manage native operating system services.
- Automated Production Setup Script (Ubuntu Linux / systemd) #!/usr/bin/env bash
- set -euo pipefail
- # 1. Create dedicated non-root runner user
- sudo useradd -m -s /bin/bash actions-runner
- sudo usermod -aG docker actions-runner || true
- # 2. Prepare installation directory
- sudo mkdir -p /opt/actions-runner && cd /opt/actions-runner
- sudo chown -R actions-runner:actions-runner /opt/actions-runner
- # 3. Download official runner package and verify SHA-256 checksum
- RUNNER_VERSION="2.317.0"
- RUNNER_TAR="actions-runner-linux-x64-${RUNNER_VERSION}.tar.gz"
- EXPECTED_HASH="9e883d3f0ee374fbd34e02f82c8e496dc53f5d752b81763761ecda10d62df13e"
- sudo -u actions-runner curl -o "${RUNNER_TAR}" -L \
- "https://github.com/actions/runner/releases/download/v${RUNNER_VERSION}/${RUNNER_TAR}"
- echo "${EXPECTED_HASH} ${RUNNER_TAR}" | shasum -a 256 -c
- sudo -u actions-runner tar xzf "${RUNNER_TAR}"
- # 4. Install OS-level dependencies
- sudo ./bin/installdependencies.sh
- # 5. Execute unattended registration (Using 1-hour registration token)
- REG_TOKEN="AB12CD34EF56GH78IJ90KLMN"
- ORG_URL="https://github.com/my-enterprise-org"
- sudo -u actions-runner ./config.sh \
- -url "${ORG_URL}" \
- -token "${REG_TOKEN}" \
- -name "linux-prod-runner-01" \
- -runnergroup "production-pool" \
- -labels "self-hosted,linux,x64,gpu,nvme-storage" \
- -work "_work" \
- -unattended \
- -replace
- # 6. Install and start native systemd background service
- sudo ./svc.sh install actions-runner
- sudo ./svc.sh start
- # 7. Check service status
- sudo ./svc.sh status
- svc.sh Service Command Reference
./svc.sh install [user] : Generates a systemd service file (e.g., /etc/systemd/system/actions.runner.<owner>.<name>.service ) configured to run under the specified user account.
./svc.sh start : Starts the registered systemd service immediately.
./svc.sh status : Checks current execution state and PID of the running service daemon.
./svc.sh stop : Gracefully stops the runner service (finishes current job before terminating).
./svc.sh uninstall : Removes the service configuration from systemd.