# StackPilot A self-hosted Docker Compose manager for power users and homelab enthusiasts — as intuitive as Dockge, as capable as Portainer for Compose workflows. > **Status:** Phase 1 (Core) + Phase 2 (Volumes & GPU) complete. Image-update > checks, templates, multi-host agents and backups land in later phases. ## What works today (Phase 1) - **File-first stacks** — every stack is a plain `compose.yaml` (+ optional `.env`) on disk. The DB only stores metadata; nothing is locked in. - **Auth** — JWT access/refresh tokens, bcrypt hashing, admin/user roles, and a first-launch setup wizard that creates the initial admin account. - **Stack lifecycle** — create, edit, clone, delete, and `up / down / start / stop / restart / pull / update` via `docker compose`. - **Live status** — running / partial / stopped / error / updating, computed from Docker container labels. - **Real-time logs** — streamed over WebSocket, color-coded per service. - **Monaco editor** — YAML editing with an `.env` tab and a **`docker run` → compose** converter. - **Dashboard** — system resource bar, stack grid with quick actions, and a recent-activity audit feed. - **Auto-discovery** — stacks created outside the UI (any folder under the stacks dir containing a compose file) are picked up automatically. - **Dark / light theme.** ### Phase 2 — Volumes & GPU - **Volume Wizard** in the editor (right-hand helper panel): Bind / Named / NFS / SMB-CIFS / tmpfs, with a sandboxed **host path browser** for bind mounts and a live YAML preview. NFS/SMB `driver_opts` are generated for you. - **GPU assignment** per service: auto-detects NVIDIA (`nvidia-smi`) and AMD/Intel (`/dev/dri` + sysfs), injects the right YAML (NVIDIA `deploy.reservations`, or `/dev/dri` passthrough + render/video groups + `LIBVA_DRIVER_NAME=iHD` for Intel). - **Device passthrough**: lists host USB / serial-TTY / DRI nodes, add per service, plus a guarded `privileged` toggle. - All wizard edits are merged into the compose YAML **server-side** (robust, validated) and returned to the editor for review before saving. > GPU/device detection needs host visibility. The bundled compose bind-mounts > `/dev:/dev:ro`; NVIDIA additionally requires the NVIDIA container runtime on the host. ## Architecture ``` frontend (React + Vite + Tailwind, served by nginx) │ proxies /api and /ws ▼ backend (FastAPI + docker-py + SQLite) │ docker-py + `docker compose` CLI ▼ Docker Engine (via /var/run/docker.sock — never exposed to the browser) ``` ## Quick start ```bash cd stackpilot cp .env.example .env # edit .env and set a strong SECRET_KEY: openssl rand -base64 48 docker compose up -d --build ``` Open and complete the first-launch setup wizard to create your admin account. ### Configuration All backend settings are environment variables (see `backend/config.py`). The most important ones: | Variable | Default | Purpose | |-----------------|--------------------|-------------------------------------------| | `SECRET_KEY` | _(auto, dev only)_ | JWT signing key — **set this in prod** | | `STACKS_DIR` | `/opt/stacks` | Where stack folders live (in-container) | | `DATA_DIR` | `/data` | SQLite DB + app data | | `CORS_ORIGINS` | localhost | Allowed API origins (comma separated) | The host path for stacks is set via `STACKS_HOST_DIR` in `.env`. ## Local development Backend: ```bash cd backend python -m venv .venv && source .venv/bin/activate pip install -r requirements.txt SECRET_KEY=dev STACKS_DIR=../data/stacks DATA_DIR=../data uvicorn main:app --reload --port 5008 ``` Frontend (proxies to the backend on :5008): ```bash cd frontend npm install npm run dev # http://localhost:5173 ``` ## API surface (Phase 1) ``` POST /api/auth/setup | login | refresh GET /api/auth/me | needs-setup GET /api/stacks POST /api/stacks GET /api/stacks/{id} PUT /api/stacks/{id} DELETE /api/stacks/{id} POST /api/stacks/{id}/{start|stop|restart|pull|update|down|clone} GET /api/stacks/{id}/logs GET /api/stacks/{id}/export POST /api/stacks/convert (docker run → compose) GET /api/system/info | gpus | devices GET /api/audit WS /ws/logs/{stack_id}[/{service}] WS /ws/events ``` ### Phase 2 endpoints ``` GET /api/volumes | /orphaned DELETE /api/volumes/{name} POST /api/volumes/prune POST /api/volumes/generate-yaml GET /api/host/paths?path=&show_hidden= (sandboxed browser) POST /api/editor/services | add-volume | set-gpu | add-device | remove-device | set-privileged ``` ## Security notes - The Docker socket is only ever touched by the backend process; it is never proxied to the browser. - Login is rate-limited (10/min/IP). - Compose files are backed up to `*.bak` before every overwrite. - Generated YAML never includes the obsolete `version:` field and uses Compose v2 (`docker compose`) syntax.