Documentación
Instala tu actualizador Docker.
PullPilot es un actualizador Docker Compose self-hosted para homelabs — estado, logs y modos de despliegue desde una sola interfaz. Así lo instalas, organizas tus stacks y lo aseguras.
Instalación rápida
No hay ningún .env que escribir. PullPilot trae valores por defecto que funcionan — un contenedor, un fichero SQLite y tu carpeta de Compose — y te pide usuario y contraseña en el navegador la primera vez.
$ sudo mkdir -p /srv/docker-stacks
$ mkdir -p ~/pullpilot && cd ~/pullpilot
$ curl -fsSL -o docker-compose.yml https://raw.githubusercontent.com/KN990x/PullPilot/main/docker-compose.yml
$ docker compose up -dLuego abre http://tu-servidor-ip:8000 (o el puerto de PULLPILOT_PORT). Eso es toda la instalación.
Primer arranque
El navegador muestra un asistente de configuración: eliges usuario y contraseña, la repites, y ya estás dentro. Las credenciales se guardan hasheadas (scrypt) en la propia base de datos de PullPilot y el secreto de firma de sesión se genera y persiste solo — no hay nada que configurar ni ningún secreto que meter en un fichero.
Entre el primer arranque y completar el asistente, cualquiera que alcance la instancia puede reclamarla. Complétalo enseguida y no publiques el puerto antes de hacerlo.
Tras el arranque
Cada proyecto es una subcarpeta bajo la raíz de stacks con un docker-compose.yml (o docker-compose.yaml) dentro. Cuando puedas, mantén la carpeta de compose de PullPilot fuera de ese árbol.
/srv/docker-stacks/ # STACKS_PATH por defecto
├── plex/
│ └── docker-compose.yml
├── uptime-kuma/
│ └── docker-compose.yml
└── ...Las carpetas llamadas pullpilot, pullpilot-ui, docker-updater y data se ignoran bajo la raíz de stacks.
Usar otra ubicación de stacks
Crea la carpeta en el host y añade un .env junto a docker-compose.yml apuntando a ella. La ruta debe ser idéntica en el host y dentro del contenedor, porque se monta uno a uno. Tras cualquier cambio en .env, ejecuta docker compose up -d.
STACKS_PATH=/absolute/path/to/stacksGuía de uso
Dashboard
Una tarjeta por proyecto — estado, actualización por proyecto e interruptores Full stop y Excluir.
Actualizar todo
Escanea los proyectos no excluidos, ejecuta git pull cuando aplica, recrea contenedores; resumen en el Historial. Responde al instante y trabaja en segundo plano.
Excluir
Significa no actualizar esto nunca de forma automática: lo salta Actualizar todo, su botón de actualizar se deshabilita y una tarea programada que le apunte no se ejecuta. Solo quitando el interruptor vuelve.
Programación
Tareas cron o puntuales, por proyecto o para todo a la vez. No hay nada programado hasta que tú lo creas — el formulario solo sugiere las 04:00.
Qué pasa si una actualización falla
Antes de descargar nada, PullPilot anota qué imagen local está usando cada servicio. Después hace el pull, recrea el stack y espera hasta 60 segundos a que los contenedores levanten sanos. Si el despliegue o el healthcheck fallan, restaura esas imágenes, revierte el fichero de compose cuando el stack es un clon de Git y vuelve a levantarlo en cualquier caso — una actualización fallida no lo deja caído.
Dos límites que conviene conocer: los servicios construidos desde un Dockerfile (build:) se reconstruyen en vez de revertirse, y una imagen que nunca se había descargado en este host no tiene versión anterior a la que volver.
Las actualizaciones corren en segundo plano. Tanto Actualizar todo como la de un solo proyecto responden al instante y hacen el trabajo por detrás, así que un proxy inverso con un read timeout corto ya no marca como fallido un despliegue que va bien. Una segunda actualización del mismo stack se rechaza mientras corre la primera.
Variables de entorno
Las cuatro son opcionales. Copia .env.example a .env junto a docker-compose.yml solo si necesitas cambiar alguna, y ejecuta docker compose up -d.
| Variable | Por defecto | Descripción |
|---|---|---|
| STACKS_PATH | /srv/docker-stacks | Carpeta de stacks: una subcarpeta por proyecto, cada una con su docker-compose.yml. Se monta en la misma ruta absoluta en host y contenedor. |
| PULLPILOT_PORT | 8000 | Puerto publicado en el host para la interfaz. |
| TZ | UTC | Zona horaria del contenedor — con la que corren las tareas programadas. |
| PUBLIC_URL | (sin definir) | Solo detrás de un proxy inverso. Un valor https:// marca la cookie de sesión como Secure y hace que el límite de login lea X-Forwarded-For. |
Todo lo que antes era configurable — el secreto de sesión, el SameSite de la cookie, los orígenes CORS, los timeouts de comandos, el límite de login — ahora se genera solo o es una constante con un valor sensato. Si tenías DOCKER_ROOT_PATH o PROJECTS_ROOT en un .env antiguo, ambas siguen funcionando como alias de STACKS_PATH.
Notas de seguridad
Trata PullPilot como acceso root — el socket de Docker está montado. No expongas el puerto 8000 a internet pública sin TLS, una contraseña robusta y, a ser posible, otra capa de auth (Authelia, Authentik…).
Las actualizaciones y tareas programadas solo se ejecutan bajo la raíz de stacks resuelta. Las rutas fuera de ese árbol se rechazan.
Las credenciales viven hasheadas en la base de datos y se crean desde el asistente. No hay ninguna variable de entorno capaz de crearlas, sustituirlas o saltárselas. El login está limitado a 15 intentos cada 5 minutos por IP.
Detrás de un proxy que termina TLS, define PUBLIC_URL con la dirección que usas de verdad, por ejemplo https://pullpilot.example.com. Déjala sin definir en una instalación LAN a secas. El botón de cuenta de la cabecera cambia usuario y contraseña — al hacerlo se cierra la sesión en el resto de dispositivos.
Usa un solo worker de Uvicorn por instancia. La clave de firma sí se comparte entre workers — vive en un fichero dentro del volumen de datos — pero el planificador, el límite de login y el estado de las actualizaciones son por proceso, así que más de un worker significa actualizaciones programadas duplicadas.
La imagen publicada es ghcr.io/kn990x/pullpilot:latest. Si todavía apuntas a ghcr.io/kernel-nomad/pullpilot, actualiza tu compose — esa ruta ya no se mantiene.