
Workflow Automation with n8n
The cluster can reason, orchestrate, and generate media. But most real work is a chain of steps — fetch from an API, transform, call an Large Language ModelA model trained to predict text, served behind a chat or completion endpoint. On Frank these run locally on the GPU node rather than against a hosted provider., post the result, repeat on a schedule. That is workflow automation.
n8n is an open-source workflow automation platform with 400+ integrations, a visual node editor, and a webhook system. It runs as a single Node.js process backed by PostgreSQL.
flowchart LR
subgraph Authentik[Authentik — Forward Auth Proxy]
BP[Blueprint ConfigMap<br/>forward_single proxy]
end
subgraph GPU1[gpu-1 — i9, 128GB RAM]
subgraph n8nInstance[n8n-01 — per-user instance]
n8n[n8n Deployment<br/>port 5678]
PVC[10Gi PVC<br/>Longhorn<br/>/home/node/.n8n]
end
DB[paperclip-db-postgresql<br/>Bitnami PostgreSQL<br/>5Gi Longhorn]
end
subgraph Network
LB[Service<br/>192.168.55.216:5678<br/>Cilium L2]
Metrics[Prometheus /metrics<br/>scraped by VMAgent → Grafana]
end
BP -->|forward-auth| n8n
n8n -->|DATABASE_URL| DB
n8n --> Metrics
LB --> n8n
Why Per-User Instances
n8n’s Community Edition does not support multi-user accounts with workflow isolation. Single Sign-OnOne login across many applications. On Frank, Authentik holds the session and Traefik asks it before forwarding a request. (OpenID ConnectAn identity layer on top of OAuth 2.0: it adds a token saying *who* the user is, not merely what the client may do. Frank's single sign-on speaks it, with Authentik as the provider./Security Assertion Markup LanguageThe XML-based single sign-on standard that predates OIDC. Still what many enterprise applications support, and only that.) is enterprise-only, gated behind a $400/month license. The pattern is simple: n8n-01, n8n-02, n8n-03 — each with its own namespace, PostgreSQL, PersistentVolumeClaimA Kubernetes request for durable storage. The pod names a claim and the storage layer — Longhorn on Frank — binds real disk behind it, so the data outlives the pod., and LoadBalancer IP. Adding an instance is a find-replace across ~6 files.
Why gpu-1
Not for the GPU — n8n does not request nvidia.com/gpu. gpu-1 has an i9 and 128GB RAM sitting mostly idle while Ollama and ComfyUI take turns with the RTX 5070. n8n tolerates the GPU taint but does not claim GPU resources.
Architecture
Two ArgoCD apps per instance:
| Component | Type | Purpose |
|---|---|---|
n8n-01 | Raw manifests | Deployment, Service (Load BalancerWhatever spreads traffic across backends and gives them one address. On Frank that is Cilium answering for an address on the LAN, not a cloud appliance.), PVC |
n8n-01-postgresql | Bitnami Helm chart | Standalone PostgreSQL, Longhorn storage |
Authentication: The OIDC Detour
n8n Community Edition gates OIDC behind enterprise. A community project (n8n-oidc) injects OIDC via external hooks — but no commits in three months and open issues with zero maintainer response.
The solution: Authentik forward-auth proxy, same pattern as Longhorn, Hubble, and Sympozium. A blueprint ConfigMap in authentik-extras:
- model: authentik_providers_proxy.proxyprovider
identifiers:
name: n8n-01
attrs:
mode: forward_single
external_host: https://n8n-01.frank.derio.netThe Init Container That Wasn’t
The plan included an init container to bootstrap the admin account via n8n user:create. Community forums suggested this would work. It didn’t — n8n Community Edition has no user:create CLI command. The owner account must be created via the browser setup wizard on first access.
Secrets and Encryption
Three values in the Secrets OPerationSMozilla's tool for encrypting the *values* in a YAML file while leaving the keys readable, so an encrypted secret still reviews as a sensible diff.-encrypted secret secrets/n8n-01/n8n-01-secrets.yaml:
| Key | Purpose |
|---|---|
postgres-password | PostgreSQL admin password |
password | PostgreSQL n8n user password |
encryption-key | n8n credential encryption key |
The encryption-key is critical. n8n uses it to encrypt stored API credentials. Without it set explicitly, n8n auto-generates one on the filesystem — lose the PVC, lose all credentials.
Metrics
n8n exposes Prometheus metrics at /metrics with N8N_METRICS=true:
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "5678"
prometheus.io/path: "/metrics"VMAgent auto-discovers these and feeds execution counts, durations, error rates into VictoriaMetrics → Grafana.
Adding Instances
- Copy
apps/n8n-01/→apps/n8n-<NN>/, find-replacen8n-01→n8n-<NN> - Copy
apps/n8n-01-postgresql/→apps/n8n-<NN>-postgresql/, find-replace - Copy the 3 Application Custom ResourceAn object of a type Kubernetes did not ship with, added by a CRD. Frank's ArgoCD Applications, Rollouts and Tekton Pipelines are all CRs. templates, find-replace
- Pick next available IP from
192.168.55.2xxrange - Add proxy provider to
blueprints-proxy-providers.yaml - Create and encrypt
secrets/n8n-<NN>-secrets.yaml - Apply SOPS secret, commit, push
Missteps
| What Happened | Why It Was Wrong | How We Fixed It | Commit |
|---|---|---|---|
OIDC init planned but unworkable — n8n Community EditionThe free build of a product that also ships a paid one. Worth knowing which you are running: n8n CE has no SSO, and LiteLLM's CE image emits none of the Prometheus metrics its dashboards assume. has no user:create CLI command, OIDC is enterprise-only | Community forums suggested user:create CLI exists; it does not in CE | Switched to Authentik forward-auth proxy; removed init container | — |
| N8N_ENCRYPTION_KEY not set — auto-generated key stored on filesystem, all credentials unrecoverable on PVC loss | Default n8n behavior generates a key on first boot without persisting it explicitly | Added N8N_ENCRYPTION_KEY from SOPS secret | — |
| RollingUpdate deadlocks on ReadWriteOnceA PVC access mode that lets exactly one node mount the volume read-write at a time. It is the reason a RollingUpdate deadlocks: the replacement pod cannot mount the volume until the outgoing pod releases it. PVC — new pod cannot attach while old pod holds the claim | Default strategy creates new pod before terminating old one | Changed to Recreate strategy | — |
Recovery Path
| Symptom | Cause | Fix |
|---|---|---|
| Setup wizard appears on every access | User account not created | Complete wizard once per instance — or create via n8n API |
| “Invalid credentials” for stored API keys | N8N_ENCRYPTION_KEY changed — all encrypted creds invalid | Restore original encryption key from SOPS secret |
| n8n redirects to Authentik login loop | Forward-auth proxy misconfiguration | Check external_host in blueprint ConfigMap |
| Pod stuck CreateContainerConfigError | Missing SOPS secret not applied | Check kubectl get secrets -n n8n-01 |
References
- n8n documentation — Hosting, environment variables, community features
- Bitnami PostgreSQL chart
- Authentik proxy providers
