From 04c995d2719d00a4545e362f2872720756c81eb7 Mon Sep 17 00:00:00 2001 From: Travis Herbranson Date: Wed, 20 May 2026 07:51:41 -0400 Subject: [PATCH] docs: write operator README MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Repo had a 0-byte README. New one covers: - Single-service inventory + host port - .env-driven config table (keys ONLY — no values; .env stays gitignored, contains real PBS integration credentials) - External volume pin to n8n_server_n8n_data (don't remove the name: override; would create an empty volume) - Backup one-liner via volume tar - Two routing modes (direct host port vs Traefik /n8n + /n8n/api) matching the current dirty compose.yml situation - WEBHOOK_URL-must-match-ingress + :latest-image-tag gotchas Working tree has uncommitted changes to .env and compose.yml. NEITHER is part of this commit — verified pre-commit. Co-Authored-By: Claude Opus 4.7 (1M context) --- README.md | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/README.md b/README.md index e69de29..52ee135 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,101 @@ +# 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. + +## 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. +- The repo also contains some leftover uv-init artifacts (`main.py`, + `pyproject.toml`, `uv.lock`, `.python-version`). These are not part + of the deployment.