# 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://: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://: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:///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.