A few months ago I hit a moment of clarity while watching my n8n monthly report: I had sent over 400,000 tokens to the OpenAI API in a single week β all of it from automation workflows that were classifying support tickets, summarizing webhook payloads, and extracting structured data from emails. The bill was not catastrophic, but the principle bothered me. All that internal data β project names, client details, error logs β leaving my infrastructure and going to a third-party server. I already had Ollama running locally on my Beelink for inference experiments. Why was I still routing automation traffic through the cloud?
That week I spent two evenings connecting n8n directly to my local Ollama instance. I've now been running this stack in production for about three months, and it has completely changed how I think about AI-powered automation. No API keys to rotate. No per-token costs on high-volume workflows. No data leaving my home lab. In this post I'm going to show you the exact setup I use β from the Ollama HTTP endpoint to the n8n workflow architecture β and the real limitations you'll hit along the way.
This is a tutorial for developers who are already comfortable with n8n basics and want to understand how to integrate a local Ollama model as the AI backbone of their workflows. If you're still getting your Ollama and Open WebUI stack off the ground, start with my Local AI on a Mini PC setup guide first, then come back here.
My Local AI Automation Stack: What's Running and Where
Before getting into the integration, let me describe the actual hardware so you have realistic expectations. My primary inference machine is a Beelink EQ12 Mini PC (~$189) running Proxmox VE 9. Inside Proxmox I have an LXC container dedicated to Ollama and another one running n8n as a Docker container. Both containers share the same internal bridge network, which is the key detail that makes low-latency local inference possible β the HTTP request from n8n to Ollama never leaves my physical server.
For RAM I upgraded to Crucial 32GB DDR4 (~$59), which is the minimum I'd recommend if you want to run anything larger than a 7B model comfortably while also keeping n8n, PostgreSQL, and a few other services alive. Proxmox is good at memory ballooning across LXC containers, but you need the headroom. For model storage I use a WD Black 2TB NVMe (~$129) passed through to the Proxmox host β Ollama model files are large and a fast drive genuinely matters for load times when switching between models.
On the software side: Ollama runs as a systemd service inside an Ubuntu 24.04 LXC container, exposed on http://<container-ip>:11434. n8n runs as a Docker container in a separate LXC, connected to the same Proxmox internal bridge. My primary models for automation tasks are llama3.1:8b for fast classification and extraction tasks, and qwen2.5:14b for anything that requires more reasoning. I do not use GPU passthrough on this box β the EQ12's Intel N100 handles 7-8B models at about 15-20 tokens/second on CPU, which is fast enough for async automation workflows where a 5-second response time is perfectly acceptable.
Getting n8n to Talk to Ollama: The HTTP Request Method
n8n has an official "Ollama" node as of version 1.x, but I actually prefer using the HTTP Request node directly. The reason is control: I can set the exact request body, handle streaming responses explicitly, and avoid the abstraction layer that occasionally hides useful error information. Here's the fundamental pattern I use in every Ollama-connected workflow.
Ollama exposes a REST API at /api/generate for single-turn completions and /api/chat for multi-turn conversations with message history. For automation workflows I almost always use /api/generate because each n8n execution is stateless β I'm not building a chatbot, I'm processing a payload and returning structured output. The request looks like this:
{
"model": "llama3.1:8b",
"prompt": "Classify the following support ticket into one of these categories: billing, technical, feature-request, other. Return only the category name, nothing else.\n\nTicket: {{ $json.ticket_body }}",
"stream": false,
"options": {
"temperature": 0.1,
"num_predict": 50
}
}
The critical settings here are "stream": false β which makes Ollama return the complete response as a single JSON object rather than a stream of chunks β and a low temperature for deterministic classification tasks. The num_predict cap prevents runaway generation when the model gets confused by an edge case input. In n8n, I configure the HTTP Request node as a POST to http://192.168.100.10:11434/api/generate (replace with your Ollama container's IP), with Content-Type set to application/json and the body set to the JSON above, using n8n's expression syntax to inject the incoming data.
One thing that tripped me up early: Ollama's response object wraps the actual text inside a response field. So in the downstream n8n node you need to access {{ $json.response }}, not {{ $json.text }} or {{ $json.content }} as you might expect from OpenAI-style APIs. I now keep a sticky note in every Ollama workflow reminding me of this β I have lost at least an hour total across different projects debugging this exact thing.
Building Your First Local LLM Workflow in n8n
Let me walk through a complete end-to-end workflow: automatically classifying and routing inbound webhook events from a GitHub repository. This is actually one I've had running for about six weeks now, processing issue-created and PR-opened webhooks from a private .NET project.
The workflow structure is: Webhook β Set node (format payload) β HTTP Request (Ollama) β Switch node (route by classification) β Slack/email notification. The Webhook node receives the GitHub payload. The Set node extracts the relevant fields β action, issue.title, issue.body β and formats a clean prompt string. The HTTP Request node sends that to Ollama and gets back a classification. The Switch node uses that classification to route to different notification channels.
Here's the prompt template I use in the Set node, which I then pass to Ollama:
// In n8n Set node expression:
`You are a GitHub issue classifier for a .NET/Angular web application.
Classify this issue into one of: [bug, feature, performance, docs, question].
Return ONLY the single word classification.
Title: ${$json.issue.title}
Body: ${$json.issue.body?.substring(0, 500) ?? 'No body provided'}
Classification:`
The substring(0, 500) guard is important β Ollama's context window is finite, and pasting entire issue bodies unconstrained can cause slow responses or context overflow on longer items. For my use case the first 500 characters of the body gives the model enough signal to classify accurately. I tested this against a month of historical issues and got about 89% classification accuracy with llama3.1:8b, which is good enough for routing notifications. Anything edge-case enough to be misclassified probably needs human review anyway.
Three Real Workflows I Run Every Day
The GitHub classifier is one example, but here are three production workflows from my own n8n instance that give you a sense of what's practical at home-lab scale.
Blog metadata extraction. I run a WordPress-adjacent publishing pipeline for my own site (gilricardo.com runs on a custom stack, not WordPress, but the principle applies). When I drop a new markdown draft into a watched folder, an n8n workflow picks it up via the File Trigger node, sends the first 800 words to Ollama with a prompt asking for a suggested slug, meta description, and five tags, and writes the result into a JSON sidecar file. I still review the suggestions before publishing, but the first draft of SEO metadata now takes about 12 seconds instead of 5 minutes of manual work. I use qwen2.5:14b for this task because the output quality on metadata is noticeably better than the 8B model for nuanced SEO copy.
Email triage and draft generation. This one is probably the most time-saving workflow I've built. A webhook from my email provider fires whenever I receive an email from a specific domain set (clients and leads). n8n passes the subject and first 600 characters to Ollama with a prompt that asks whether the email requires a response today, a response this week, or no response, and if a response is needed, drafts a one-paragraph reply based on context. The draft goes into a Notion database row tagged "needs-review." I open Notion in the morning, scan the drafts, and usually just clean up the AI output rather than writing from scratch. Total time savings: roughly 20 minutes daily.
n8n error log summarization. n8n has a built-in error workflow trigger. When any of my other workflows fail, I have a dedicated error-handler workflow that fires, grabs the execution error object, sends it to Ollama with a prompt asking for a plain-English explanation of what went wrong and what the most likely fix is, and sends that to my Telegram. This means I often know the root cause of a broken workflow before I even open the n8n editor. The model is surprisingly good at this β it recognizes common patterns like "expression references undefined field" or "HTTP 429 rate limit" and gives actionable context rather than just echoing the raw error message.
Choosing the Right Ollama Model for Automation Tasks
Not all models are equal for automation use cases. Over three months of testing I've settled on two models for most tasks, and I want to explain why so you can make your own informed choice rather than just copying my setup.
llama3.1:8b is my default for any task that requires fast turnaround and the output is a short, structured response: classification labels, yes/no decisions, entity extraction, short summarization. At 15-20 tokens/second on my N100 CPU, an 8B model can handle a response under 100 tokens in 5-7 seconds. That's fast enough for any async workflow. The 8B model is also small enough to coexist with other containers without causing memory pressure β it uses about 6GB of RAM when loaded.
qwen2.5:14b is my choice for tasks that require longer, higher-quality output: draft generation, complex summarization, anything where I'll be reading the result rather than just routing on it. It uses about 11GB of RAM and runs at roughly 8-10 tokens/second on my setup, so a 300-token response takes 30-35 seconds. That's fine for async workflows that run overnight or are triggered manually, but it's too slow for anything expected to respond in near-real-time. The quality improvement over 8B is real and consistent for prose generation tasks.
I stay away from anything larger than 14B on CPU-only inference for automation. It's not worth it β 32B and 70B models drop to 3-5 tokens/second, meaning a 500-token response takes over a minute. If you need that level of reasoning in a workflow, you're better off routing those specific steps to the Claude API as I describe in my n8n + Claude API automation guide. Speaking of which, you can mix Ollama and Claude in the same n8n workflow β some nodes hit Ollama for fast local tasks, others call the Claude API for tasks that need frontier-model reasoning. That hybrid architecture is what I use today.
Performance Reality Check: What to Expect from a Beelink Mini PC
I want to be honest about this because I've seen too many blog posts that imply you can run serious AI workloads on a $189 mini PC without caveats. You can run useful AI workflows β I do it every day β but there are real constraints.
CPU-only inference on the Intel N100 is useful for async automation but not for interactive applications. If you're building workflows that need to respond in under 2 seconds, you either need to use smaller models (3B or 4B parameter range), use a GPU-accelerated machine, or call a cloud API. My Beelink sits at 100% CPU during inference on an 8B model, which means if two workflows fire at the same time they'll queue. I haven't had a production failure from this, but I did have to add a concurrency limit to my n8n instance (EXECUTIONS_PROCESS=main and N8N_CONCURRENCY_PRODUCTION_LIMIT=2 in my Docker env) to prevent queue buildup during busy periods.
Thermal performance is fine β the EQ12's cooling is adequate for sustained CPU load. I've watched it run at 85-90% CPU for extended periods during model loading and inference without throttling. The fan does spin up audibly, which matters if the machine is in your living space. Mine is in a closet with the rest of my homelab gear, so it's not an issue. If you're on the fence about hardware, the Beelink is genuinely the right entry point. If you already know you'll want GPU inference in the future, plan for a machine with a discrete GPU from the start β upgrading to GPU passthrough later is more hassle than it sounds.
One more practical note: model cold-start time. When a model isn't loaded in memory, the first inference request triggers Ollama to load it from disk, which takes 10-30 seconds depending on model size. Ollama keeps models warm in memory after use (configurable via OLLAMA_KEEP_ALIVE β I set mine to 30 minutes). For automation workflows I pre-warm my primary models by sending a dummy request to Ollama in a scheduled n8n workflow every 20 minutes during business hours. It's a small hack but it eliminates the cold-start penalty entirely for my most-used models.
When to Use Ollama vs. Claude API in n8n
After running both in parallel for months, I've developed a mental framework for which tasks go where. I share this because the "local LLM vs. cloud API" question is often framed as an either/or binary, but in practice the answer is almost always "both, for different things."
Use Ollama locally when: the data is sensitive or internal (client names, proprietary code, personal information), the task is high-volume and predictable (classification, extraction, tagging), the response time requirements are relaxed (async workflows, batch processing), and the quality bar is achievable by a 7-14B model. These are the 80% of automation tasks that don't need frontier intelligence.
Use the Claude API when: you need the highest possible output quality for something a human will read (client-facing drafts, complex technical summaries), the task involves nuanced reasoning that smaller models consistently fail at, you need 100% reliability with no cold-start delays, or the workflow is low-volume enough that the cost is negligible. In my own setup, I still use Claude API for about 20% of my automation steps β the ones where output quality directly affects a business outcome. As I covered in my Claude API Tool Use Tutorial, the function-calling capabilities also go significantly beyond what a locally-hosted model can do reliably today.
The hybrid approach β Ollama for private, high-volume, lower-stakes tasks and Claude API for quality-critical steps β is the most cost-effective and practical setup I've found for a solo developer running production automation. You get data privacy where it matters, you get frontier quality where it's worth paying for, and your monthly AI bill stays predictable and reasonable.
Need AI tools integrated into your dev workflow?
I build custom AI automation pipelines with Claude API, n8n, and local LLMs for development teams. Let's talk β