ECONNREFUSED on localhost: reaching your host machine's services from n8n in Docker
Published 3 August 2026 · 8 min read
The scenario is disarmingly common: Ollama is running on your machine, curl http://localhost:11434 answers perfectly from a terminal, yet the HTTP Request node (or the Ollama node, or the Postgres node) in your Docker-installed n8n stubbornly returns ECONNREFUSED 127.0.0.1:11434. Nothing is broken, no firewall is blocking anything, and still the connection is refused. It's probably the single most frequent error in self-hosted n8n — we run into it in our Postgres and Ollama guides alike — and it has one cause: from inside a Docker container, localhost does not mean your machine.
This guide explains why, lays out the mental model that keeps you from falling into the trap again, and walks through the four solutions in the order you should consider them: the Docker service name, host.docker.internal, the gateway IP, and network_mode: host. With three concrete cases to close it out: Ollama, a local Postgres, and the webhook of an app you're developing.
The exact symptom
The error wears several faces depending on the node, but the pattern is always the same:
ECONNREFUSED 127.0.0.1:11434 ← HTTP Request or Ollama node
ECONNREFUSED 127.0.0.1:5432 ← Postgres credential
ECONNREFUSED ::1:3000 ← local API in development
The service refused the connection
What makes it disorienting is that everything else works: the service responds from a browser or a curl run on the machine, the port is correct, no password is involved. ECONNREFUSED doesn't mean "wrong credentials" or "service crashed": it means nothing is listening at the address n8n called. And the address n8n called isn't the one you think.
Why localhost isn't your machine
A Docker container isn't just a process: it lives in its own network namespace, with its own lo interface, its own routing table, its own IP address on a bridged network. That's precisely what makes isolation valuable — the reference study by Felter, Ferreira, Rajamony and Rubio at IBM Research (An updated performance comparison of virtual machines and Linux containers, IEEE ISPASS 2015 — see on Google Scholar) shows that containers deliver near-native performance on almost every front, networking (NAT, bridging) being one of the few layers where isolation adds extra cost and complexity. That complexity is exactly what you're running into here.
The mental model to keep fits in three lines:
- Your machine (the host) has a
localhostof its own: that's where Ollama, your apt- or Homebrew-installed Postgres, and your app in development are listening. - The n8n container has its own, separate
localhost: when n8n calls127.0.0.1, it knocks on its own door, inside the container, where there's nothing but itself. - The other containers in the same
docker-composeare neighbors on a shared network, reachable by their service name — never bylocalhost.
In other words, ECONNREFUSED 127.0.0.1:11434 translates literally to: "nobody is listening on port 11434 inside the n8n container". Which is true. So the question isn't "why is the connection refused?" but "which hostname points to where the service actually runs?". There are four possible answers.
Solution 1 — the service runs in the same docker-compose: the service name
This is the simplest case and the cleanest solution. If Ollama, Postgres or any other service runs in a container within the same docker-compose as n8n, Docker creates a shared network where each service is reachable by its name:
services:
n8n:
image: docker.n8n.io/n8nio/n8n
ports:
- "5678:5678"
ollama:
image: ollama/ollama
volumes:
- ollama_data:/root/.ollama
postgres:
image: postgres:16
environment:
POSTGRES_PASSWORD: change-me
volumes:
ollama_data:
From n8n, Ollama's URL becomes http://ollama:11434 and the Postgres credential host becomes postgres (port 5432) — the service name, as written in the file, acts as a DNS name. Note that containers talk to each other on their internal ports, with no ports: section needed: port publishing only exists to expose a service outside the Docker network.
Prefer this solution whenever you can: it's portable (the same file works on Mac, Windows, Linux, a VPS), survives restarts and IP changes, and keeps all traffic inside the Docker network. If you're starting from scratch, our n8n Docker installation guide sets up this docker-compose foundation properly — and it stays stable through n8n updates.
Solution 2 — the service runs on the host machine: host.docker.internal
Second case: the service does not run in Docker, but directly on the machine — an Ollama installed via the official script, a system Postgres, an application you're developing. Docker provides a special hostname for this, host.docker.internal, which points to the host machine from inside a container.
On Docker Desktop (Mac and Windows), the name works natively, with no configuration at all. Simply replace localhost with host.docker.internal in the URL or credential:
http://localhost:11434 → http://host.docker.internal:11434
On Linux (the typical VPS case), the name doesn't exist by default. You have to declare it explicitly in the docker-compose, via extra_hosts and the magic value host-gateway:
services:
n8n:
image: docker.n8n.io/n8nio/n8n
ports:
- "5678:5678"
extra_hosts:
- "host.docker.internal:host-gateway"
Then recreate the container (docker compose up -d).
The trap within the trap: the service must listen beyond 127.0.0.1
This is where half of all troubleshooting attempts fail. Many services listen by default only on 127.0.0.1 — that is, only for connections coming from the machine itself. But a connection arriving from the n8n container via host.docker.internal comes in through the Docker bridge interface, not through the loopback: the service rejects it, and you get… ECONNREFUSED, despite having the right hostname.
Ollama is the canonical example: by default it only listens on 127.0.0.1:11434. You have to tell it to listen on all interfaces:
# Linux (systemd service)
sudo systemctl edit ollama
# add:
# [Service]
# Environment="OLLAMA_HOST=0.0.0.0"
sudo systemctl restart ollama
Same logic for a host Postgres (listen_addresses in postgresql.conf, plus a pg_hba.conf rule for the Docker subnet) or a development server (npm run dev -- --host 0.0.0.0, for example). The pair to check is always the same: the right hostname on the n8n side, and a listener that goes beyond 127.0.0.1 on the service side. If you open a service on 0.0.0.0 on an internet-facing VPS, mind the firewall: open the port to the Docker subnet only, not to the whole world.
Solution 3 — the Docker gateway IP: possible, but fragile
On Linux, the host machine is also reachable from a container via the Docker bridge gateway IP — 172.17.0.1 by default on the bridge network, a different address (often 172.18.x.x or beyond) on networks created by docker compose. You can find it with docker network inspect and use it directly as the host.
It works, but we don't recommend it: the address depends on which network the container is attached to, can change if you recreate the networks, and makes the docker-compose non-portable between machines. extra_hosts: - "host.docker.internal:host-gateway" does exactly the same thing while letting Docker resolve the right address on every start. Keep the raw IP for one-off diagnostics.
Solution 4 — network_mode: host: the last resort
On Linux only, you can remove the container's network isolation altogether:
services:
n8n:
image: docker.n8n.io/n8nio/n8n
network_mode: host
The container then shares the host's network namespace: localhost means the machine again, everything works "like before Docker". But the price is real: no more network isolation, no more ports: section (it's ignored — n8n listens directly on the host's port 5678), no more service names to reach other containers, and no compatibility with Docker Desktop on Mac and Windows. It's a last-resort option for very specific cases — not a default answer to an ECONNREFUSED that solution 2 fixes cleanly.
Three concrete cases
Ollama on the host, n8n in Docker. The star case since local LLMs took off, covered in detail in our n8n + Ollama without an API key guide. The full recipe: extra_hosts: - "host.docker.internal:host-gateway" on the n8n side, OLLAMA_HOST=0.0.0.0 on the Ollama side, and http://host.docker.internal:11434 as the base URL in n8n's Ollama credential. If you can instead run Ollama as a container in the same compose file, it's even simpler: http://ollama:11434, nothing else needed.
A local Postgres. Same trade-off. Postgres as a neighboring container: host postgres, port 5432 in the credential — the nominal case in our Postgres node guide. Postgres installed on the machine: host host.docker.internal, after checking listen_addresses and pg_hba.conf.
Testing the webhook of an app in development. You're building an API on http://localhost:3000 and want n8n to call it: http://host.docker.internal:3000, with a dev server listening on 0.0.0.0. It's the exact complement of our guide on testing n8n webhooks locally, which covers the opposite direction — getting external requests into your n8n.
And in the other direction?
The confusion sometimes runs the other way: reaching n8n from the machine or from the internet. From the host, that's what port publishing is for — the ports: - "5678:5678" line in the compose file is what makes http://localhost:5678 work in your browser (there, localhost is legitimate: you're on the host). To expose the interface and webhooks to the internet with a real domain name and HTTPS, port publishing is no longer enough: that's the subject of our HTTPS and domain name with Traefik or Caddy guide.
Common pitfalls
- Fixing the URL to
host.docker.internalbut leaving the service listening on127.0.0.1only: the connection stays refused despite the right hostname. For Ollama,OLLAMA_HOST=0.0.0.0is as much a part of the fix as the hostname. - Adding
extra_hostson Mac or Windows thinking it's required: Docker Desktop provideshost.docker.internalnatively; thehost-gatewayline is only essential on Linux (and it breaks nothing elsewhere). - Using
host.docker.internalfor a service running in the same compose file: between neighboring containers, the service name is the right call (http://ollama:11434) — simpler and more robust. - Hard-coding
172.17.0.1: the address varies by Docker network and machine; preferhost-gateway, which resolves it automatically. - Adding a
ports:section so n8n can reach a neighboring container: port publishing exposes services outward; between containers on the same network, it's unnecessary. - Switching to
network_mode: hostat the first ECONNREFUSED: you lose isolation and control over published ports for a problemextra_hostsfixes in one line. - Forgetting to recreate the container after editing the compose file:
docker compose up -dis required forextra_hoststo take effect — merely re-running the n8n workflow isn't enough.
In summary
ECONNREFUSED 127.0.0.1 from n8n in Docker is almost never an outage: it's localhost not meaning what you think it means. The reflex to build comes down to two questions. Where does the service run? If it's in the same docker-compose, call it by its service name (http://ollama:11434, host postgres). If it runs on the host machine, call host.docker.internal — with extra_hosts: - "host.docker.internal:host-gateway" on Linux — and make sure it listens beyond 127.0.0.1. The gateway IP and network_mode: host remain diagnostic tools or last resorts, not default answers. This network plumbing is precisely the prerequisite for a 100% local AI assistant: a RAG with Ollama means n8n has to reach both the LLM and the vector store without a single byte leaving your machine. The RAG Assistant Pack (€119) ships that complete pipeline — ingestion, embedding, chat — ready to plug into the Docker architecture you've just straightened out.
FAQ
Frequently asked questions
Why does n8n in Docker return ECONNREFUSED 127.0.0.1:11434 when Ollama is running fine on my machine?
Because a Docker container has its own network namespace: when n8n calls localhost or 127.0.0.1, it's talking to itself, inside the container, not to your machine. Ollama is indeed running — but on the other side of a network boundary. Replace localhost with host.docker.internal (adding extra_hosts with host-gateway to the docker-compose on Linux) and make sure Ollama listens on all interfaces with OLLAMA_HOST=0.0.0.0 — otherwise the connection stays refused even with the right hostname.
Should I use host.docker.internal or the Docker service name to connect n8n to Postgres?
It depends on where Postgres runs. If it's in the same docker-compose as n8n, use the service name (for example postgres as the host, port 5432): both containers share a Docker network where that name resolves directly — the clean, portable solution. host.docker.internal only applies in the other case: a Postgres installed directly on the host machine, outside Docker.
host.docker.internal doesn't work on my Linux server — what now?
Unlike Docker Desktop on Mac and Windows, Docker on Linux doesn't create that hostname automatically. Add an extra_hosts section to the n8n service in your docker-compose with the line host.docker.internal:host-gateway, then recreate the container. If the connection is still refused, the target service is probably listening on 127.0.0.1 only: configure it to listen on 0.0.0.0, or at least on the Docker bridge interface.
Bundle FlowKit Complet
€269