GitHub Actions runners
Coolify can run the GitHub Actions workflow jobs of a GitHub organization on your build servers. Each job runs in a new runner container. Coolify deletes the container after the job.
GitHub Actions runners are in beta. The settings and the behavior can change in later versions.
The runners run on your own servers, on self-hosted Coolify and on Coolify Cloud. Coolify never runs them on the server that runs Coolify itself.
How it works
- A workflow job asks for
runs-on: [self-hosted, <your label>]. - GitHub sends a Workflow job webhook event to Coolify through your GitHub App.
- Coolify finds an enabled build server whose labels match the job and that has free capacity. It selects the least busy server.
- Coolify starts an ephemeral runner container on that server and registers it with GitHub.
- The runner takes one job. When the job completes, Coolify deletes the container, its network, and its volumes.
When all runners are busy, the job waits in the Coolify queue until a runner is free. When a runner cannot start, Coolify removes it and tries again, up to 3 times. Refer to Monitor runners.
In the Docker (privileged, full host access) mode, each job gets a privileged Docker daemon. A malicious workflow can take control of the build server. Use Isolated Docker (Sysbox) or No Docker to keep jobs away from the server. Coolify creates a runner group that is limited to private repositories. Do not use these runners for repositories that accept code from untrusted contributors.
What you need
Before you start, make sure you have:
- a server with the Builds only role. Refer to Build servers.
- a GitHub App source in Coolify that belongs to a GitHub organization. Runners are registered at organization level, so GitHub Apps of personal accounts cannot run workflow jobs.
- a Coolify instance that GitHub can send webhook events to.
- outbound internet access from the build server to
github.com,ghcr.io(runner image), and Docker Hub (Docker sidecar image).
Set up the GitHub App
The GitHub App needs these permissions and events:
| Type | Name | Access |
|---|---|---|
| Organization permission | Self-hosted runners | Write |
| Repository permission | Actions | Read |
| Webhook event | Workflow job | - |
Create the source
- Open Sources in the Coolify sidebar.
- Select + Add to create a source.
- Enter the Name and the Organization.
- In Use this App for, select GitHub Actions runners.
- Select Continue.
The Organization field is required when you select GitHub Actions runners.
Register the App on GitHub
- On the next page, make sure that GitHub Actions runners is set to Run workflow jobs on build servers.
- Select Register with GitHub.
- Complete the registration and install the App in your organization.
Coolify adds the required permissions and the Workflow job webhook event to the App.
For the full registration flow, refer to Set up a GitHub App.
Configure runners on a build server
Enable the runners
- Open Servers in the Coolify sidebar and select the server.
- Open GitHub Runners.
- Select Enable runners.
Coolify saves the default settings and shows the runner settings. If the server does not have the Builds only role, the page shows This server is not enabled for builds. Change the role in the General settings of the server first.
Set the runner settings
| Setting | Description |
|---|---|
| GitHub App | The organization GitHub App that receives the Workflow job events. Coolify selects the first App that has all the required permissions. |
| Labels | Comma-separated custom labels, for example coolify. Coolify also registers self-hosted and linux. |
| Application builds | Also build applications, or Dedicated to runners. A dedicated server is not used for application builds while its runners are enabled. |
Pull request jobs defaults to Refuse pull request jobs. Jobs started by pull requests, including pull_request_target and review events, are refused before a step runs. Choose Run pull request jobs only when your repository and organization approval policies permit it. The setting applies to runners started after you save; push, scheduled, and manual jobs are unaffected.
If Coolify shows The GitHub App is not ready, complete Set up the GitHub App. You can save the settings with an App that is not ready, but Coolify does not get jobs until the App has the required permissions.
Set the resources
| Setting | Default | Description |
|---|---|---|
| Parallel runners | 2 | The maximum number of runners on this server at the same time (1 to 32). |
| CPU limit | No limit | The number of CPUs for each runner, for example 2. |
| Memory limit | No limit | The memory for each runner, for example 4g. |
| Docker in jobs | Docker (privileged, full host access) | Refer to Docker in jobs. |
| Runner image | ghcr.io/actions/actions-runner:latest | Refer to Runner image. |
The CPU and memory limits apply to the runner container and to its Docker sidecar.
Set the timeouts
All values are in minutes.
| Setting | Default | Description |
|---|---|---|
| Queue wait | 60 | Coolify drops a job that waits longer for a free runner. |
| Idle runner | 10 | Coolify removes a runner that gets no job in this time. |
| Job | 360 | Coolify stops a job that runs longer. |
Save the settings
Select Save.
When the GitHub App has all the required permissions, Coolify creates a runner group named Coolify <app-uuid> in your organization. The group is limited to private repositories.
Organizations on the GitHub Free plan cannot create runner groups. In that case, Coolify uses the Default runner group and shows a warning. On GitHub, check which repositories can use the Default group.
You can configure runners on more than one build server. Coolify sends each job to the least busy server that matches the job labels.
Use the runners in a workflow
Add self-hosted and one of your custom labels to runs-on:
jobs:
build:
runs-on: [self-hosted, coolify]
steps:
- uses: actions/checkout@v4
- run: docker build -t my-app .Coolify takes a job only when:
- the job asks for at least one of your custom labels, and
- all labels of the job are registered by the runner (
self-hosted,linux, and your custom labels).
Jobs that ask only for generic labels, such as self-hosted, are left for other runners. This prevents Coolify from taking jobs that are for other self-hosted runners of your organization.
A custom label can contain letters, numbers, dots, dashes, and underscores. You cannot use self-hosted, linux, x64, arm64, arm, windows, or macos as the only label.
Docker in jobs
| Mode | Description |
|---|---|
| Docker (privileged, full host access) | Each runner gets its own Docker daemon in a privileged sidecar container. A job can get root access to the build server. Use this mode only for trusted repositories. |
| Isolated Docker (Sysbox) | Each runner gets its own Docker daemon in an unprivileged sidecar container that uses the Sysbox runtime. The root user in a job has no rights on the build server. The server must have Sysbox. Refer to Install Sysbox. |
| No Docker (isolated, no container actions) | Jobs run in an unprivileged container without Docker. |
What works in each mode:
| Workflow feature | Docker (privileged) | Isolated Docker (Sysbox) | No Docker |
|---|---|---|---|
| Shell steps, JavaScript actions, and composite actions | Yes | Yes | Yes |
docker commands | Yes | Yes | No |
Service containers (services:) | Yes | Yes | No |
Container jobs (container:) | Yes | Yes | No |
Docker container actions (uses: docker://... or actions with runs.using: docker) | Yes | Yes | No |
Coolify never shares the Docker socket of the host with a runner. Each runner has its own network and volumes.
Install Sysbox
When you select Isolated Docker (Sysbox), Coolify checks if the server has Sysbox. If Sysbox is not installed, select Install Sysbox. Coolify shows the installation logs.
The automatic installation needs:
- Debian or Ubuntu.
- The
amd64orarm64architecture. - Linux kernel 5.12 or newer.
During the installation, Coolify:
- Writes the current
bipanddefault-address-poolsvalues of Docker to/etc/docker/daemon.json. It keeps the other settings and saves a backup of the file as/etc/docker/daemon.json.before-sysbox. Without these values, the Sysbox package restarts Docker, or stops when containers exist. - Downloads the pinned Sysbox package from GitHub and checks its SHA-256 checksum.
- Installs the package and
fuse3. Docker reloads its configuration. Running containers are not restarted.
For other distributions, install Sysbox manually. Coolify detects it when the Sysbox services run and Docker lists the sysbox-runc runtime.
Sysbox has an open issue in which a host can stop responding. Coolify does not remove Sysbox from a server. To remove it, refer to the Sysbox uninstall instructions.
Runner image
By default, Coolify uses ghcr.io/actions/actions-runner:latest and pulls it each time it starts a runner, so the runner stays up to date. When the registry is not available, Coolify uses the image that is already on the server.
In Runner image, you can:
- pin a version, for example
ghcr.io/actions/actions-runner:2.337.0. - use a custom image based on the official runner image, to add tools.
GitHub stops sending jobs to runners that are more than 30 days behind the newest runner version. If you pin a version or use a custom image, update it regularly.
Monitor runners
The Recent runners section on the GitHub Runners page shows the queued jobs, the active runners, and their results. The list updates every 10 seconds.
| Status | Description |
|---|---|
| Queued | The job waits for a free runner. |
| Provisioning | Coolify starts the runner container. |
| Waiting for job | The runner is registered and waits for GitHub to give it a job. |
| Running | The runner runs the job. |
| Completed | The job completed and Coolify removed the runner. |
| Failed | Coolify could not start the runner after 3 attempts. The error message shows the cause. |
| Cancelled | The job ended before a runner started, the runner got no job, or a user cancelled it. |
| Timed out | The job waited or ran longer than the configured timeout. |
When a runner cannot start, Coolify removes it and puts the job back in the queue. It tries again after 30 seconds, and then after 60 seconds, possibly on another build server. While it waits, the row shows Attempt 1 of 3 failed or Attempt 2 of 3 failed with the cause.
After the last failed attempt, the job stays queued on GitHub until GitHub cancels it. Another runner with matching labels can still take it.
To stop an active runner, select Cancel on its row.
Disable runners
Select Disable runners to stop taking new jobs. Coolify removes the runners that wait for a job. Running jobs continue until they finish. Coolify keeps the settings and the execution history of the server.
To take jobs again, select Enable runners.
You cannot change the role of a build server while its runners are enabled. Disable the runners first.
Troubleshooting
| Problem | Solution |
|---|---|
| This server is not enabled for builds | Set the server role to Builds only in the General settings of the server. |
| The GitHub Runners menu does not show | Coolify does not run runners on the server that runs Coolify. Use another server. |
| No GitHub App shows in the settings | Add a GitHub App that belongs to an organization, and install it. |
| The GitHub App is not ready | Add the missing permissions or events on GitHub, then select Refetch on the Permissions page of the App. |
| Jobs stay in Queued on GitHub and Coolify shows nothing | Make sure that runs-on has one of your custom labels, and that all labels of the job are registered by the runner. Make sure that GitHub can send webhook events to Coolify. |
| Jobs stay in Queued in Coolify | All runners are busy. Increase Parallel runners or configure runners on more build servers. |
| A job fails at Initialize containers or at a Docker step | The job needs Docker. Select Docker (privileged, full host access) or Isolated Docker (Sysbox). |
| Install Sysbox fails | Make sure that the server runs Debian or Ubuntu on amd64 or arm64, with Linux kernel 5.12 or newer. Otherwise, install Sysbox manually. |
| Sysbox is not installed shows after a manual installation | Make sure that the sysbox-mgr and sysbox-fs services run, that /usr/bin/fusermount3 exists, and that docker info lists the sysbox-runc runtime. Select Install Sysbox to repair the installation on Debian or Ubuntu. |
| Runners show Failed with Could not start a runner after 3 attempts | Read the error message. For Isolated Docker, check the Sysbox services on the server. |
| GitHub does not send jobs to the runners | A pinned or custom Runner image can be too old. Use a newer runner version. |
| The job cannot find a tool | Use a custom Runner image based on the official runner image that includes the tool. |
