repo for storing the n8n-contents
Go to file
Travis Herbranson 4df0b9700f chore: remove uv-init leftover stub main.py
Untouched `uv init` placeholder (print("Hello from n8n!")). Not
imported, not wired as an entry point, and documented in this repo's
own README/CLAUDE.md as leftover scaffolding not on the build path.
2026-05-22 20:22:31 -04:00
.gitignore update to compose and ignore files 2026-05-22 18:42:41 -04:00
.python-version init commit to create the project 2026-05-13 18:46:03 -04:00
compose.yml update to compose and ignore files 2026-05-22 18:42:41 -04:00
pyproject.toml init commit to create the project 2026-05-13 18:46:03 -04:00
README.md docs: write operator README 2026-05-20 07:51:41 -04:00
uv.lock init commit to create the project 2026-05-13 18:46:03 -04:00

n8n

n8n 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

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.