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:
parent
61b685ed3b
commit
04c995d271
101
README.md
101
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://<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.
|
||||||
Loading…
Reference in New Issue
Block a user