Self-hosted sync backend for the Obsidian LiveSync plugin, following https://blog.admin-intelligence.de/selbsthosting-von-obsidian-mit-couchdb-kostenlose-synchronisation-einrichten/. local.ini.example carries the required chttpd/cors config; local.ini itself is gitignored since CouchDB rewrites it in place (hashed admin password, node uuid) on first start, so a tracked copy would never stay clean. The config also has to be mounted read-write, not :ro: CouchDB's entrypoint chowns everything under /opt/couchdb and aborts under set -e if that fails. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
130 lines
5.1 KiB
Markdown
130 lines
5.1 KiB
Markdown
# 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 |
|
|
| `headscale` | Self-hosted Tailscale control server (WireGuard mesh VPN) | headscale |
|
|
| `obsidian` | CouchDB sync backend for the Obsidian LiveSync plugin | obsidian |
|
|
| `pulsenode` | Infrastructure dashboard - monitors all the stacks above | pulsenode |
|
|
|
|
## Config files
|
|
|
|
| File | Description |
|
|
|---|---|
|
|
| `.env` | Root config: `WEBHOOK_URL`, `RESTIC_REPOSITORY`, `RESTIC_PASSWORD` (gitignored) |
|
|
| `.env.example` | Template for the root `.env` |
|
|
|
|
## Management
|
|
|
|
Stacks are managed via `stacks.sh` from [git@dev.pivoine.art:valknar/scripts.git](ssh://git@dev.pivoine.art/valknar/scripts.git), available as `stacks` in PATH.
|
|
|
|
**Stack commands** — all accept one or more stack names or glob patterns (omit for all stacks):
|
|
|
|
```bash
|
|
stacks ls # list all stacks with live container status
|
|
stacks ps gitea # container status table
|
|
stacks up # start all stacks
|
|
stacks up gitea traefik # start specific stacks
|
|
stacks down 'g*' # stop stacks matching glob
|
|
stacks restart 'g*,traefik' # glob + exact name, comma-separated
|
|
stacks pull --parallel # pull all images in parallel
|
|
stacks logs -f gitea # follow logs
|
|
stacks logs -n 100 gitea n8n # tail multiple stacks
|
|
stacks exec gitea gitea gitea admin user list # exec in container
|
|
stacks run passbolt passbolt bin/cake passbolt healthcheck
|
|
```
|
|
|
|
**Service management** (reads `WEBHOOK_URL`, `RESTIC_REPOSITORY`, `RESTIC_PASSWORD` from root `.env`):
|
|
|
|
```bash
|
|
stacks update install # write & enable systemd update timer
|
|
stacks update run # run update now
|
|
stacks update status # show timer/service status
|
|
stacks update logs # show journal logs
|
|
|
|
stacks backup install # write & enable systemd backup timer
|
|
stacks backup run # run backup now (auto-detects <stack>_db containers)
|
|
stacks backup snapshots # list restic snapshots
|
|
```
|
|
|
|
**Scaffold a new stack:**
|
|
|
|
```bash
|
|
stacks new myapp # basic stack with Traefik labels
|
|
stacks new myapp --db postgres # with Postgres service
|
|
stacks new myapp --db postgres --redis # with Postgres + Redis
|
|
stacks new myapp --no-traefik # expose port instead of Traefik
|
|
```
|
|
|
|
Generates `compose.yml` (with healthchecks, `../.data/` volumes, Traefik labels) and `.env.example`.
|
|
|
|
**Global flags:** `--dry-run`, `--parallel`, `--verbose`, `--quiet`
|
|
|
|
## Deployment
|
|
|
|
```bash
|
|
# 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 'stacks up <stack>'
|
|
```
|
|
|
|
## Network
|
|
|
|
All stacks share the external `falcon_network` Docker network for inter-service communication (e.g. traefik routing, mailpit SMTP).
|
|
|
|
## Backup
|
|
|
|
Runs daily at 3:00 AM via a systemd timer. Detects Postgres databases automatically by convention (`<stack>_db` container, user `<stack>`, database `<stack>`), dumps each one, then runs a full restic backup of `.data/`. Retention: 7 daily, 4 weekly, 6 monthly. Notifications go to Telegram via n8n.
|
|
|
|
```bash
|
|
# First-time setup on VPS
|
|
cp .env.example .env && $EDITOR .env # set RESTIC_REPOSITORY, RESTIC_PASSWORD, WEBHOOK_URL
|
|
source .env && restic init # initialise restic repo
|
|
|
|
stacks backup install # write & enable systemd unit + timer
|
|
stacks backup run # test run
|
|
stacks backup snapshots # list snapshots
|
|
stacks backup status # timer/service status
|
|
stacks backup logs # journald logs
|
|
```
|
|
|
|
## Updates
|
|
|
|
Runs nightly at 2:00 AM via a systemd timer. Pulls the latest image for every stack, recreates any container whose image changed, prunes dangling images, and sends a Telegram notification via n8n.
|
|
|
|
```bash
|
|
stacks update install # write & enable systemd unit + timer
|
|
stacks update run # test run
|
|
stacks update status # timer/service status
|
|
stacks update logs # journald logs
|
|
```
|
|
|
|
## Notifications
|
|
|
|
Both update and backup POST to an n8n webhook on completion, which forwards the message to Telegram.
|
|
|
|
The webhook URL is set via `WEBHOOK_URL` in the root `.env`. Both services point to the same n8n workflow at `https://n8n.pivoine.art`, which accepts `{ "message": "...", "color": "..." }` 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.
|