blog.back_article_list

n8n AI agent setup on a VPS: OpenAI, Anthropic and Ollama

n8n AI agent setup on a VPS: OpenAI, Anthropic and Ollama

Where does the text go when your n8n workflow calls a model? For a hosted model it goes to OpenAI or Anthropic over HTTPS and comes back with a bill measured in tokens. For a local model it goes to an Ollama container on the same server, or on a GPU server next door, and never leaves your network. That single decision shapes the rest of an AI workflow in n8n, so this guide covers both routes and the nodes that are the same either way: the AI Agent node, the chat model sub-nodes, memory, tools, output parsers, vector stores and the MCP nodes. All of it is current for n8n 2.38.

The AI Agent node and its sub-nodes

The AI Agent node is a root node. On its own it does nothing; it needs a chat model sub-node connected, at least one tool sub-node and optionally a memory sub-node plus an output parser. Older versions of the node had a dropdown of agent types (Conversational, ReAct, SQL Agent, OpenAI Functions, Plan and Execute) and those are gone: every AI Agent node now behaves as the Tools Agent, and the legacy v1 node with its modes will be removed in n8n 3.0 this October. If you still have workflows on the old node, open them and move to the current node version before October.

The prompt comes from a connected Chat Trigger node or from an expression you define in the node. Under Options you get System Message, Max Iterations, Return Intermediate Steps, Tracing Metadata, Automatically Passthrough Binary Images and Enable Streaming, and the AI Agent node docs list everything else the node accepts. I set Max Iterations to 5 on every agent that runs unattended, because the one time I left it at the default a broken tool description sent an agent round in circles for 14 calls to a paid model before it gave up. Five is enough for any tool chain I've built; if an agent needs more, the tools are cut wrong.

Chat model sub-nodes: OpenAI, Anthropic, Gemini, OpenRouter and Ollama

Each provider is a separate sub-node that plugs into the same socket on the agent: OpenAI Chat Model, Anthropic Chat Model, Google Gemini Chat Model, OpenRouter Chat Model, Ollama Chat Model, plus Azure OpenAI, DeepSeek, Perplexity and a few more. The credential holds the API key. Swapping providers means dragging a different sub-node onto the connection, nothing in the agent changes.

Options differ slightly per node. OpenAI Chat Model has Frequency Penalty, Maximum Number of Tokens, Presence Penalty, Sampling Temperature, Timeout, Max Retries and Top P. Anthropic Chat Model has Maximum Number of Tokens, Sampling Temperature, Top K, Top P and a Prompt Caching option that caches the system prompt and conversation history on Anthropic's side, which is the setting to turn on for any agent with a long system message. Ollama Chat Model has Sampling Temperature, Top K and Top P.

Model names change faster than this page will, so pick the current mid-tier Claude or GPT model from the dropdown for anything that has to reason over tools and the cheapest one for routing and classification. The dropdown is populated from the provider's API.

Run Ollama next to n8n in Docker

Ollama listens on port 11434 and the Ollama credential in n8n defaults its Base URL to http://localhost:11434. That default is wrong the moment n8n runs in a container, because localhost inside the container is the container. Two layouts work.

Ollama on the host, n8n in Docker

Set the credential's Base URL to http://host.docker.internal:11434. On Linux that hostname doesn't exist by default, so add it to the n8n service in your compose file:

services:
  n8n:
    image: n8nio/n8n:2.38.5
    extra_hosts:
      - "host.docker.internal:host-gateway"

Ollama on the host also has to listen on more than the loopback interface, which means starting it with OLLAMA_HOST=0.0.0.0. The Ollama Chat Model common issues page has the same two steps in the same order, and it's the page I send people to when the credential test fails with a connection refused. Docker Desktop on a laptop maps the host on its own, which is why the same credential works locally and fails on the server.

Ollama as a compose service

Add an ollama service to the same compose project and use the service name as the host in the Base URL: http://ollama:11434. Docker's internal DNS resolves it and nothing is published to the internet. Pull models with docker compose exec ollama ollama pull <model> and give the service a named volume so the pulled weights survive a recreate. On a GPU server you also install the NVIDIA container toolkit and hand the GPU to the ollama service in the compose file; the Ollama Docker docs cover that block and it's four lines.

CPU or GPU for a local model

A 7B or 8B model quantised to 4 bits loads in about 5 GB of RAM and runs on a CPU-only VPS at a few tokens per second on 4 vCPUs, which is fine for a nightly classification job and painful for a chat. The same model on a GPU VPS answers in a second or two. My rule is CPU for batch work that nobody waits on, GPU the moment a human sits at the other end of a Chat Trigger. There's an Ollama VPS template if you want the runtime pre-installed instead of adding the service yourself.

Memory: Simple Memory doesn't work in queue mode

Simple Memory keeps the conversation in the n8n process. The docs are blunt about the limit: "Don't use this node if running n8n in queue mode. If your n8n instance uses queue mode, this node doesn't work in an active production workflow." A worker picks up the next message with no memory of the previous one, and the agent looks like it has amnesia. It's fine on a single-process instance and in the editor.

Postgres Chat Memory and Redis Chat Memory store the history in a database both mains and workers can see. Postgres Chat Memory takes a Session Key, a Table Name (it creates the table if it's missing) and a Context Window Length for how many previous turns to include. Since a production instance should already be on Postgres, I default to Postgres Chat Memory everywhere and skip Simple Memory outside testing, then the move to n8n queue mode with workers changes nothing in the AI workflows. Multiple memory nodes in one workflow share the same store unless their session IDs differ, per the docs, so give each agent its own key.

Tools: HTTP Request, Custom Code Tool, Call n8n Workflow Tool and AI Agent Tool

The HTTP Request node connects to an agent as a tool directly, and it has an "Optimize Response" option for that use that strips a JSON or HTML response down before the model sees it. Custom Code Tool runs a JavaScript or Python function and exposes the tool's input as query. Call n8n Workflow Tool hands the call to another workflow, with inputs the model fills in through $fromAI() expressions, and the docs carry a warning for it: with a Database source in production "the sub-workflow must be published. If it isn't, the tool call fails with the error Workflow is not active and cannot be executed." AI Agent Tool, added in 1.103, lets one agent call another agent as a tool, which is how you get an orchestrator with specialists underneath without a single 3,000-token system prompt.

Tool descriptions are the prompt for tool selection. A vague one ("gets data") is why agents loop.

Structured Output Parser and Require Specific Output Format

Turn on "Require Specific Output Format" on the agent and a parser socket appears. Structured Output Parser takes a Schema Type of either "Generate from JSON Example", where you paste a sample object, or "Define using JSON Schema", where you write the schema by hand ($ref isn't supported). The output then arrives as parsed JSON on the item, so the downstream Switch or Postgres node reads fields instead of regexing a string. This replaced the old habit of asking for JSON in the prompt and cleaning it up in a Code node, and I haven't written a JSON-repair snippet since.

Chat Trigger and the hosted chat page

Chat Trigger starts a workflow from a chat message. With "Make Chat Publicly Available" on, it serves a Hosted Chat page from your n8n instance or an Embedded Chat you place on your own site with n8n's widget, and authentication can be None, Basic Auth or n8n User Auth. The response mode includes a streaming option that needs the agent's Enable Streaming turned on. For an internal helpdesk bot I use Hosted Chat with n8n User Auth so only people with an n8n account can reach it.

RAG on a VPS: Simple Vector Store, Qdrant and PGVector

Every vector store node in n8n has the same four modes: "Get Many", "Insert Documents", "Retrieve Documents (As Vector Store for Chain/Tool)" and "Retrieve Documents (As Tool for AI Agent)". The last one plugs straight into an agent as a tool, which is the shortest path to a RAG agent: a Document loader and an embeddings sub-node on the insert side, the same embeddings sub-node on the retrieve side, done.

Simple Vector Store holds everything in memory. The docs say "This node stores data in memory only. All data is lost when n8n restarts and may also be purged in low-memory conditions," and two variables cap it: N8N_VECTOR_STORE_MAX_MEMORY in MB for all stores combined and N8N_VECTOR_STORE_TTL_HOURS for idle expiry. Development only.

For a small team on one VPS I use the PGVector Vector Store node against the same Postgres 17 that n8n runs on, with the pgvector extension enabled in that database. It has collection support (Use Collection, Collection Name, Collection Table Name) so several knowledge bases share one table. Qdrant Vector Store is the other option I'd run, as a compose service, when the vector data outgrows what I want inside the n8n database. I've only pushed PGVector to about 40,000 chunks on a 4 GB box, so where the index starts needing tuning above that is something I haven't measured.

Embeddings come from a matching sub-node: Embeddings OpenAI, Embeddings Ollama and others. Use the same one for insert and retrieve or the distances are meaningless.

MCP Server Trigger, MCP Client Tool and the instance-level MCP server

Three different things carry the MCP name in n8n and they get mixed up. MCP Server Trigger turns one workflow into an MCP server: the tools it exposes are the tool sub-nodes connected to it, transport is SSE or streamable HTTP (no stdio), auth is None, Bearer or Header, and the URL path is random. Behind nginx it needs proxy buffering off for its endpoint, and the docs suggest disabling gzip and setting the Connection header to an empty string; the n8n behind nginx guide has the location block. MCP Client Tool is the reverse, a tool sub-node that lets an agent call an external MCP server, with OAuth support since 1.119.

The instance-level MCP server is newer (settings layout from 2.33.0, agents support from 2.34.0) and it isn't a node at all. You enable it under Settings, then Instance-level MCP (the instance MCP server docs have the client configuration), the URL ends in /mcp-server/http, auth is OAuth or a personal access token as a Bearer, and it exposes workflow management and building tools to whatever MCP client you point at it, Claude Code included. Rate limit is 100 requests per 5 minutes by default. Disable it with N8N_DISABLED_MODULES=mcp if nobody uses it, which is what I do on instances that only run scheduled jobs.

Evaluations and what the community edition gets

Evaluations run a workflow against a dataset and score the output. The Evaluation Trigger reads test cases, the Evaluation node sets outputs and metrics, and built-in metrics have existed since 1.103. Metric-based evaluation is an Enterprise feature on self-hosted, with an exception: registered community instances can use it on one workflow. Parallel test cases are capped at 1 on community, 3 on Business and 5 on Enterprise via N8N_CONCURRENCY_EVALUATION_LIMIT. Register the instance (free, an email address) and spend that one slot on the agent that matters most.

n8n Agents (beta) and how they differ from the AI Agent node

n8n Agents, launched August 5, 2026, are a different object from the AI Agent node. An agent is set up once with a model, tools and knowledge, then reached from Slack, Telegram or Linear and from a workflow through the "Message an Agent" node. On self-hosted it's a beta from 2.32.3, turned on by adding agents to N8N_ENABLED_MODULES, and the docs say self-hosted Enterprise doesn't get it yet. Channels need a public webhook URL, and knowledge bases need a Daytona sandbox, which is a separate service. I've kept it off on production instances until it leaves beta.

Token costs on a self-hosted instance

Self-hosting removes the execution meter but not the token meter. What I do to keep the second one small: route with the cheapest model and reason with the mid-tier one, cap Maximum Number of Tokens on every chat model node, turn on Prompt Caching on Anthropic nodes with long system messages, trim the input in a Set node before the agent so it doesn't see forty fields it will never use and move any job that runs more than a few thousand times a day to a local model where the cost is the server you already pay for. Return Intermediate Steps stays off in production; it's a debugging setting that doubles the stored execution data.

Local models have a cost too, in RAM and in the hours you spend picking one. That's the trade.

Data residency: the reason AI workflows get self-hosted

A support triage agent reads every ticket. A document Q&A agent reads every document. On a hosted automation platform those texts pass through the platform and then through the model provider; on a self-hosted n8n with a local model they never leave the server, and with a hosted model they go to exactly one third party you chose and signed a data processing agreement with. That's the argument that gets AI workflows onto a VPS, and it's the one that holds up when a customer asks where their data went. The n8n GDPR guide goes through the subprocessor list and the retention settings; for this article the short version is that execution data from an agent run contains the prompt and the response, so set EXECUTIONS_DATA_SAVE_ON_SUCCESS=none on workflows that handle personal data and let pruning take care of the rest.

Automate faster, for less

Bring your winning ideas to life with AMD power, NVMe speed and unmetered bandwidth.