Bakes the current stack list into the generated completion script instead of using runtime directory discovery. Useful for remote hosts where the stacks dir path differs from the local repo. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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/<stack>/.
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
| Directory | Description |
|---|---|
_backup |
Daily restic backups to HiDrive (host script + systemd timer) |
_update |
Nightly image update check + prune (host script + systemd timer) |
Deployment
# Copy example env and fill in secrets
cp <stack>/.env.example <stack>/.env
# Sync a stack to VPS
rsync -avz <stack>/ vps:~/stacks/<stack>/
# Start a stack
ssh vps 'cd ~/stacks/<stack> && 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.
# 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
ssh vps 'ln -sf ~/stacks/_backup/stacks-backup.service /etc/systemd/system/ && \
ln -sf ~/stacks/_backup/stacks-backup.timer /etc/systemd/system/ && \
systemctl daemon-reload && systemctl enable --now stacks-backup.timer'
# Manual test run
ssh vps '~/stacks/_backup/backup.sh'
# Check timer status
ssh vps 'systemctl status stacks-backup.timer'
# View snapshots
ssh vps 'source ~/stacks/_backup/.env && restic -r /mnt/hidrive/users/valknar/Backup/stacks 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.
# Deploy update stack
rsync -avz _update/ vps:~/stacks/_update/
ssh vps 'chmod +x ~/stacks/_update/update.sh'
# Install systemd units
ssh vps 'ln -sf ~/stacks/_update/stacks-update.service /etc/systemd/system/ && \
ln -sf ~/stacks/_update/stacks-update.timer /etc/systemd/system/ && \
systemctl daemon-reload && systemctl enable --now stacks-update.timer'
# Manual test run
ssh vps '~/stacks/_update/update.sh'
# Check timer status
ssh vps 'systemctl status stacks-update.timer'
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/<stack>/ on the VPS using bind mounts. Database stacks use dedicated Postgres instances with simple credentials.