Your prompts stay on the machine; the software around them still talks to the internet. I ran a stock Ollama plus Open WebUI stack behind a packet capture for a week: no prompt or completion content left the box, but there was regular traffic for model pulls and update-style version checks, plus container-registry traffic on every image update. All of it can be eliminated with an internal Docker network and one environment variable — at the cost of doing updates manually. The bigger finding is the boring one: the privacy risk in a local AI stack isn't secret telemetry, it's the features you enable that are internet-shaped by design.
What a default install talks to
Three classes of traffic showed up. Model distribution: Ollama pulls models from its registry (registry.ollama.ai), so the act of downloading llama3.1:8b tells that registry someone at your IP wanted it — same privacy shape as any package manager. Version checks: both Ollama's desktop builds and Open WebUI check for newer releases by default. Container images: docker pull traffic to Docker Hub and ghcr.io. What did not appear, across a week of real usage: any request carrying chat content, embeddings, or document text. Inference in this stack is genuinely local.
The by-design exceptions matter more than any of that. Open WebUI's web search feature sends your query to whichever search backend you configured. Remote TTS/STT endpoints send text or audio out. And an "OpenAI API connection" added in the admin panel routes those chats to that provider — obvious when stated, forgotten when a housemate adds a connection six months later. A local stack is only as local as its most recently enabled integration.
Verify it yourself; don't trust blog posts
Including this one — the stack updates weekly and my capture is a snapshot. The audit takes an evening. Watch everything the host sends that isn't LAN-local:
sudo tcpdump -i any -nn 'not port 22 and not (net 192.168.0.0/16 or net 10.0.0.0/8)'
Run it during a normal evening of chatting, model pulls, and document uploads. For hostnames instead of raw IPs, your DNS resolver's query log is the friendlier view — Pi-hole or AdGuard Home shows every domain the stack resolves, per client, which is usually all the audit you need. For TLS traffic where you want to see paths rather than just destinations, mitmproxy with its CA injected into the container does it, but destination plus timing plus payload size answers the real question (is chat content leaving?) with far less setup: a 40-byte version check and a 5GB model pull don't look like your conversation history. Repeat the capture after every stack update: egress behaviour is a moving target, and the diff between two weeks of DNS logs is the fastest-reading changelog you'll ever get.
Locking it down: the internal-network pattern
Docker can enforce what policy promises. Put inference on a network with no route out; give the UI a LAN-facing port but the same no-egress rule for its AI traffic path:
networks:
airgap:
internal: true
services:
ollama:
image: ollama/ollama:0.9.0
networks: [airgap]
volumes:
- ./ollama:/root/.ollama
open-webui:
image: ghcr.io/open-webui/open-webui:0.6.5
networks: [airgap]
ports:
- "3000:8080"
environment:
- OFFLINE_MODE=true
- ENABLE_OPENAI_API=false
internal: true removes the default route — containers on airgap can reach each other and nothing else, and the published port still works because it's host-mediated. Open WebUI's OFFLINE_MODE stops version checks and remote model-list fetches. Verify the cage: docker exec into each container and confirm wget -T3 https://example.com times out.
Getting models in without opening the cage: pull on any connected machine and copy ~/.ollama/models (blobs and manifests) into the volume, or download GGUFs from Hugging Face and load them with a Modelfile via ollama create. Updates become deliberate: bump the pinned image tags, pull on a connected host or temporarily relax the network, and re-verify. That's the trade — and for a stack holding years of your conversations, it's a good one.
The threat model you're actually left with
With egress closed, what remains is local and mundane. Open WebUI stores every conversation in its database — chats with an assistant are among the most sensitive documents you own (health questions, contracts, half-written resignation letters), and they now sit unencrypted on your disk, flow into your backups, and are readable by anyone with admin on the box. Encrypt the backups, scope Open WebUI accounts properly if the household shares it, and remember the web UI itself should never face the internet without auth in front. Right-sizing this level of paranoia is a topic of its own — threat modelling for normal people — but the one-line version: you moved the risk from a provider's data retention policy to your own disk hygiene, which is the trade self-hosting always makes.
What I'd do
Run the stack with pinned image versions on an internal network with OFFLINE_MODE=true, keep one documented procedure for model imports and monthly updates, and let Pi-hole's query log be the standing tripwire — any new domain appearing after an update is your cue to read a changelog. Leave web search off unless you'd be comfortable typing those queries into the search engine directly, because that is literally what the feature does. Audited once and caged, a local stack delivers what the pitch promises: the model, the prompts, and the history all on hardware you control, verified by tcpdump rather than a privacy policy.