--- sidebar_position: 3 --- # Configuration The runner is configured with a single YAML file. It is optional: without one, the built-in defaults apply, which are the same as an empty YAML document and safe to run with. ```bash gitea-runner generate-config > config.yaml gitea-runner -c config.yaml register gitea-runner -c config.yaml daemon ``` `-c` / `--config` is a global flag and is accepted by every command that loads configuration (`register`, `daemon`, `cache-server`). The generated file is fully commented and is reproduced in [Example configuration](reference/config-example.md). :::warning No environment variable overrides The runner process is configured only through the YAML file. Earlier releases let a few variables (`GITEA_DEBUG`, `GITEA_TRACE`, `GITEA_RUNNER_CAPACITY`, `GITEA_RUNNER_FILE`, `GITEA_RUNNER_ENVIRON`, `GITEA_RUNNER_ENV_FILE`) override parts of the config; those overrides have been removed. The variables understood by the Docker images belong to their [entrypoint](installation/docker.md#entrypoint-environment-variables), not to the runner, and `GITEA_RUNNER_LABELS` / `GITEA_RUNNER_REGISTRATION_TOKEN` are read by the corresponding CLI flags only. ::: Values with a duration type accept Go duration strings such as `30s`, `10m`, `3h`. ## `log` Controls the runner's own log, not how step output is streamed to the UI. | Option | Default | Description | | --- | --- | --- | | `log.level` | `info` | `trace`, `debug`, `info`, `warn`, `error`, `fatal` or `panic`. `trace` and `debug` add the caller's `file:line`. | ## `runner` | Option | Default | Description | | --- | --- | --- | | `file` | `.runner` | path of the registration file. Each runner process needs its own. | | `capacity` | `1` | jobs executed concurrently. With an empty `container.network`, every concurrent docker job takes a subnet from the daemon's address pool, so a high capacity can exhaust it (see `default-address-pools` in the daemon config). | | `envs` | – | extra environment variables given to every job. | | `env_file` | `.env` | same, read from a file; ignored when empty or missing. | | `timeout` | `3h` | maximum job duration. Gitea has its own timeout (3h by default) and may stop the job earlier. | | `shutdown_timeout` | `0s` | how long a shutdown waits for running jobs before cancelling them. | | `insecure` | `false` | skip TLS verification of the Gitea instance. | | `fetch_timeout` | `5s` | timeout of a single job fetch. | | `fetch_interval` | `2s` | base polling interval. | | `fetch_interval_max` | `5s` | upper bound of the exponential backoff applied while idle. `0`, or the same value as `fetch_interval`, disables the backoff. | | `labels` | see [Labels](labels.md) | labels used at registration, and by `daemon` when the flag is absent. | | `github_mirror` | – | replaces `https://github.com` when actions are pulled and the instance's `DEFAULT_ACTIONS_URL` points at GitHub. | | `action_shallow_clone` | `true` | fetch only the requested ref of an action repository at depth 1 instead of its full history. | | `set_act_env` | `true` | inject `ACT=true` into jobs. Set to `false` so workflows gated on `if: ${{ !env.ACT }}` behave as they do on GitHub. | | `allocate_pty` | `false` | allocate a pseudo-TTY per step. Enable only when a job needs an interactive terminal; tools like `docker build` then write redrawing progress frames into the log. | | `workdir_cleanup_age` | `24h` | age at which stale task workspaces and orphaned host-mode scratch directories are removed while idle. | | `idle_cleanup_interval` | `10m` | cadence of the idle cleanup pass. Setting either this or `workdir_cleanup_age` to `0` disables all idle cleanup. | | `post_task_script` | – | host script run after each task's cleanup, see [Post-task script](hooks/post-task-script.md). | | `post_task_script_timeout` | `5m` | hard limit for that script. | Log and state reporting can be tuned when the UI updates too slowly or the instance sees too many requests: | Option | Default | Description | | --- | --- | --- | | `log_report_interval` | `5s` | base interval of the periodic log flush. | | `log_report_max_latency` | `3s` | maximum time a single log row waits. Only has an effect below `log_report_interval`. | | `log_report_batch_size` | `100` | flush immediately once this many rows are buffered, so bursty output arrives promptly. | | `state_report_interval` | `5s` | interval of task state reports. State is also sent on every step transition. | | `report_close_timeout` | `10s` | per-attempt deadline for the final log and state flush of a finished job. | ### Idle cleanup While no job is running, the runner cleans up after earlier ones: - stale task workspaces older than `workdir_cleanup_age` are removed when `container.bind_workdir` is enabled. Only purely numeric subdirectories of `container.workdir_parent` are treated as workspaces, and the path is assumed not to be shared with another runner; - orphaned host-mode scratch directories are removed on the same schedule. Per-job docker networks of jobs the runner did not live to tear down are *not* cleaned up in this version, and each of them keeps holding a subnet of the daemon's address pool until it is removed manually. Runner `3.0` removes them as part of the idle pass. ## `cache` See [Caching](cache.md) for the full picture, including shared cache servers. | Option | Default | Description | | --- | --- | --- | | `enabled` | `true` | run the built-in cache server used by `actions/cache` and friends. | | `dir` | `$HOME/.cache/actcache` | where cache blobs are stored. Ignored with `external_server`. | | `host` | – | address job containers use to reach this runner's cache server. Empty means auto-detect; `0.0.0.0` is not valid. | | `port` | `0` | port of the built-in server, `0` picks a free one. | | `external_server` | – | URL of a shared `cache-server` to use instead of a local one. It has to end with `/`. | | `external_secret` | – | shared secret, required with `external_server`; must be identical everywhere. Generate with `openssl rand -hex 32`. | | `external_secret_file` | – | read that secret from a file instead. Setting both is an error. | | `offline_mode` | `false` | reuse a cached action instead of fetching it on every job. A moved tag or updated branch then stays at the cached commit until the entry expires or is removed. | ## `container` Applies to jobs that run in containers. | Option | Default | Description | | --- | --- | --- | | `network` | – | network the job container joins: `host`, `bridge`, or a custom network name. Empty means the runner creates one per job. `network_mode` is still accepted for old configs. | | `network_create_options.enable_ipv4` / `enable_ipv6` | Docker defaults | only apply to auto-created networks. IPv6 additionally requires `dockerd --ipv6`. | | `privileged` | `false` | run job containers privileged; required for Docker-in-Docker inside jobs. | | `options` | – | extra `docker run` options, e.g. `--add-host=my.gitea.url:host-gateway`, `--platform` or `--pull`. | | `workdir_parent` | `/workspace` | parent directory of a job's working directory inside the container. A leading `/` is trimmed and re-added. | | `valid_volumes` | `[]` | volumes and bind mounts a job may mount, as [glob](https://github.com/gobwas/glob) patterns. `[]` forbids all, `['**']` allows all. | | `docker_host` | – | override the docker host. Empty auto-detects it, `-` auto-detects it but does not mount the socket into job containers. | | `force_pull` | `false` | pull images even when present. | | `force_rebuild` | `false` | rebuild local action images even when present. | | `require_docker` | `false` | always require a reachable daemon, even for host-only labels. | | `docker_timeout` | `0s` | how long to wait for the daemon to become reachable. | | `bind_workdir` | `false` | bind-mount the workspace from the host instead of using a docker volume. Needed for jobs that use `docker compose` with bind mounts under Docker-in-Docker. The parent directory must then be mounted into the runner container and listed in `valid_volumes`. | :::warning Workflow container options are not filtered A workflow's own `jobs..container.options` are merged into the container configuration as they are, apart from `--privileged` itself. A workflow can therefore reach the host through options such as `--pid=host` or `--cap-add=ALL`. Runner `3.0` strips those options while `container.privileged` is disabled; until then, only grant this runner to repositories you trust. ::: ## `host` | Option | Default | Description | | --- | --- | --- | | `host.workdir_parent` | `$HOME/.cache/act/` | parent directory of a job's working directory for host-mode jobs. | ## `health_check` and `metrics` Both are covered in [Monitoring](monitoring.md). | Option | Default | Description | | --- | --- | --- | | `health_check.enabled` | `false` | pause fetching new tasks while the machine looks unhealthy. | | `health_check.min_free_disk_space_mb` | `1024` | minimum free space on the filesystem holding the workspaces. | | `health_check.script` | – | extra executable; a non-zero exit, a timeout or a start failure marks the runner unavailable. | | `health_check.interval` | `30s` | how long a result is cached. | | `health_check.timeout` | `10s` | maximum script runtime. | | `metrics.enabled` | `false` | serve `/metrics`, `/healthz` and `/readyz`. | | `metrics.addr` | `127.0.0.1:9101` | listen address. There is no authentication, so only expose it behind a firewall. | | `metrics.readiness_grace` | `30s` | how long consecutive polling failures may last before `/readyz` returns 503. | ## Reloading The runner reads its configuration at startup only. Restart the process after a change — with `shutdown_timeout` set, running jobs are given that much time to finish first.