# GitHub Actions runners with Terraform

When a build needs a specific Linux setup, you can give GitHub Actions a machine with the CPU, memory, and tools you choose. GitHub sends the job to a runner process on that machine.

This recipe uses the [Dedalus Terraform provider](https://registry.terraform.io/providers/dedalus-labs/dedalus/latest/docs) to create the machine and register its runner. A separate GitHub-hosted job deletes the machine afterward, so cleanup can finish even after the runner is gone.

The [example repository](https://github.com/dedalus-labs/cookbook/tree/main/examples/github-actions-runner) contains the Terraform configuration, runner setup, and workflow. Its first job prints the machine's operating system and filesystem information. Replace those steps with your build once you have verified the full run.

## Set up your repository

Fork [dedalus-labs/cookbook](https://github.com/dedalus-labs/cookbook), enable Actions in your fork, and clone it. Install Terraform 1.5 or later, Go, `make`, `jq`, and the GitHub CLI. Authenticate `gh` with administrator access to your fork.

```bash
git clone https://github.com/YOUR_ACCOUNT/cookbook.git
cd cookbook/examples/github-actions-runner
export TF_VAR_github_repo=YOUR_ACCOUNT/cookbook
export DEDALUS_BASE_URL=https://dcs.dedaluslabs.ai
export DEDALUS_API_KEY=your-api-key
```

`TF_VAR_github_repo` tells Terraform where to register the runner. The provider reads `DEDALUS_API_KEY` and `DEDALUS_BASE_URL` from your shell. Keep the key out of Terraform source files.

## Create the runner

```bash
make init
make apply
make verify REPO="$TF_VAR_github_repo"
```

Review the Terraform plan before approving it. The [configuration](https://github.com/dedalus-labs/cookbook/blob/main/examples/github-actions-runner/terraform/main.tf) requests 2 vCPUs, 4 GiB of memory, and 20 GiB of storage. It disables autosleep so the machine stays awake while it waits for a job. `make verify` checks that GitHub reports the runner as online.

## Run the job

The cleanup job needs the machine ID and API address because it runs on another machine. Store those as repository variables, then add `DEDALUS_API_KEY` as a repository secret when prompted:

```bash
gh variable set DM_MACHINE_ID --repo "$TF_VAR_github_repo" \
  --body "$(terraform -chdir=terraform output -raw machine_id)"
gh variable set DEDALUS_BASE_URL --repo "$TF_VAR_github_repo" \
  --body "$DEDALUS_BASE_URL"
gh secret set DEDALUS_API_KEY --repo "$TF_VAR_github_repo"
gh workflow run github-actions-runner.yml --repo "$TF_VAR_github_repo"
gh run list --workflow github-actions-runner.yml --repo "$TF_VAR_github_repo"
```

The [workflow](https://github.com/dedalus-labs/cookbook/blob/main/.github/workflows/github-actions-runner.yml) sends `hello-from-dm` to a runner labeled `[self-hosted, dedalus]`. After that job, `teardown` runs on `ubuntu-latest` with `if: always()` and calls the DCS API to delete the machine.

Check both jobs in GitHub. To change the build steps, edit [`ci/github-actions-runner.ts`](https://github.com/dedalus-labs/cookbook/blob/main/examples/github-actions-runner/ci/github-actions-runner.ts) and regenerate the workflow with [Hollywood](https://oss.dedaluslabs.ai/hollywood), following the repository's instructions.

## Run it again or clean up

Run one workflow at a time. The cleanup job reads a shared machine ID, so overlapping runs could delete a machine that another job still needs.

After a run deletes its machine, run `make apply` again and update `DM_MACHINE_ID` before starting another workflow. If automatic cleanup did not finish, delete the machine from your checkout:

```bash
make destroy
```

Confirm deletion because autosleep is disabled. Compute is billed while the machine is awake, and storage remains billable until deletion. See [pricing](/dcs/dm/pricing) for rates.

The example puts the runner and its workspace on a 2 GiB filesystem backed by memory. That workspace resets on boot. Builds that need more space or persistent caches must use the machine's persistent storage.
