PullPilot is a self-hosted Docker Compose updater aimed at homelabs and personal deployments. It brings the status of every project, the pull of new images and the recreation of your services into a single interface — with an automatic rollback when a deploy does not come up healthy.
The problem
Keeping a dozen Compose stacks current is manual, repetitive work: SSH in, git pull, docker compose pull, up -d, check everything is still standing, and repeat folder by folder. The existing alternatives either update blindly, or ask you to stand up more infrastructure than a homelab warrants.
PullPilot scans the root where you keep your stacks, shows one card per project, and leaves the decision to you: update everything, update one, or never touch that one.
What it does
- Per-project dashboard. One card per stack with its status, its own update button, and the Full stop and Exclude toggles.
- Update All. Walks the non-excluded projects, runs
git pullwhere applicable, recreates the containers, and leaves a summary in History. - Full stop. For delicate services that do not take a hot restart well: forces a full
docker compose downbefore pulling the new image and bringing the stack back up. - Exclude. Means never update this automatically: Update All skips it, its per-project button is disabled, and a scheduled task pointing at it will not run. Only removing the toggle brings it back.
- Scheduling. Cron or one-off tasks, per project or for everything at once. There is no schedule until you create one. Cron times follow the container clock (
TZ); a one-off task keeps the timezone of the browser that created it. A schedule is refused if its target does not exist, is excluded, or would duplicate one you already have. - Updates run in the background. Both Update All and a single-project update answer immediately and do the work behind the request; the UI follows them by polling. No HTTP connection is held open for the length of a deploy, so a reverse proxy with a short read timeout will not report a working deploy as failed.
- English and Spanish across the interface and the history log.
What happens when an update fails
Before pulling anything, PullPilot records which local image each service is currently using. If the deploy or the healthcheck fails, it puts those tags back, reverts the compose file when the stack is a Git clone, and brings the stack up again either way — so a failed update does not leave it down.
Two limits worth knowing: services built from a Dockerfile (build:) are rebuilt rather than reverted, and an image that had never been pulled on this host has no previous version to go back to.
Security and scope
- PullPilot talks straight to the Docker socket: treat it like root access. Do not expose port 8000 to the public internet without TLS via a reverse proxy, a strong password and, ideally, an extra auth layer (Authelia, Authentik and the like).
- Credentials are created through the setup wizard on first run and live hashed in the database. There is no environment variable that can create, replace or bypass them.
- Updates and scheduled jobs only run under
STACKS_PATH; paths outside that tree are rejected. - Behind a reverse proxy, set
PUBLIC_URLto the address you actually use: anhttps://value marks the session cookieSecureand makes the login rate limit readX-Forwarded-For. Leave it unset on a plain LAN install. - One Uvicorn worker per instance: the scheduler, the login rate limit and the update state are per process, so more than one worker would mean duplicated scheduled updates.
Stack
React and Vite on the frontend; FastAPI on Uvicorn with SQLite on the backend; all in one container. Apache-2.0, image ghcr.io/kn990x/pullpilot. If you still pin ghcr.io/kernel-nomad/pullpilot, update the path — the repository was renamed.
Getting started
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 -d
Open http://your-server:8000 and create a username and password in the wizard. Each project is a subfolder under /srv/docker-stacks with its own docker-compose.yml; keep PullPilot's own compose folder outside that tree when you can.
Every variable is optional. If you need to change one, create a .env next to docker-compose.yml: STACKS_PATH (stacks root, same path on host and container), PULLPILOT_PORT (published port, 8000 by default), TZ (the timezone scheduled tasks run on) and PUBLIC_URL (only behind a reverse proxy). After any change, docker compose up -d.
Full documentation and release notes live at pullpilot.app and in the KN990x/PullPilot repository.