# Concepts

> Runner states, products and locations, executors, which changes recreate the server, and what you pay for.

Source: https://managerunners.com/docs/manual/concepts/

## Runners and servers

A *runner* in Manage Runners is a configuration: name, server type, location, executor, concurrency, GitLab host and token, Hetzner token, SSH keys, labels and the monitoring setting. While the runner is active, a Hetzner server with that configuration exists in your Hetzner project and runs GitLab Runner.

Every server is created fresh from a Debian 13 image. On first boot it:

- installs Docker and GitLab Runner from their official package repositories,
- registers with your GitLab instance using the runner authentication token,
- sets GitLab Runner's global job concurrency,
- turns on automatic package updates, including Docker and GitLab Runner, and reboots automatically when an update requires it,
- allows SSH only for `root` with a key, never with a password, and enables fail2ban,
- removes Docker volumes that GitLab Runner created and that are older than 7 days, once a day,
- installs the monitoring collector, if [monitoring](https://managerunners.com/docs/manual/monitoring/) is on.

Because a paused runner has no server, pausing and resuming always gives you a clean, freshly installed machine. Anything stored on the server's disk is lost when the server is deleted.

## Runner states

| State | Meaning |
| --- | --- |
| **Creating** | Hetzner is creating the server. |
| **Configuring** | The server is installing Docker and GitLab Runner. |
| **Active** | GitLab Runner registered successfully. The runner takes jobs. The API and CLI call this state `READY`. |
| **Invalid Gitlab Token** | GitLab rejected the runner token during registration. The server keeps running. Use **Fix** to enter a new token. |
| **Paused** | The server is deleted. The configuration and the IP addresses are kept. |
| **Unknown** | Manage Runners lost track of the server, for example because the Hetzner token stopped working. See [Troubleshooting](https://managerunners.com/docs/manual/troubleshooting/#a-runner-is-unknown). |

A new runner normally goes from **Creating** through **Configuring** to **Active** within a few minutes. Resuming a paused runner takes the same path.

## IP addresses

Each server gets a public IPv4 and IPv6 address, as Hetzner primary IPs. When you pause a runner, Manage Runners deletes the server but keeps both addresses, and attaches them to the new server when you resume. Firewall rules and allow lists that mention a runner's addresses keep working across pause and resume.

The addresses are released only when you delete the runner. A runner's location cannot be changed, because a different location would change its addresses.

## Products and locations

A *product* is a Hetzner Cloud server type. Manage Runners offers every server type that Hetzner has not deprecated and that is available in at least one location. Product IDs are the Hetzner server type name with a `hz-` prefix, for example `hz-cpx31`.

Each product shows:

- **Architecture:** x86 (Intel or AMD, best compatibility) or ARM. Your CI images must support the architecture you choose.
- **vCPUs, RAM and disk.**
- **Locations** where Hetzner currently offers it, with Hetzner's monthly net list price in EUR.

Hetzner's locations are Falkenstein and Nuremberg (Germany), Helsinki (Finland), Singapore, and Ashburn and Hillsboro (USA). Not every server type is offered in every location, and availability changes over time. If Hetzner stops offering a server type in a location, a paused runner using it cannot be resumed until it is available again, and it cannot be duplicated.

## Executors

| Executor | Dashboard label | What jobs get |
| --- | --- | --- |
| `docker` | docker | Each job runs in a container. The default image is `alpine:latest`; jobs choose their own with `image:`. |
| `dind` | docker-in-docker | Like `docker`, with the default image `docker:28-cli`, privileged containers and the server's Docker socket mounted, so jobs can build and run images. |
| `shell` | shell | Jobs run directly on the server as the `gitlab-runner` user. |

With `dind`, jobs control the server's Docker daemon. Use it only for projects you trust.

## Concurrency

Concurrency is the number of jobs the runner runs at the same time (GitLab Runner's global `concurrent` setting). When you select a product in the dashboard, it is set to twice the server's vCPU count. Lower it for memory-hungry jobs.

## Changes that recreate the server

Some settings are applied when the server is created. Changing them on an active runner makes Manage Runners delete the server and create a new one with the same IP addresses. Jobs running at that moment are interrupted.

| Change | Recreates an active runner's server |
| --- | --- |
| Product | yes |
| GitLab host | yes |
| GitLab runner token | yes |
| Concurrency | yes |
| Executor | yes |
| SSH keys | yes |
| Monitoring on or off | yes |
| Name | no |
| Labels | no, they are updated on the Hetzner server directly |
| Hetzner token | no |
| Location | cannot be changed |

Editing a paused runner never creates a server; the new settings apply when you resume it.

## Costs

You pay two parties:

- **Hetzner** bills your Hetzner account for the servers in your project, at Hetzner's prices. The prices in the dashboard are Hetzner's monthly net list prices, without VAT. While a runner is paused, it has no server. Hetzner may still charge for the IP addresses that are kept; see Hetzner's pricing.
- **Manage Runners** bills your plan. See [Billing and plans](https://managerunners.com/docs/manual/billing/) and [pricing](https://managerunners.com/pricing/).

Pausing runners when nobody needs them, by hand or with a [schedule](https://managerunners.com/docs/manual/schedules/), is the main way to save server costs.
