If you run a homelab with multiple Docker containers, you already know how tedious it is to keep them updated manually. Let me introduce PullPilot, the tool designed to solve this in a visual, automated, and, above all, super secure way.

Honestly, this project was born out of frustration. As I've mentioned before, I was tired of having to remember to update my containers, and honestly, current alternatives felt way too complex for something SO simple. So, I basically built a webapp with a super clean dashboard that scans your Dockers and lets you keep them up to date.

The only thing to keep in mind (as with any updater) are "breaking changes". In other words, if the developers of those Docker images make major changes to their projects (which rarely happens in serious projects), you might break your docker-compose.yml—but the exact same thing would happen if you did it manually.

You can find all the information on how it works, installation, and configuration in the new official repository (KN990x/PullPilot), but here are the main features:

  • Total Control: You decide when to update. You can hit the "Update All" button or go project by project using their individual cards.
  • "Full Stop" Mode: If you have sensitive services (like databases) that don't handle hot reboots well, I've added a toggle to force a full shutdown (docker compose down) before pulling the new image and bringing the service back up.
  • Exclusion List: You can flag specific projects to be completely ignored during bulk updates.
  • Smart Scheduling (Cron/Date): You can schedule automatic updates (daily, weekly, monthly) or set a one-time date directly from the visual interface.
  • Built-in Auto-Rollback: PullPilot takes a snapshot of the Git commit before updating. If the new container experiences a critical failure or fails its healthcheck, the system automatically runs a git reset --hard and forces a redeployment of the previous version so your service doesn't stay down.
  • Disk Cleanup and Maintenance: After a global update finishes with zero errors, PullPilot safely runs an internal docker image prune -f command. This way, old and dangling images are automatically removed, keeping your hard drive clean.
  • Native Multi-Language Support: Both the interface and the history logs support Spanish and English. The frontend auto-detects your browser language, but you can force the language for background tasks using the environment variable LOG_LOCALE=en.

Important notes on security

Since PullPilot interacts directly with the Docker socket, treat it with the same caution as root access.

  1. Do not expose port 8000 to the internet without a reverse proxy with TLS.
  2. The system includes a built-in Rate Limiting policy in the backend: if more than 15 failed login attempts are detected from an IP within a 5-minute window, that IP will be temporarily blocked to prevent brute-force attacks.

Quick installation via docker compose

By default, the deployment is designed to scan projects stored within the host path /srv/docker-stacks. Each project must be a subfolder containing its own docker-compose.yml file.

1) Configure the .env file (Recommended)

# Absolute path on the host where you store your Docker project folders
DOCKER_ROOT_PATH=/srv/docker-stacks

# Interface port and Timezone
PULLPILOT_PORT=8000
TZ=Europe/Madrid

# Security (Forces login)
ALLOW_NO_AUTH=false
AUTH_USER=admin
AUTH_PASS=your-secure-password

# Fixed key to sign session cookies (so they don't expire when restarting the container)
# Generate a long, random one in your terminal with: openssl rand -hex 32
SESSION_SECRET=your-hex-token-here

2) Create the docker-compose.yml

This is the official, optimized file to deploy the tool by reading your environment variables:

services:
  pullpilot:
    container_name: pullpilot
    image: ghcr.io/kn990x/pullpilot
    restart: unless-stopped
    ports:
      - "${PULLPILOT_PORT:-8000}:8000"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - pullpilot_data:/app/data
      - ${DOCKER_ROOT_PATH:-/srv/docker-stacks}:${DOCKER_ROOT_PATH:-/srv/docker-stacks}
    environment:
      TZ: ${TZ:-UTC}
      DATA_DIR: ${DATA_DIR:-/app/data}
      DOCKER_ROOT_PATH: ${DOCKER_ROOT_PATH:-/srv/docker-stacks}
      PROJECTS_ROOT: ${PROJECTS_ROOT:-}
      ALLOW_NO_AUTH: ${ALLOW_NO_AUTH:-true}
      AUTH_USER: ${AUTH_USER:-}
      AUTH_PASS: ${AUTH_PASS:-}
      SESSION_SECRET: ${SESSION_SECRET:-}

volumes:
  pullpilot_data:

Once created, spin up the container using the classic command:

docker compose up -d

And that's it! You can now open http://your-server-ip:8000 in your browser, log in with the credentials you set up in the .env file, and enjoy total, automated control over your Homelab updates.