Phase 83 — n8n Workflow Automation
Deployed: 2026-08-01 | Version: n8n 2.32.7 | Namespace: automation
n8n is a self-hosted workflow automation platform — like Zapier or Make, but running entirely on the cluster. Workflows connect internal services (Plane, NATS, Stalwart mail, ERPNext, Backstage) and external APIs without sending data off-platform.
Three orchestration shapes — n8n vs Temporal vs Airflow
These are not competitors — they are three different shapes of orchestration, chosen by the nature of the work, not preference. Picking the wrong one is the common mistake.
| n8n (live) | Temporal (live) | Airflow (deferred, #153) | |
|---|---|---|---|
| Shape | event-driven integration | durable stateful workflow | scheduled batch DAG |
| Trigger | an event/webhook happens | a business process must run to completion | a clock (cron / interval) |
| Built by | anyone, visual UI (low-code) | developers, in code (Go/TS/Py) | developers, Python DAGs |
| Durability | best-effort + per-step retry | deterministic replay — survives crashes, resumes exactly, runs for days/months, saga/compensation | task-level retry within a run |
| Reach for it when… | "when X happens, call Y and Z across APIs, retry/alert on failure" — glue, human-editable | the process is long-lived and must not lose state / must guarantee completion (e.g. claims-settlement saga: reserve → approve → SEPA payout → accounting → notify, rollback on failure) | time-driven data/ML pipelines ("run the dbt transform nightly at 02:00") |
| On this cluster | integration glue: premium-collection lifecycle, SEPA/Stripe webhooks, notifications | durable workflows: MAAS node power-dispatch/provisioning; the intended home for long insurance sagas | none yet — the analytical data platform (ClickHouse→dbt→BI) isn't built, so nothing needs cron DAGs; Airflow earns its place when it is |
Litmus test: reactive glue → n8n; a transaction that must survive failure and complete → Temporal; a scheduled pipeline over data → Airflow. Two orchestrators are live (n8n + Temporal, each with a distinct role); the third is deferred until its use case (scheduled data pipelines) becomes real — see Temporal and Airflow.
Architecture
https://n8n.devandre.sbs
│
Cloudflare Tunnel
│
ingress-nginx
│ (Authentik forward auth — nginx snippet pattern)
▼
n8n Deployment (automation ns)
│ SQLite on Longhorn 5Gi RWO PVC
│ Encryption key from Vault
▼
/webhook/ /webhook-test/ ← separate ingress, no auth
(for Plane/NATS/external triggers)
| Component | Detail |
|---|---|
| Image | docker.io/n8nio/n8n:2.32.7 |
| Database | SQLite on Longhorn RWO PVC (/home/node/.n8n) |
| Storage | n8n-data PVC, 5Gi, longhorn StorageClass |
| Auth | Authentik forward auth (proxy provider pk 17, forward_single) |
| Webhooks | /webhook/ and /webhook-test/ bypass Authentik (separate ingress) |
| TLS | cert-manager, ClusterIssuer minicloud-ca |
| Secrets | ESO → platform/n8n.encryption_key, platform/mail.smtp-relay-password |
| SMTP | Stalwart (stalwart.mail.svc.cluster.local:587), sender n8n@devandre.sbs |
| Timezone | Europe/Paris |
GitOps layout
manifests/n8n/
├── 00-namespace.yaml # automation namespace
├── 01-externalsecret.yaml # Vault → n8n-credentials secret
├── 02-pvc.yaml # 5Gi Longhorn RWO
├── 03-deployment.yaml # n8n Deployment
├── 04-service.yaml # ClusterIP :5678
├── 05-ingress.yaml # main (Authentik) + webhook (open)
└── 06-certificate.yaml # cert-manager TLS
apps/n8n.yaml # ArgoCD Application
Access
| URL | Auth |
|---|---|
https://n8n.devandre.sbs | Authentik OIDC (kanmegnea + TOTP) → n8n login |
https://n8n.10.0.0.200.nip.io | Internal only (requires Tailscale) |
Owner account: kanmegnea@gmail.com (set at first deploy via /rest/owner/setup).
Deployment gotchas
1. Gatekeeper policy violations
The cluster's OPA Gatekeeper enforces constraints that n8n's default pod spec violates:
| Policy | Fix |
|---|---|
require-non-root | securityContext.runAsNonRoot: true, runAsUser: 1000 |
no-privilege-escalation | securityContext.allowPrivilegeEscalation: false |
block-net-raw | securityContext.capabilities.drop: [NET_RAW] |
require-resource-limits | resources.limits.cpu: 1000m |
2. Node.js OOM at 512Mi
n8n requires at least 1 GB RAM. The V8 heap exhausted at 512Mi:
FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory
Fix: memory limit 1.5Gi + NODE_OPTIONS=--max-old-space-size=1024.
3. Cloudflare tunnel requires a config.yml entry
cloudflared tunnel route dns creates the DNS CNAME but does not add the ingress rule. Every new public hostname needs a manual entry in ~/.cloudflared/config.yml:
- hostname: n8n.devandre.sbs
service: https://10.0.0.200
originRequest:
noTLSVerify: true
originServerName: n8n.10.0.0.200.nip.io
Restart: pkill -f 'cloudflared tunnel' && nohup ~/.local/bin/cloudflared tunnel --config ~/.cloudflared/config.yml run >> ~/.cloudflared/cloudflared.log 2>&1 &
Authentik provider (rebuild reference)
# Create proxy provider (forward_single)
curl -X POST https://auth.devandre.sbs/api/v3/providers/proxy/ \
-H "Authorization: Bearer $AK_TOKEN" -H "Content-Type: application/json" \
-d '{
"name":"n8n-forward-auth",
"authorization_flow":"3cb61a3d-47ba-47ac-bf32-b270179bb735",
"invalidation_flow":"2c1cd937-5a93-4e36-b9df-96839a9e3e05",
"external_host":"https://n8n.devandre.sbs",
"mode":"forward_single",
"property_mappings":["35c5c354-c9ce-4942-a919-43208923127f","06730f5f-cf59-4227-afe7-7fdf9dc113ba","d4967c11-acbe-4ae6-80c0-4b45c0fcf95b","677d145c-2abe-407e-9e5f-e425b65a8740","6e52eb60-9e8c-4684-be85-6cf79e894a01"],
"token_validity":"hours=24"}'
# → note the returned pk, then:
curl -X POST https://auth.devandre.sbs/api/v3/core/applications/ \
-d '{"name":"n8n","slug":"n8n","provider":<pk>,"meta_launch_url":"https://n8n.devandre.sbs"}'
# Add provider pk to embedded outpost providers list
curl -X PATCH https://auth.devandre.sbs/api/v3/outposts/instances/93d11dbf-e7fe-4604-afb1-7269980a5b47/ \
-d '{"providers":[1,8,15,<pk>]}'
Use cases on this platform
- Plane → Stalwart: email notifications for issue state transitions
- ERPNext webhooks → NATS: publish HR events to the messaging bus
- Monitoring alerts → custom logic: route Alertmanager webhooks beyond Slack
- Scheduled exports: pull ERPNext/Plane data, format, send via Stalwart
Real-world skills demonstrated
| Skill | Industry context |
|---|---|
| Self-hosted workflow automation | Replaces SaaS tools (Zapier, Make) for compliance-sensitive data |
| Authentik nginx forward auth | Standard proxy-auth pattern for internal tools without native OIDC |
| Separate webhook ingress | Protect UI, expose API surface — same shape as Stripe/GitHub webhook receivers |
| Gatekeeper policy compliance | Enforcing non-root, no NET_RAW, resource limits on third-party images |
| Vault-backed secrets at deploy | Encryption key injected from Vault — no plaintext in gitops |