How to Use a Local LLM in Cursor with Ollama (2026 Tunnel Setup)
This page is the Cursor wiring path — Ollama, a public HTTPS tunnel, and Override OpenAI Base URL. The general Ollama and llama.cpp stack lives in How to Run LLMs Locally. Distilled DeepSeek-R1 tags and thinking traces stay on How to Run DeepSeek-R1 Locally. Editor-vs-editor comparison is Cursor vs GitHub Copilot.
A lot of ranking posts still tell you to paste http://localhost:11434/v1 into Cursor. That recipe is leftover from an older assumption: that the editor calls your model from the same machine. Current Cursor does not. Custom-model traffic is assembled on Cursor’s backend, then that backend calls the URL you typed. A loopback address on your laptop is invisible from there. The working setup in 2026 is a public HTTPS endpoint — usually an ngrok or Cloudflare Tunnel in front of Ollama — plus an honest map of what still stays in Cursor’s cloud.
Desk note — who this is for / what it’s bad at: Developers who already run Ollama and need Cursor Chat to hit those weights. Bad as a privacy architecture — a public tunnel is not an air gap — and a poor reason to buy a flagship card so Tab can stay local (it will not).
What to check before you open a tunnel (or buy a card)
Listing identity first: Ollama is the local OpenAI-compatible server on 127.0.0.1:11434. ngrok and cloudflared are public HTTPS doors in front of that port. Cursor Override OpenAI Base URL is a BYOK setting that still sends prompts through Cursor’s backend. None of them is an offline IDE. Continue or Tabby talking to localhost is a different product — see self-hosted coding tools.
Before you paste a tunnel URL or open a GPU invoice:
- Prove
/v1/chat/completionson localhost first. If curl fails, Cursor will fail louder. The install path without the Cursor hop is the local LLM setup. - A public tunnel is not an air gap. Prompts still leave the machine for Cursor’s prompt builder. If the contract forbids a SaaS hop, stop. Do not buy a card to “keep code local” inside Cursor.
- Do not buy a flagship card to localize Tab. Tab stays on Cursor’s cloud. A 4090 search is unused VRAM if you only wanted autocomplete. Size a real local chat tag on the GPU guide.
- Skip a paid tunnel plan until a rotating free URL actually breaks your day. ngrok’s free host and a Cloudflare quick tunnel are enough to prove the path. A reserved domain is an ops convenience, not a model upgrade.
- Skip this page if you wanted a hosted chat or an editor comparison — that is ChatGPT vs Claude vs Gemini or Cursor vs Copilot. If you wanted retrieval over your docs, that is vector databases, not a tunnel. If you wanted a CI first pass or a client-tool loop, start at AI code review or building agents.
Practical cadence: pull an 8B coder → curl localhost → one tunnel with Host rewrite → one Cursor chat. Then decide whether a pipeline even needs a local model. More articles live on the blog index. Amazon search links on this page use tcalnet-20; see how we make money.
TL;DR: Install Ollama, pull a coding tag, prove
POST /v1/chat/completionsonlocalhost:11434, open a tunnel that rewritesHosttolocalhost:11434, then set Cursor’s Override OpenAI Base URL tohttps://your-tunnel/v1with any non-empty API key. Tab still uses Cursor’s models. This is not an air-gapped editor.
What “local” means inside Cursor
Ollama can run the weights on your GPU. Cursor still owns the product surface around those weights.
Cursor staff have said this plainly on the community forum: Override OpenAI Base URL needs a publicly accessible HTTPS endpoint because prompt building happens on Cursor’s servers. A full bypass of those servers is an architectural limit, not a missing checkbox. Native loopback support is a requested feature with no published timeline.
That produces a three-hop path:
- You type in Cursor.
- Cursor’s backend builds the prompt (context, rules, tool scaffolding) and calls your base URL.
- The tunnel forwards that HTTPS request to Ollama on
127.0.0.1:11434.
The model runs on your hardware. The conversation is not confined to your hardware.
Keep that distinction in mind before you treat this setup as a privacy win. Inference cost and GPU residency move local. Prompt assembly, Tab, and the agent loop do not.
What still stays on Cursor’s cloud
The override redirects OpenAI-format traffic. It does not replace Cursor.
Tab stays cloud. Inline autocomplete is a Cursor-hosted model path. Pointing Base URL at Ollama does not make Tab run qwen2.5-coder on your card. If Tab is the feature you wanted to localize, this page will not do that. Continue, Tabby, or another editor-side client that actually calls localhost is a different product — see the self-hosted coding tools note.
Indexing stays cloud. Cursor’s codebase index is built and queried on Cursor’s side. A local chat model can read the snippets Cursor already retrieved. It does not replace that index.
Agent orchestration stays cloud. Multi-file edits and tool calls are still planned on Cursor’s backend. Your Ollama process only sees the completion request that backend sends. Small local models often fumble tool-call syntax even when the tunnel is perfect. That is a model-capacity problem, not a URL problem.
The request still leaves the machine. Even with Privacy Mode on, the hop through Cursor’s API and a public tunnel is not air-gapped. Privacy Mode is about training and logging policy, not about keeping bytes on-box. If a contract forbids third-party processing of source, stop here and use a tool that never phones home.
What you need before the tunnel
- Cursor current enough that Settings → Models lets you edit OpenAI API Key and Override OpenAI Base URL. Builds in the 3.15.19 window had a focus bug on those fields; 3.15.20 and later restored click-to-edit. If a field ignores the mouse, Tab into it or update.
- A Cursor plan that allows Bring Your Own Key. The override is a BYOK feature. A free tier that cannot set a custom key will not take a custom base URL either.
- Ollama on the same machine that will serve the model, or on a box you control that the tunnel can reach.
- A tunnel client: ngrok or cloudflared.
- Hardware that can hold the tag you pull. An 8B-class Q4 model wants roughly 8–12 GB of VRAM or a 16 GB Apple Silicon machine. Card-by-card sizing is the GPU guide. Portable machines are the developer laptop page. This article does not reprint those tables.
You do not need to bind Ollama to 0.0.0.0. The tunnel connects to localhost. Leave Ollama on the default 127.0.0.1:11434 bind unless you have a separate reason to expose it on the LAN.
Step 1: Install Ollama
Use the installer from ollama.com, not a random mirror.
# macOS or Linux
curl -fsSL https://ollama.com/install.sh | sh
On macOS you can also brew install ollama. On Windows, download the installer from the same site and let it register the background service.
Confirm the daemon answers:
curl -s http://localhost:11434/api/tags
A JSON list (even an empty models array) means the server is up. Connection refused means the service is not running. On Linux, systemctl status ollama is the first place to look. On macOS and Windows, start the Ollama app from the menu bar or system tray.
Ollama’s own FAQ is the source for the later tunnel flags. Bookmark docs.ollama.com/faq before you invent extra environment variables.
Step 2: Pull a coding model
Pull a tag that fits the machine you already have. Do not start with a 70B model on a 16 GB laptop.
# Solid default for 16 GB unified memory or 8–12 GB VRAM
ollama pull qwen2.5-coder:7b
# Faster / smaller
ollama pull qwen2.5-coder:3b
# Heavier, if you have ~16 GB VRAM or 32 GB unified memory
ollama pull qwen2.5-coder:14b
qwen2.5-coder is a coding-tuned family. General chat tags (llama3.2, mistral) will answer, but they waste context on prose when you wanted diffs. If you specifically want DeepSeek-R1 thinking traces, stop cloning this page and use the R1 local setup for tags and temperature. Come back here only for the Cursor URL.
Confirm the exact name Cursor will have to send:
ollama list
Copy the NAME column verbatim — including the :7b suffix. Cursor forwards the model string as-is. qwen2.5-coder and qwen2.5-coder:7b are different IDs if that is how you pulled them.
Warm the weights so the first Cursor request is not a cold load:
ollama run qwen2.5-coder:7b ""
ollama ps should then show the tag in memory and whether it landed on GPU or CPU. CPU-only 7B is usable for chat. It is painful for agent-sized prompts.
Step 3: Prove the OpenAI-compatible API locally
Ollama speaks a slice of the OpenAI API at /v1. Official examples live in Ollama’s OpenAI compatibility docs. Cursor will call /v1/chat/completions. Prove that path before you add a tunnel, or you will debug three systems at once.
curl -s http://localhost:11434/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "qwen2.5-coder:7b",
"messages": [{"role": "user", "content": "Reply with the word pong only."}]
}'
You want a JSON completion, not model not found and not connection refused. The dummy API key is irrelevant here; Ollama ignores it. Cursor still requires a non-empty key later because the field is mandatory in the UI.
If this curl fails, fix Ollama first. A tunnel cannot repair a missing tag.
Step 4: Open a public HTTPS tunnel
Cursor’s backend needs a URL it can resolve on the public internet, over HTTPS. Plain http:// fails even if you somehow published a port. That is why ngrok and Cloudflare show up in every working write-up: both mint HTTPS without you terminating TLS.
Ollama also checks the Host header. A request that arrives as Host: random-words.trycloudflare.com is rejected with 403. Both official tunnel recipes rewrite the header to localhost:11434.
ngrok
Install the CLI, authenticate if the current ngrok release requires it, then:
ngrok http 11434 --host-header="localhost:11434"
That command is the one in Ollama’s FAQ. Copy the https://….ngrok-free.app (or reserved domain) forwarding URL. Do not add /chat/completions. Cursor appends the path.
Free ngrok URLs rotate when the process restarts. Every rotation means a trip back to Cursor Settings. A reserved domain is the daily-driver version of the same command.
Cloudflare Tunnel (cloudflared)
cloudflared tunnel --url http://localhost:11434 --http-host-header="localhost:11434"
Again, that pair of flags is from Ollama’s FAQ. The quick tunnel prints a https://….trycloudflare.com URL. If you already have ~/.cloudflared/config.yml from a named tunnel, a quick tunnel can inherit a catch-all http_status:404. Passing --config /dev/null on the same command avoids that leftover.
A named Cloudflare tunnel with your own hostname is more stable than a trycloudflare.com URL. The ingress rule still needs originRequest.httpHostHeader: "localhost:11434". Without it you are back to 403.
Prove the tunnel without Cursor
From a network that is not your loopback — a phone on cellular is enough:
curl -s https://YOUR-TUNNEL-HOST/v1/models
You want Ollama’s model list, not Cloudflare’s HTML 404 and not an ngrok interstitial you forgot to click through. If this curl works and Cursor still fails, the bug is in Cursor settings, not the tunnel.
Step 5: Point Cursor at the OpenAI-compatible base URL
In Cursor:
- Open Settings → Models (Cursor Settings, not the VS Code-style JSON dump).
- Enable OpenAI API Key and enter any non-empty placeholder, such as
ollama. Ollama will ignore it. Cursor will not save an empty field. - Enable Override OpenAI Base URL.
- Paste the tunnel origin plus
/v1, for example:https://abcd-1234.ngrok-free.app/v1orhttps://random-words.trycloudflare.com/v1 - Do not paste
http://localhost:11434/v1. That is the recipe that no longer works. - Do not append
/chat/completions. The base URL is the prefix Cursor already knows how to extend.
Routing follows the key plus the override, not the display name of a built-in model. Cursor staff have described it this way: if your key is not one of Cursor’s internal keys and the override is set, OpenAI-family requests go to your endpoint, and the model string is forwarded unchanged. Claude- and Gemini-prefixed built-ins stay on Cursor’s vendors. That is why you add your Ollama tag instead of renaming it claude-sonnet.
Step 6: Add the exact tag and send a chat
- Under custom / additional models, Add Model.
- Type the exact
ollama listtag, for exampleqwen2.5-coder:7b. - Turn that model on.
- Turn the other models off for the first test.
The last step exists because Verify is a poor test. Several public write-ups show Verify probing a built-in name such as gpt-4o. Ollama then returns 404 for a model you never pulled. That is not proof the tunnel is down. Open Chat, select your added tag, and ask for a one-word reply.
If chat streams tokens and ollama ps shows activity, the path works. If chat hangs and the tunnel log stays quiet, Cursor never reached you — wrong URL, HTTP instead of HTTPS, or a stale ngrok host. If the tunnel log shows 403, the Host header rewrite is missing. If it shows 404 on /v1/chat/completions, you pointed at the origin without /v1 or you pointed at a different process on that port.
Which Cursor surfaces actually use the override
| Surface | Uses your Ollama URL? | Notes |
|---|---|---|
| Chat | Yes, when your custom tag is selected | This is the path you just tested. |
Inline edit (Cmd/Ctrl+K) | Usually yes, same model picker | Same OpenAI-format call, still via Cursor’s backend. |
| Agent / Composer | Yes for the completion hop, no for planning | Tool use quality tracks the local model, which is often weaker than hosted Claude or GPT. |
| Tab autocomplete | No | Stays on Cursor’s completion model. |
| Codebase index | No | Retrieval stays on Cursor. |
Treat this table as the honest product map. A local model in Chat does not make Cursor a local IDE.
Security: you published an unauthenticated API
Ollama’s HTTP API has no user login. Anyone who learns the tunnel URL can POST /v1/chat/completions on your GPU, pull model names, and burn electricity. A free ngrok or trycloudflare.com URL is guessable only in the sense that it leaks through screenshots, shell history, and log dumps — which is enough.
Minimum hygiene:
- Do not paste the live URL into a ticket, a tweet, or a screenshot of Settings.
- Stop the tunnel when you are not using Cursor.
- Prefer a named Cloudflare tunnel or reserved ngrok domain with access rules over a disposable URL you leave up for days.
- Leave Ollama bound to localhost. The tunnel is the only ingress.
OLLAMA_HOST=0.0.0.0plus a tunnel is two ways in. - If you need this daily, put Cloudflare Access or ngrok’s own auth in front. The Host-header rewrite still applies behind that gate.
This is the opposite of hardening a lab. It is the cost of Cursor’s current architecture.
Honest limits (read this before you cancel a cloud plan)
Not air-gapped. Prompts, file snippets, and tool traces still transit Cursor’s servers. The tunnel then exposes those same bytes on a public hostname. If the requirement is “source never leaves the building,” Cursor plus Ollama is the wrong stack. Use a local client that talks to 127.0.0.1 without a SaaS hop.
Not a cost-zero Cursor. You still pay for the Cursor seat that unlocks BYOK. You still pay for the GPU, the electricity, and (if you want a stable URL) the tunnel plan. What you stop paying is per-token inference on the chat model you replaced.
Quality is the model, not the IDE. A 7B coder is fine for “rename this function” and thin unit tests. It will lose to hosted Claude or GPT on multi-file refactors, odd frameworks, and tool-call formatting. That gap is why this desk still treats local inference as a complement, not a replacement — same conclusion as the local LLM setup guide.
Latency stacks. Cursor backend + tunnel + local decode. A fast GPU can still feel slower than a nearby hosted API because you added two network hops to “save” one.
Ephemeral URLs break overnight. Restart ngrok or a quick Cloudflare tunnel and Cursor still has yesterday’s host. The failure mode looks like “local models stopped working.” Update the base URL, or graduate to a named tunnel.
One override, many models. The base URL is process-wide for OpenAI-format traffic. If you also BYOK to OpenAI proper, you are sharing that slot. Do not expect to keep api.openai.com and Ollama on the same override.
Optional hardware path
If the tunnel works and the model is just slow, you have a hardware problem, not a Cursor problem. ollama ps showing 100% CPU on a 14B tag is the tell.
- Desktop cards and VRAM tiers: The Best GPUs for Running Local LLMs in 2026. A 24 GB card is the usual step up from “7B is fine, 14B swaps.” The RTX 4090 search is a price check for that tier, not a spec-sheet reprint.
- Portable machines and unified memory: Best Laptops for Developers in 2026. 32 GB is the comfortable local-LLM laptop floor; 16 GB is an 8B-class ceiling.
Do not buy a card to make Tab local. Tab will not move.
Troubleshooting
Chat hangs, tunnel log idle. Cursor cannot see the host. Check HTTPS, /v1, and that the tunnel process is still running. A killed ngrok session is the common overnight failure.
403 from Ollama. Missing --host-header / --http-host-header. Add it. Do not “fix” this by binding Ollama to the world unless you intend to.
404 model not found. The string in Cursor is not the string in ollama list. Re-add the tag. Ignore Verify if it mentioned gpt-4o.
404 from Cloudflare HTML. Quick tunnel picked up an old config.yml. Rerun with --config /dev/null, or fix ingress.
Slow first token, fine after. Cold load. Preload with ollama run <tag> "" or a keep-alive of -1 if this is a desk machine you do not mind occupying.
Agent loops or emits broken tool JSON. The local model is too small for the agent prompt. Stay in Chat, or pick a larger tag. This is not a tunnel defect.
Fields in Models will not accept clicks. Update past 3.15.19, or Tab into the field. That was a Cursor UI bug, not Ollama.
Works in curl, fails after you add Claude-named custom models. Do not name an Ollama tag after a built-in Cursor model. Colliding IDs confuse the picker. Use the Ollama tag.
FAQ
Why does http://localhost:11434/v1 fail in Cursor?
Because Cursor does not call that URL from your laptop. The backend that builds the prompt lives on Cursor’s network. localhost there is Cursor’s loopback, not yours. A public HTTPS tunnel is the workaround the team points people at today.
Does Cursor Tab use my Ollama model?
No. Tab, the index, and the agent planner stay on Cursor’s cloud. The override is for OpenAI-format chat and edit completions you explicitly send to your custom tag.
Is this air-gapped or fully private?
No. Inference is local. Prompt construction, retrieval, and the HTTPS hop are not. Anyone with the tunnel URL can also hit Ollama. Treat “local LLM in Cursor” as “local decode, remote control plane.”
Why does the tunnel return 403?
Ollama wants Host: localhost:11434. ngrok --host-header="localhost:11434" and cloudflared --http-host-header="localhost:11434" are the documented fixes.
Why does Verify fail with a GPT-4o 404?
Verify often asks for a built-in OpenAI name. Ollama does not have that name. Add your real tag, disable the others, and use Chat as the test.
Do I need to expose Ollama on my LAN?
No. Keep the default localhost bind and let the tunnel be the only door.
ngrok or Cloudflare?
Both work. ngrok is one binary and a rotating free URL. Cloudflare quick tunnels are free and also rotate; a named tunnel is the stable option if you already have a Cloudflare account. Pick one, set the Host rewrite, and stop collecting clients.
Related Reading
- How to Run LLMs Locally: Ollama, llama.cpp, and Hardware Requirements
- How to Run DeepSeek-R1 Locally with Ollama
- The Best GPUs for Running Local LLMs in 2026
- Best Laptops for Developers in 2026
- Cursor vs GitHub Copilot: Which AI Code Editor Wins?
- Best Open Source AI Coding Tools You Can Self-Host
- Vector Databases Explained: When You Need One and How to Choose
- Building AI Agents: Architecture Patterns and Practical Examples
- Automating Code Reviews with AI: A Practical Integration Guide
- CI/CD Pipeline Design: From Zero to Production Deployment
- All articles
- How We Make Money