Self-Host n8n and Ship a Production AI Ops Agent
Stand up n8n on a VPS with HTTPS, connect Slack and CRM, ship a read-first AI ops agent, then gate writes with human approval.
- Time needed
- 2–3 hours
- Sections
- 14
- Level
- Intermediate
What you will have live
By the end of this playbook you will have:
- A self-hosted n8n instance on a VPS, reachable only over HTTPS on your own subdomain
- Credentials stored in n8n (not in chat logs), with a durable encryption key backed up offline
- One working AI Ops Agent workflow: Slack (or Telegram) question → agent uses tools → posts a useful ops result (CRM lookup or Slack summary)
- A production harden pass: secrets, HTTPS, backups, permissions, and a human approval gate before any CRM write
Prerequisites
Gather these before you start:
- VPS — Ubuntu 22.04 or 24.04, 2 GB RAM minimum (4 GB comfortable), 20+ GB disk, public IPv4. Hetzner, DigitalOcean, Contabo, Linode all work.
- Domain you control — you will create
n8n.yourdomain.com(A record → VPS IP). - SSH access as a sudo user.
- Docker Engine + Docker Compose plugin on the VPS (install steps below if missing).
- Accounts for the first business outcome: Slack workspace (or Telegram bot) where ops lives; CRM you already use (HubSpot, Pipedrive, or Salesforce) or a Google Sheet stand-in for week one; an LLM API key (OpenAI, Anthropic, or another provider n8n’s LLM nodes support).
- A password manager — you will store: VPS root/user password, n8n owner password,
N8N_ENCRYPTION_KEY, DB password (if you add Postgres later), API keys.
Step 1 — Point DNS at the VPS
- In your DNS provider, create an A record:
- Name:
n8n(or the subdomain you prefer) - Value: your VPS public IPv4
- TTL: 300 (or Auto)
- Wait until
dig +short n8n.yourdomain.comreturns the VPS IP from your laptop. - Open ports 80 and 443 on the VPS firewall (uFW / cloud security group). Do not expose
5678to the world — n8n stays on localhost; Traefik publishes HTTPS.
Step 2 — Install Docker on the VPS
SSH in, then:
sudo apt update && sudo apt install -y ca-certificates curl
# Follow Docker’s current Engine install for Ubuntu, then:
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
docker --version
docker compose version
Optional: add your user to the docker group so you can run compose without sudo every time (usermod -aG docker $USER, then re-login).
Step 3 — Create the official n8n Compose stack (HTTPS)
n8n’s current production-shaped Docker Compose path uses Traefik for TLS and binds n8n to 127.0.0.1:5678. As of late September 2026, docs list stable ~2.40.x — pin or use the documented n8nio/n8n image tag your ops standard allows; prefer stable over beta.
mkdir -p ~/n8n-compose/local-files
cd ~/n8n-compose
Create .env (edit values):
DOMAIN_NAME=yourdomain.com
SUBDOMAIN=n8n
GENERIC_TIMEZONE=Asia/Karachi
SSL_EMAIL=you@yourdomain.com
Create compose.yaml from n8n’s Docker Compose guide — Traefik + n8n services, volumes n8n_data and traefik_data, WEBHOOK_URL=https://${SUBDOMAIN}.${DOMAIN_NAME}/, N8N_PROTOCOL=https, port bind 127.0.0.1:5678:5678.
Add an encryption key before first start (critical):
# Generate once; store in password manager AND in .env
openssl rand -hex 32
Add to .env:
N8N_ENCRYPTION_KEY=paste_the_hex_here
And under the n8n service environment: in compose:
- N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY}
Start:
docker compose up -d
docker compose ps
Open https://n8n.yourdomain.com. Create the owner account (first user = admin). Save that password in your vault.
Step 4 — Lock the owner account and basic settings
In n8n:
- Settings → Users — invite only people who should edit workflows. Prefer SSO later; for day one, strong unique passwords.
- Confirm the instance URL and webhook URL match HTTPS (Settings / environment already set
WEBHOOK_URL). - Enable execution pruning (Settings → Executions) so disk does not fill with old runs — e.g. keep successful executions 7–14 days, errors longer if you triage.
- Do not paste API keys into sticky notes or Slack. Use Credentials objects only.
Step 5 — Connect LLM + Slack (or Telegram)
LLM credential
- Credentials → add your provider (OpenAI / Anthropic / etc.).
- Name it clearly:
prod-openai-ops— nevertest. - Restrict who can use the credential if your plan/RBAC allows.
Slack
- Create a Slack app (or use n8n’s Slack credential OAuth flow).
- Scopes typically needed for ops bots: post messages, read channels you choose, and (if using slash commands/events) event subscriptions pointing at your HTTPS webhook URL.
- Install to the workspace; invite the bot to
#opsor#revops. - Save the Slack credential in n8n.
Telegram alternative: create a bot via BotFather, paste the token into n8n’s Telegram credential, and use a Telegram Trigger.
Step 6 — Ship the first AI Ops Agent (read-only CRM outcome)
Goal: an ops person asks in Slack: “What’s the stage and owner for deal Acme?” The agent looks it up and replies in-thread. No writes yet.
Workflow shape
- Trigger — Slack Trigger (app mention or slash command) or Chat Trigger for a quick smoke test.
- AI Agent node — system message that states:
- You are an internal ops assistant for COMPANY.
- You may read CRM / sheets tools.
- You must not invent deal stages; if lookup fails, say so.
- Keep answers short; cite the record id.
- Chat Model — attach your LLM credential.
- Memory (optional) — Window Buffer Memory for short threads.
- Tools (read-only first):
- HubSpot / Pipedrive / Salesforce Get or Search nodes as Agent tools, or
- Google Sheets tool limited to a “Deals mirror” tab if CRM OAuth is blocked this week.
- Reply — Slack node posts the agent’s final text back to the thread.
Smoke test
- Activate the workflow.
- From Slack, mention the bot with a real deal name that exists.
- Confirm: correct stage/owner, no hallucinated fields.
- In n8n Executions, open the run — every tool call should show real parameters.
Step 7 — Add a safe write path (HITL before CRM updates)
When you are ready for writes (e.g. “Log that Acme asked for a quote”):
- Add a CRM Update / Create note tool.
- In the Agent’s tool connector, add a Human review (HITL) step for that write tool (Slack / Gmail / Teams / n8n Chat — see n8n’s Human-in-the-loop for tools docs).
- Wire: Agent → HITL review → Write tool on the
ai_toolpath. The agent still “sees” the write tool’s name/schema; the review node intercepts execution. - Approval message must show actual parameters (deal id, fields to change) — not a model paraphrase.
- Set
limitWaitTimeexplicitly (e.g. 1–4 hours in seconds). Do not leave unbounded waits in production queues. - Deny path: agent should acknowledge “update not applied” and suggest a human follow-up.
Step 8 — Production harden
Run this checklist before you call the agent “production”:
| Area | Action |
|---|---|
| Secrets | All keys in n8n Credentials; N8N_ENCRYPTION_KEY in vault + .env; no keys in workflow static fields |
| HTTPS | Only https://n8n… works; HTTP redirects; 5678 not public |
| Access | Owner + named editors only; remove unused users |
| Backups | Nightly backup of Docker volume n8n_data (and Postgres if you migrate); test restore on a second folder monthly |
| Updates | Pin image tags; read release notes; stage upgrades on a Friday morning, not month-end close |
| Permissions | CRM credentials use least privilege (read-only integration user until HITL writes are proven) |
| HITL | Every tool with side effects (email send, CRM write, refund, ticket close) goes through Human review |
| Observability | Failed executions → Slack #n8n-alerts; prune old successes |
| Timezone | GENERIC_TIMEZONE matches the ops team (e.g. Asia/Karachi) |
Go-live checklist
- [ ]
https://n8n.yourdomain.comloads with valid cert - [ ] Owner MFA/strong password stored in vault
- [ ]
N8N_ENCRYPTION_KEYbacked up offline - [ ] Slack/Telegram bot responds in the intended channel only
- [ ] Read-only CRM (or Sheet) lookup succeeds on 3 real records
- [ ] Write tool blocked until HITL approve; deny leaves CRM unchanged
- [ ] Backup job ran once and a file exists off-box
- [ ] At least one other human can open Executions and revoke credentials
- [ ] Runbook link pasted in
#ops(this playbook URL + who owns the VPS)
Pitfalls
- Exposing port 5678 — bots and scanners will find it. Always reverse-proxy; bind localhost only.
- Losing the encryption key — credentials become permanent garbage. Backup the key the same day you create it.
- SQLite on a tiny disk with no pruning — disk full → silent outage. Prune executions and monitor disk.
- Webhook URL still http:// — Slack events fail randomly. Force HTTPS + matching
WEBHOOK_URL. - Agent writes without HITL — one bad tool call updates the wrong deal. Gate writes from day one.
- Shared “god mode” CRM token — use a dedicated integration user with minimum scopes.
- Beta image in production — prefer documented stable; schedule upgrades.
FAQ
n8n Cloud
Can I use n8n Cloud instead?
Yes. Skip Steps 1–3; still do credentials discipline, HITL on writes, and the go-live checklist. Self-host when you need data residency, custom networking, or cost control at volume.
Cloudflare
Do I need Cloudflare?
Not required. Traefik + Let’s Encrypt is enough. Cloudflare helps if you want WAF/CDN in front; configure SSL mode so you do not break Traefik’s cert flow.
Model Choice
What model should I use?
Start with a current mid-tier model your budget allows. Optimize later; reliability of tools + HITL matters more than model brand for ops lookups.
Next step
When this agent is live and gated, deepen approvals with Production Approvals: n8n Human-in-the-Loop Tool Gates, or connect a chat brain on top via OpenClaw + n8n over MCP.
Governed Handoff
Need a governed CRM/ERP handoff designed for your stack? See Solutions and Architecture, or contact Octacer.
Keep going
More playbooks
Want it running on your stack?
We implement this playbook for clients — tailored to your stack, your data, and your team's workflow, and handed over documented.