GitHub Runner Self-Hosted vs Hosted: Cuándo Vale la Pena Ejecutar el Tuyo
Una comparación práctica entre los runners hospedados de GitHub Actions y los runners self-hosted: costo, mantenimiento, rendimiento, seguridad y control. Cuándo tiene sentido cada uno.
El dilema de quien paga la cuenta del CI
Se habla mucho de optimizar el pipeline de CI, pero poca gente se detiene a mirar de dónde viene la cuenta. GitHub Actions es generoso en el plan gratuito, con sus 2.000 minutos al mes en repositorios privados, y por un buen tiempo eso es más que suficiente. El problema empieza cuando el equipo crece, la suite de pruebas engorda, los builds pasan a ejecutarse en paralelo y, de repente, ese número cómodo se convierte en una factura que nadie previó en el presupuesto.
Y no es solo dinero. Es también esa sensación de estar esperando a que una máquina fría sea aprovisionada desde cero en cada push, descargando dependencias que ya descargaste diez mil veces, solo para ejecutar el mismo
npm cide siempre.
Es en ese momento que aparece la pregunta, normalmente en un canal de ingeniería a las once de la noche: ¿no valdrá la pena ejecutar nuestro propio runner? La respuesta, como casi todo en infraestructura, es un sólido depende. El objetivo de este post es dibujar con claridad de qué depende.
Qué es realmente cada modelo
Antes de comparar, conviene alinear el vocabulario, porque los dos modelos resuelven el mismo problema por caminos bien distintos.
Un runner hospedado es una máquina virtual efímera que GitHub aprovisiona, ejecuta tu job y descarta. Cada ejecución empieza desde cero, en un entorno limpio, con un conjunto preinstalado de herramientas, y desaparece en cuanto termina. No administras nada, no actualizas nada, no te preocupas ni por un disco lleno ni por un kernel desactualizado. A cambio, pagas por minuto y aceptas las restricciones de hardware que GitHub ofrece.
Un runner self-hosted es una máquina tuya, sea un servidor en un datacenter, una VM en la cloud, un container o incluso ese mini-PC empolvado debajo del escritorio, en la cual instalas el agente de GitHub Actions. Esa máquina se registra en el repositorio o en la organización y queda lista esperando jobs. Tú controlas el hardware, el sistema operativo, las herramientas instaladas y, sobre todo, el estado entre ejecuciones. A cambio, el mantenimiento es todo tuyo.
La diferencia filosófica es esa: el hosted es ganado, el self-hosted es mascota. Uno lo cambias sin pena, al otro lo cuidas.
Costo: lo primero que todo el mundo mira
El argumento financiero es lo que suele abrir la conversación, así que vamos a encararlo de frente. Los runners hospedados se cobran por minuto, con multiplicadores que varían según el sistema operativo. Linux es la opción más barata, Windows cuesta el doble y macOS llega a costar diez veces más por minuto. Cuando tu pipeline depende de runners macOS para compilar una app iOS, la cuenta escala a una velocidad que asusta.
El runner self-hosted, por otro lado, tiene un costo de naturaleza distinta. En vez de pagar por minuto consumido, pagas por hardware ocioso. Un servidor que corre 24 horas al día cuesta lo mismo sin importar si disparas diez o diez mil builds en él. Eso invierte por completo la lógica de optimización: en el hosted, cada segundo ahorrado es dinero de vuelta en el bolsillo, mientras que en el self-hosted lo que importa es mantener la máquina lo bastante ocupada como para justificar el costo fijo.
Existe un punto de cruce, y es ese el que necesitas calcular antes de cualquier decisión. Suma tus minutos mensuales, multiplícalos por el costo por minuto del sistema operativo que usas, y compáralo con el costo de mantener una máquina equivalente encendida todo el mes. Para equipos pequeños con poco volumen de CI, el hosted casi siempre gana, porque la máquina dedicada quedaría parada la mayor parte del tiempo. Para equipos que revientan decenas de miles de minutos al mes, especialmente en macOS o en builds pesados, el self-hosted empieza a tener sentido financiero rápido.
Un detalle que mucha gente olvida poner en la planilla: el costo de mantenimiento también es dinero. Esa hora de ingeniero depurando por qué se llenó el disco del runner vale tanto como los minutos de CI que ahorraste.
Rendimiento: donde el self-hosted brilla
Aquí el self-hosted tiene una ventaja que va más allá del dinero, y que suele ser el motivo real detrás de la migración. Como la máquina persiste entre ejecuciones, puedes mantener una caché realmente caliente. Las dependencias del node_modules, las imágenes Docker ya descargadas, los artefactos de build intermedios, todo eso sigue ahí entre un job y otro. Un pipeline que tarda ocho minutos en un runner hospedado, descargando todo desde cero, puede caer a dos o tres minutos en una máquina que ya tiene el entorno templado.
Suma a eso la libertad de elegir el hardware. Puedes ejecutar tus builds en una máquina con muchos más núcleos y memoria de los que ofrecen los runners estándar de GitHub, o conectar una caché de dependencias local con latencia irrisoria, o usar disco NVMe rápido donde el hosted te daría almacenamiento genérico. Para builds de compilación pesada, suites de pruebas masivas o pipelines de machine learning que necesitan GPU, esa diferencia no es marginal, es la diferencia entre un CI que estorba y un CI que ayuda.
Los runners hospedados, hay que reconocerlo, han evolucionado bastante. Hoy existen opciones de runners más grandes, con más núcleos, y la caché de Actions funciona razonablemente bien para los casos comunes. Pero siempre vas a estar limitado al catálogo de hardware que GitHub decidió ofrecer, y su caché, por más que ayude, todavía pasa por la red en cada ejecución.
Mantenimiento: el costo que no aparece en la factura
Ahora la parte de la que a nadie le gusta hablar. El runner hospedado tiene un costo de mantenimiento cercano a cero, y ese es su mayor as. GitHub actualiza el sistema operativo, mantiene las herramientas al día, garantiza el aislamiento entre ejecuciones y se encarga de toda la infraestructura subyacente. Tú escribes el workflow y te olvidas de que existe una máquina por debajo.
El self-hosted te devuelve todo ese trabajo, y es más de lo que parece a primera vista. Necesitas actualizar el agente del runner cuando GitHub lanza nuevas versiones, mantener el sistema operativo con parches de seguridad, monitorear disco y memoria, limpiar la basura que se acumula entre builds y garantizar que una ejecución no contamine a la siguiente. Esa caché caliente que te dio rendimiento es la misma cosa que puede darte dolor de cabeza cuando un artefacto corrupto de un build anterior hace que el siguiente falle de un modo imposible de reproducir localmente.
La estrategia que resuelve buena parte de esto es usar runners efímeros, normalmente en containers o VMs descartables que se crean para un único job y se destruyen enseguida. Herramientas como actions-runner-controller en Kubernetes o setups basados en VMs con Terraform y Ansible automatizan exactamente eso. Recuperas el aislamiento de los runners hospedados sin renunciar al control, pero pagas el precio de mantener esa orquestación funcionando. No hay almuerzo gratis, solo la elección de qué cuenta pagar.
Seguridad: el punto donde el self-hosted exige respeto
Existe una recomendación que vale repetir hasta cansarse: nunca uses runners self-hosted en repositorios públicos sin aislamiento riguroso. La razón es simple y seria. Cuando alguien abre un pull request desde un fork en un repositorio público, el workflow de ese PR puede terminar ejecutándose en tu máquina. En un runner hospedado eso es inofensivo, porque el entorno se destruye después. En un runner self-hosted persistente, eso significa que código arbitrario de un desconocido corrió en tu infraestructura, con acceso potencial a la red interna, a secretos en caché y al propio host.
Ese es el tipo de detalle que convierte un ahorro de CI en una puerta de entrada a un incidente de seguridad. Si vas a ejecutar self-hosted, hazlo en repositorios privados o con runners efímeros completamente aislados, en red segmentada, sin acceso a nada que no estés dispuesto a exponer. El modelo hosted, en este aspecto, te entrega aislamiento de fábrica, y eso tiene un valor real que rara vez entra en la cuenta de costo.
Un cuadro para cerrar el ticket
Resumiendo la comparación en los ejes que importan:
| Criterio | Hospedado | Self-hosted |
|---|---|---|
| Costo inicial | Cero | Hardware o VM |
| Costo por volumen | Por minuto, escala con el uso | Fijo, independiente del uso |
| Rendimiento | Limitado al catálogo | Hardware y caché a tu elección |
| Mantenimiento | Cero | Tuyo, íntegramente |
| Aislamiento | De fábrica | Tienes que construirlo |
| Seguridad en repos públicos | Segura por defecto | Requiere cuidado riguroso |
| Tiempo hasta el primer build | Inmediato | Setup inicial necesario |
Consideraciones finales
La elección entre runner hospedado y self-hosted no es una cuestión de cuál es mejor en lo absoluto, y desconfía de quien te vende una respuesta única. Es una cuestión de dónde está tu cuello de botella. Si tu dolor es el costo de minutos reventando todos los meses, especialmente en macOS o en builds pesados, y tienes hardware ocioso o conocimiento de infra en el equipo, el self-hosted paga la inversión. Si tu dolor es no querer administrar una cosa más, y tu volumen de CI cabe cómodamente en lo que pagas hoy, el hosted sigue siendo la elección más sensata, y probablemente la más barata cuando sumas el costo invisible del mantenimiento.
El enfoque más maduro que veo en la práctica no es elegir un bando y clavar bandera. Es usar ambos. Runners hospedados para la mayoría de los jobs, donde la conveniencia gana, y self-hosted para los casos específicos donde el hardware o el costo lo justifican, como builds de GPU, suites gigantes o pipelines que corren todo el día. La pregunta correcta nunca fue hosted o self-hosted, sino qué job pertenece a qué runner.
Love to you all.