n8n/README.md
Travis Herbranson 51f50b4704 feat: add wiki-compile-nudge workflow + document it
Daily Google Chat nudge when wiki-vault is due for a compile (>=10 new
sources or >=7 days stale). Drift query against petalbrain; needs a
wiki.compile_runs table + post-import credential/webhook wiring.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-24 22:21:46 -04:00

122 lines
5.6 KiB
Markdown

# n8n
[n8n](https://n8n.io/) workflow automation deployment for the homelab.
Single-container stack with external persistent volume for workflows,
credentials, and execution history.
## Service
| Service | Image | Container | Host port |
|---------|------------------------------------|-----------|-----------|
| `n8n` | `docker.n8n.io/n8nio/n8n:latest` | `n8n` | 5678 |
n8n is reached at `http://<host>:5678/` (or via the Traefik path-prefix
route — see "Routing" below). Webhooks fire to `WEBHOOK_URL` per
`.env`.
## Run it
```bash
docker compose up -d
docker compose logs -f n8n
```
## Configuration — `.env`-driven
All knobs are in `.env` (gitignored). Required keys (names only — values
live in the file on the host):
| Key | Purpose |
|--------------------------------|---------------------------------------------------------|
| `N8N_HOST` | Public hostname (Tailscale magic-DNS in this homelab) |
| `N8N_PORT` | Listen port (5678) |
| `N8N_PROTOCOL` | `https` when fronted by Traefik / Tailscale |
| `N8N_PATH` | URL path prefix (`/n8n/` when using the Traefik route) |
| `GENERIC_TIMEZONE` | e.g. `America/New_York` |
| `N8N_SECURE_COOKIE` | `true` for HTTPS-fronted deployments |
| `N8N_BASIC_AUTH_ACTIVE` | `true` / `false` |
| `N8N_BASIC_AUTH_USER` | Basic-auth username |
| `N8N_BASIC_AUTH_PASSWORD` | Basic-auth password (rotate via .env, not via UI) |
| `WEBHOOK_URL` | Outward-facing webhook base (must match real ingress) |
| `PBS_*` | Workflow-side integration creds (Google Chat, Portainer, monitor base URLs, healer webhook) |
Rotate any of these by editing `.env` and restarting:
`docker compose up -d` (compose will recreate the container).
**Never commit `.env`** — it's listed in `.gitignore` for this reason.
If you need a checked-in template, create `.env.example` with the keys
but no values.
## Workflows (version-controlled here)
Importable workflow JSON lives in `workflows/`. The live workflows are
stored in the n8n volume; these files are the reviewable, git-tracked
source. Import via the UI (Workflows → Import from File) or
`POST /api/v1/workflows` with an `X-N8N-API-KEY` header.
| File | Purpose |
|-----------------------------------|----------------------------------------------------------------|
| `workflows/wiki-compile-nudge.json` | Daily check that nudges Google Chat when the wiki-vault is due for a compile (≥10 new sources, or ≥7 days stale). Schedule → Postgres drift query against `petalbrain` → IF → Google Chat HTTP POST. |
**`wiki-compile-nudge` — before it runs:**
- Fill two placeholders after import: the **Postgres credential** (select
the existing `petalbrain` cred) and the **Google Chat space webhook URL**
in the HTTP node.
- Depends on a `wiki.compile_runs` table in `petalbrain`
(`id bigserial`, `compiled_at timestamptz default now()`) and the
wiki-maintenance compile writing a row to it on each run — the drift
query reads `max(compiled_at)` as its "last compile" baseline.
- The drift logic is in SQL (returns a `should_notify` boolean), so the
IF node just checks that flag.
## Persistence — external volume
```
volumes:
n8n_data:
name: n8n_server_n8n_data
external: true
```
The volume is **external** with an explicit `name:` (`n8n_server_n8n_data`)
that pins it to the data originally created by a prior compose stack
called `n8n_server`. Don't remove the `name:` override — Docker would
create a new empty volume and n8n would boot with no workflows,
credentials, or history.
Backup: `docker run --rm -v n8n_server_n8n_data:/data -v $PWD:/backup
alpine tar czf /backup/n8n-backup-$(date +%F).tgz -C /data .`
## Routing (homelab-specific)
In this homelab, n8n is reachable two ways depending on which compose
state you're running:
- **Direct host port** (current working-copy default): browse to
`http://<host>:5678/`. Tailscale-only reachable because the host
itself is Tailscale-fronted.
- **Through Traefik** (committed state): path-prefix
`/n8n` on `us-test-authy.taila7f44e.ts.net`, with a separate
`/n8n/api` route that bypasses the Authelia middleware so API-key
clients don't double-auth. If you re-enable this, the container
needs to be on the external `traefik` network and the labels
block from the committed `compose.yml` should be restored.
## Gotchas
- **`:latest` image tag.** No pin. n8n minor releases occasionally
require workflow re-saves or credential re-entry; check release
notes before pulling.
- **`WEBHOOK_URL` must match ingress.** If you put n8n behind Traefik
at `/n8n/`, `WEBHOOK_URL` must be `https://<host>/n8n/` — n8n bakes
that URL into the webhooks it shows in the UI, so a mismatch
silently breaks third-party integrations even though the workflow
page looks right.
- **The basic-auth password lives in `.env`.** Don't change it through
the UI — there's nothing to change in the UI; it's enforced by the
HTTP layer from `N8N_BASIC_AUTH_PASSWORD`.
- **Don't commit `.env`.** Contains real PBS integration credentials
(Portainer API key, Google Chat webhook, healer webhook). The
`.gitignore` already excludes it; keep it that way.