docs: write operator README

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) <noreply@anthropic.com>
This commit is contained in:
Travis Herbranson 2026-05-20 07:51:41 -04:00
parent 61b685ed3b
commit 04c995d271

101
README.md
View File

@ -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://<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.
## 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.
- The repo also contains some leftover uv-init artifacts (`main.py`,
`pyproject.toml`, `uv.lock`, `.python-version`). These are not part
of the deployment.