# 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) complete. Volume/GPU wizards, 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.** ## 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 GET /api/audit WS /ws/logs/{stack_id}[/{service}] WS /ws/events ``` ## 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.