Para actualizar act_runner a Gitea Runner 5 cambia la imagen gitea/act_runner por gitea/runner:5.2.3, conserva el volumen /data y revisa tres cosas de tu config.yaml y tus workflows antes de arrancar. La imagen antigua dejó de publicarse el 30 de abril de 2026 y sigue en la v0.6.1, así que latest ya no te trae nada nuevo. El salto reutiliza tu registro, pero en mi prueba rompió tres trabajos que pasaban con la 0.6.1: un ${VAR} sin definir en la configuración, un comodín de valid_volumes y un job sin runs-on. Lo probé el 27 de octubre de 2026 en Linux arm64 con Gitea 28.2.0 y Docker 29.5.2. Tienes la versión en inglés de esta guía.

Puntos clave

  • gitea/act_runner:latest sigue en la v0.6.1, publicada el 30 de abril de 2026; Docker Hub la marca como "Deprecated Gitea runner. Moved to gitea/runner".
  • Entre la v0.6.1 y la v5.2.3 hay 36 versiones y cinco versiones mayores, publicadas en menos de seis meses.
  • El archivo .runner de la 0.6.1 sirve tal cual: el runner conservó el id 1 en Gitea y no hubo que registrarlo otra vez.
  • Un ${VAR} sin definir en config.yaml deja el contenedor en bucle con ${DEPLOY_ENV} is not set; un ${HOME} definido se expande sin avisar.
  • Desde la v4.0.0, * en valid_volumes ya no cruza /, y desde la v5.0.0 un job sin runs-on falla en lugar de ejecutarse.

Si todavía no tienes Gitea montado, empieza por la guía para instalar Gitea con Docker. Si además vas a subir el servidor, sigue antes los pasos para actualizar Gitea 1.27 a Gitea 28 con Docker: el runner 5 funcionó contra Gitea 28.2.0 en esta prueba.

¿Por qué tu runner sigue en act_runner 0.6.1?

Porque el proyecto cambió de nombre y la imagen antigua se quedó quieta. El 5 de mayo de 2026 Gitea publicó la versión 1.0.0 con el nombre nuevo. bircni, del comité de supervisión técnica de Gitea, firmó el anuncio del blog de Gitea[1]. Su resumen fue este: "The project formerly known as act_runner has been renamed to Gitea Runner, with the repository now available at gitea/runner." El mismo anuncio describía la migración como "a straight rename", y en la 1.0.0 era cierto.

Desde entonces el proyecto ha ido deprisa. Estas son las cifras que consulté el 28 de octubre de 2026 en la API de Docker Hub y en la de Gitea:

  • gitea/act_runner: 11 109 390 descargas, última actualización el 30 de abril de 2026, etiqueta más reciente 0.6.1
  • gitea/runner: 1 742 227 descargas, última actualización el 28 de octubre de 2026, etiqueta más reciente 5.2.4, que corrige upload-artifact v4 en el modo host (la prueba de esta guía usa la 5.2.3)
  • Versiones publicadas: 37 desde la v0.6.1, con versiones mayores 1.0.0, 2.0.0, 3.0.0, 4.0.0 y 5.0.0

La primera cifra pesa: hay muchos más runners con la imagen vieja que con la nueva. Comprueba qué ejecuta el tuyo con este comando:

$ docker run --rm --entrypoint act_runner gitea/act_runner:latest --version
act_runner version v0.6.1

Qué cambia entre act_runner 0.6.1 y Gitea Runner 5

El cambio de nombre es lo de menos; lo que rompe trabajos son las versiones mayores que vinieron después. Resumo las que afectan a una instalación con Docker, sacadas de las notas de cada versión:

Versión Fecha Cambio incompatible
1.0.0 5 may 2026 Binario act_runner pasa a gitea-runner, imagen a gitea/runner, métricas act_runner_* a gitea_runner_*
2.0.0 30 jun 2026 Los secretos DOCKER_USERNAME y DOCKER_PASSWORD dejan de usarse solos para descargar imágenes
3.0.0 31 jul 2026 Un solo proceso por archivo .runner; las opciones de contenedor que tocan el host exigen modo privilegiado
4.0.0 24 sep 2026 * en valid_volumes ya no cruza /; la caché pasa por el runner
5.0.0 8 oct 2026 ${NAME} se expande en config.yaml, runs-on es obligatorio, hace falta Git 2.34.1 o posterior

Las variables de entorno de la imagen no cambian (GITEA_INSTANCE_URL, GITEA_RUNNER_REGISTRATION_TOKEN, GITEA_RUNNER_NAME, CONFIG_FILE), y el formato del archivo de registro tampoco. Por eso el cambio de imagen arranca, y los fallos aparecen después, en la configuración y en los jobs.

Cómo reproduje la actualización

Monté un Gitea 28.2.0 y un runner con Docker-in-Docker (dind, el runner lleva su propio demonio Docker dentro) en un mismo Compose. Primero lo arranqué con gitea/act_runner:0.6.1-dind, lo registré y ejecuté un workflow de dos jobs hasta verlo en verde. Después cambié solo la imagen y repetí. Este es el servicio del runner:

  runner:
    image: ${RUNNER_IMAGE:-gitea/act_runner:0.6.1-dind}
    privileged: true
    environment:
      GITEA_INSTANCE_URL: "http://172.30.202.10:3000"
      GITEA_RUNNER_REGISTRATION_TOKEN: ${RUNNER_TOKEN:-}
      GITEA_RUNNER_NAME: "b10p02-runner"
      GITEA_RUNNER_LABELS: "ubuntu-latest:docker://node:24-bookworm"
      CONFIG_FILE: /config/config.yaml
    volumes:
      - runner-data:/data
      - ./config.yaml:/config/config.yaml:ro

El config.yaml de partida tenía dos variables pensadas para expandirse dentro del job, no en el runner, y un volumen permitido con un solo asterisco:

runner:
  file: .runner
  envs:
    PIP_CACHE_DIR: "${HOME}/.cache/pip"
    DEPLOY_PATH: "/srv/${DEPLOY_ENV}/app"
container:
  valid_volumes:
    - "/srv/cache/*"

El workflow tenía un job build que monta /srv/cache/npm/v24 en /cache, y un job notify sin runs-on. Con la 0.6.1 los dos terminaron bien: notify corrió en la imagen por defecto docker.gitea.com/runner-images:ubuntu-latest, y el log de build imprimió DEPLOY_PATH=/srv/${DEPLOY_ENV}/app tal cual.

Error: parse config file: ${DEPLOY_ENV} is not set

Este es el primer fallo, y aparece nada más cambiar la imagen a gitea/runner:5.2.3-dind. El contenedor sigue en estado Up, así que docker ps no te avisa; el aviso solo sale en el log:

$ docker logs b10p02-runner
Error: parse config file "/config/config.yaml": line 8: ${DEPLOY_ENV} is not set
 is missing or not a regular file
level=info msg="Registering runner, arch=arm64, os=linux, version=v5.2.3."
Error: parse config file "/config/config.yaml": line 8: ${DEPLOY_ENV} is not set
Waiting to retry ...

La causa es la v5.0.0: un valor de config.yaml con ${NAME} lee ahora esa variable del entorno del runner, y la carga falla si no existe. Sin configuración, el script de arranque de la imagen no encuentra la ruta del archivo .runner. Cree entonces que el runner no está registrado y reintenta el registro cada 5 s.

El arreglo es escribir $${NAME} cuando quieres el texto literal. Escapa también las variables que sí existen en el runner: en mi prueba, ${HOME} no dio error, pero el job recibió PIP_CACHE_DIR=/root/.cache/pip, el HOME del contenedor del runner, en lugar del texto sin expandir. Así quedan las dos líneas:

  envs:
    PIP_CACHE_DIR: "$${HOME}/.cache/pip"
    DEPLOY_PATH: "/srv/$${DEPLOY_ENV}/app"

Recrea el contenedor después de editar el archivo, con docker compose up -d --force-recreate runner. Si editas un archivo montado con sed -i, el editor crea un archivo nuevo y un restart puede seguir viendo el antiguo.

is not a valid volume, will be ignored

Con la configuración ya cargada, el job build falló por otro motivo. El runner descartó el volumen del workflow y el paso que lo usaba no encontró el directorio:

[/srv/cache/npm/v24] is not a valid volume, will be ignored
ls: cannot access '/cache': No such file or directory
##[error]Process completed with exit code 2.

El cambio viene de la v4.0.0: * en valid_volumes ya no coincide a través de /. Con la 0.6.1, /srv/cache/* aceptaba /srv/cache/npm/v24; ahora solo acepta un nivel, como /srv/cache/npm. Usa ** para rutas anidadas:

container:
  valid_volumes:
    - "/srv/cache/**"

La v5.0.0 añade además entradas :ro, que solo permiten montajes de lectura. Si un volumen sigue sin montarse con **, revisa la incidencia 1251 de Gitea Runner[2], que recoge un caso en la 4.0.0 con volúmenes de contenedor de job.

job requires a non-empty ‘runs-on’

El tercer fallo es el de la captura de portada. El job notify no tenía runs-on, y la 0.6.1 lo ejecutaba en la imagen por defecto del runner. La 5.2.3 lo para en la preparación:

b10p02-runner(version:v5.2.3)
workflow prepared
job "notify" requires a non-empty 'runs-on'

La v5.0.0 lo hace así para comportarse igual que GitHub Actions. Los jobs que llaman a un workflow reutilizable quedan exentos. El arreglo es añadir la etiqueta en cada job:

  notify:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - run: echo "job without runs-on"

Con los tres cambios, la ejecución número 6 terminó en verde con los dos jobs sobre Gitea Runner 5.2.3.

exec: "act_runner": executable file not found in $PATH

Este error aparece si tu Compose, tu unidad de systemd o un script llaman al binario por su nombre antiguo. En la imagen nueva el binario es gitea-runner, y no hay enlace con el nombre viejo:

$ docker run --rm --entrypoint act_runner gitea/runner:5.2.3 daemon
docker: Error response from daemon: failed to create task for
container: failed to create shim task: OCI runtime create failed:
runc create failed: unable to start container process: error during
container init: exec: "act_runner": executable file not found in $PATH

En tu terminal sale en una sola línea; aquí está partido para que quepa. Cambia act_runner daemon por gitea-runner daemon, o quita el entrypoint y deja el de la imagen. Ojo con pasar el binario viejo como command: el script de la imagen ignora los argumentos e intenta registrar el runner en bucle. Aprovecha también para cambiar generate-config, que en la 5.2.3 avisa de que está obsoleto y remite a config generate.

Cómo comprobar tu config.yaml antes de cambiar la imagen

El subcomando config runner-file carga la configuración entera, así que sirve de prueba previa sin tocar el runner en marcha. Lánzalo con la imagen nueva contra tu archivo:

docker run --rm -v "$PWD/config.yaml:/c.yaml:ro" \
  --entrypoint gitea-runner gitea/runner:5.2.3 \
  --config /c.yaml config runner-file
echo "exit=$?"

Con mi configuración original devolvió el mismo ${DEPLOY_ENV} is not set y exit=1; con la corregida devolvió la ruta .runner y exit=0. Después, busca en tus workflows los jobs sin runs-on y las rutas de valid_volumes con un solo *. Esta lista cubre el resto de cambios que no reproduje y que debes revisar a mano:

  • DOCKER_USERNAME / DOCKER_PASSWORD: desde la 2.0.0 ya no autentican descargas de imágenes; usa container.credentials en el job
  • Un .runner por proceso: desde la 3.0.0 el archivo se bloquea al arrancar, así que cada runner necesita su propio registro
  • container.network: bridge: desde la 4.0.0 los jobs en bridge no llegan a la caché del runner; deja el valor vacío o usa una red propia
  • builtin:checkout: desde la 5.0.0 borra los archivos sin seguimiento salvo con clean: false
  • Métricas: act_runner_* pasó a gitea_runner_* en la 1.0.0 y la 5.0.0 adopta los nombres de OpenTelemetry
  • Opciones de log y OOM: sin container.privileged, la 5.0.0 descarta --log-driver, --log-opt, --oom-score-adj y --oom-kill-disable con un aviso

Qué pasa con el registro y cómo volver atrás

El registro se conserva si mantienes el volumen /data. Tras el cambio de imagen, el runner arrancó con el .runner que había escrito la 0.6.1 y anunció version: v5.2.3. La API de administración de Gitea siguió mostrando un único runner con id 1, en estado online. No hace falta un token nuevo.

Para volver atrás, fija otra vez la imagen anterior y recrea el contenedor; el archivo de registro es el mismo. Revierte también los $${...} del config.yaml, porque la 0.6.1 no los entiende y pasaría el doble dólar tal cual. Fija la imagen por versión, gitea/runner:5.2.3 o gitea/runner:5, y no por latest: el proyecto publicó cinco versiones mayores en cinco meses.

Si comparas con Forgejo, su runner lleva una línea de versiones propia; la guía para instalar Forgejo con Docker, Caddy y Forgejo Runner cubre ese caso.

Preguntas frecuentes

¿Tengo que volver a registrar el runner al pasar a gitea/runner?

No, si conservas el volumen con el archivo .runner. En la prueba, Gitea Runner 5.2.3 reutilizó el registro de act_runner 0.6.1 y Gitea mantuvo el mismo id. Solo registras de nuevo si borras /data o si arrancas dos procesos con el mismo archivo, que desde la 3.0.0 está bloqueado.

¿Puedo seguir usando gitea/act_runner:latest?

Puedes, pero no recibirás correcciones: la etiqueta apunta a la v0.6.1 de abril de 2026. La v5.2.0, por ejemplo, se compiló con Go 1.27.3 para cerrar la CVE-2026-111943 de certificados intermedios, y la imagen vieja no tiene ese arreglo.

¿Funciona Gitea Runner 5 con un servidor Gitea anterior a la 28?

La prueba solo cubre Gitea 28.2.0. La v5.2.1 migró a connectrpc.com/connect/v2, y sus notas dicen que funciona con servidores en connect v1 y v2. Si tu servidor es antiguo, prueba primero con un runner aparte antes de cambiar el principal.

Conclusión

Pasar de act_runner 0.6.1 a Gitea Runner 5 es un cambio de imagen que conserva el registro, y los fallos aparecen en la configuración y en los workflows. Escapa con $$ los ${...} de config.yaml, cambia * por ** en valid_volumes y añade runs-on a cada job. Valida el archivo con config runner-file antes de recrear el contenedor y fija la versión de la imagen. Si después te toca importar repositorios en Gitea 28, la guía del error You cannot import from disallowed hosts cubre el otro cambio incompatible de esa versión.

Fuentes: [1] Gitea, anuncio de Gitea Runner 1.0.0[1], [2] Gitea Runner, notas de la v5.0.0[3], [3] Gitea Runner, notas de la v4.0.0[4], [4] Gitea Runner, notas de la v3.0.0[5], [5] Gitea Runner, notas de la v2.0.0[6], [6] Docker Hub, imagen gitea/act_runner[7], [7] Docker Hub, imagen gitea/runner[8], [8] Documentación de Gitea, runner de Actions[9], [9] Gitea Runner, incidencia 1251 sobre volúmenes en la 4.0.0[2].

Fuentes

  1. anuncio del blog de Gitea
  2. incidencia 1251 de Gitea Runner
  3. Gitea Runner, notas de la v5.0.0
  4. Gitea Runner, notas de la v4.0.0
  5. Gitea Runner, notas de la v3.0.0
  6. Gitea Runner, notas de la v2.0.0
  7. Docker Hub, imagen gitea/act_runner
  8. Docker Hub, imagen gitea/runner
  9. Documentación de Gitea, runner de Actions