# Stacks Self-contained Docker Compose stacks for `pivoine.art` infrastructure. Each stack is independently deployable with its own `compose.yml` and `.env`. All persistent data lives in `../.data//`. ## Stacks | Stack | Description | Services | |---|---|---| | `traefik` | Reverse proxy, TLS termination | traefik | | `mailpit` | SMTP relay (no web UI) | mailpit | | `umami` | Web analytics | umami, db | | `immich` | Photo & video management | immich, ml, redis, db | | `n8n` | Workflow automation & notification relay | n8n, db | | `gitea` | Git hosting + CI runner | gitea, runner, db | | `coolify` | Deployment platform | coolify, realtime, redis, db | | `passbolt` | Password manager (GPG-encrypted, team sharing) | passbolt, db | | `code` | Browser-based VS Code IDE with Anthropic API access | code | ## Tools | File/Directory | Description | |---|---| | `stacks.sh` | CLI to manage stacks, services, and scaffolding | | `_backup` | Daily restic backups to HiDrive (host script + systemd timer) | | `_update` | Nightly image update check + prune (host script + systemd timer) | ## stacks.sh `stacks.sh` is the primary management CLI. It wraps `docker compose` with glob-based multi-stack targeting, manages the update and backup systemd services, scaffolds new stacks, and generates shell completions. ```bash ./stacks.sh help ``` **Stack commands** — all accept one or more stack names or glob patterns (omit for all stacks): ```bash ./stacks.sh ls # list all stacks with live container status ./stacks.sh ps gitea # container status table ./stacks.sh up # start all stacks ./stacks.sh up gitea traefik # start specific stacks ./stacks.sh down 'g*' # stop stacks matching glob ./stacks.sh restart 'g*,traefik' # glob + exact name, comma-separated ./stacks.sh pull --parallel # pull all images in parallel ./stacks.sh logs -f gitea # follow logs ./stacks.sh logs -n 100 gitea n8n # tail multiple stacks ./stacks.sh exec gitea gitea gitea admin user list # exec in container ./stacks.sh run passbolt passbolt bin/cake passbolt healthcheck ``` **Service management:** ```bash ./stacks.sh update install # link & enable systemd update timer ./stacks.sh update run # run update now ./stacks.sh update status # show timer/service status ./stacks.sh update logs # show journal logs ./stacks.sh backup install # link & enable systemd backup timer ./stacks.sh backup run # run backup now ./stacks.sh backup snapshots # list restic snapshots ``` **Scaffold a new stack:** ```bash ./stacks.sh new myapp # basic stack with Traefik labels ./stacks.sh new myapp --db postgres # with Postgres service ./stacks.sh new myapp --db postgres --redis # with Postgres + Redis ./stacks.sh new myapp --no-traefik # expose port instead of Traefik ``` Generates `compose.yml` (with healthchecks, `../.data/` volumes, Traefik labels) and `.env.example`. **Shell completion:** ```bash # Dynamic — discovers stacks at tab-complete time (default) ./stacks.sh completion zsh --install # Static — bakes current stack list in; useful on the VPS ./stacks.sh completion zsh --static --install ``` **Global flags:** `--dry-run`, `--parallel`, `--verbose`, `--quiet` ## Deployment ```bash # Copy example env and fill in secrets cp /.env.example /.env # Sync a stack to VPS rsync -avz / vps:~/stacks// # Start a stack ssh vps 'cd ~/stacks/ && docker compose up -d' ``` ## Network All stacks share the external `falcon_network` Docker network for inter-service communication (e.g. traefik routing, mailpit SMTP). ## Backup The `_backup` stack runs a daily restic backup at 3:00 AM. It dumps all Postgres databases, then backs up the entire `.data/` directory to HiDrive. Retention: 7 daily, 4 weekly, 6 monthly snapshots. Notifications go to Telegram via n8n. ```bash # Deploy backup stack rsync -avz _backup/ vps:~/stacks/_backup/ # Initialize restic repo (first time only) ssh vps 'source ~/stacks/_backup/.env && restic init -r /mnt/hidrive/users/valknar/Backup/stacks' # Install systemd units (or use stacks.sh on the VPS) ssh vps '~/stacks/stacks.sh backup install' # Manual run / status ssh vps '~/stacks/stacks.sh backup run' ssh vps '~/stacks/stacks.sh backup status' ssh vps '~/stacks/stacks.sh backup snapshots' ``` ## Updates The `_update` script runs nightly at 2:00 AM. It pulls the latest image for every stack, recreates any containers whose image changed, prunes dangling images, and sends a Telegram notification via n8n. ```bash # Deploy update stack rsync -avz _update/ vps:~/stacks/_update/ # Install systemd units (or use stacks.sh on the VPS) ssh vps '~/stacks/stacks.sh update install' # Manual run / status ssh vps '~/stacks/stacks.sh update run' ssh vps '~/stacks/stacks.sh update status' ``` ## Notifications The update script and the backup script both POST to an n8n webhook, which forwards messages to Telegram. The webhook URL is set in: - `_backup/.env` → `WEBHOOK_URL` - `_update/.env` → `WEBHOOK_URL` Both point to the same n8n workflow at `https://n8n.pivoine.art`. The workflow accepts `{ "message": "..." }` and forwards it to Telegram. ## Data Persistent data is stored in `~/stacks/.data//` on the VPS using bind mounts. Database stacks use dedicated Postgres instances with simple credentials.