Guides
Documentation
Agent in isolated container

Reaching external services

Connect a containerized app to PostgreSQL, MySQL, or Redis running outside the container.

Some apps the agent clones expect a database or cache that runs outside the container — PostgreSQL, MySQL, Redis. SQLite needs none of this: it's a file on a mounted volume, not a network service, which is why SQLite-backed apps just work. The clients are already in the image (libpq, mysql2, hiredis), so connectivity — not a missing driver — is the only thing to get right.

The one rule that causes most failures

So any cloned app whose config says redis://localhost:6379 or postgres://localhost:5432 fails in a container unless that service also runs inside the same container. Everything else here is just: what address do you use instead, and is the path open.

Two things to check every time

Addressing
Does the app's config point at something other than localhost?
Reachability
Is the listening service bound to an address reachable from outside its own loopback, and does its firewall allow the connection?

Case 1 — service on the same host

The service runs on your Mac and the container is local. Both checks apply at once: name the host correctly, and make sure the host service accepts the connection.

Addressing — how the container names the host

Docker Desktop (macOS)
Use host.docker.internal — it resolves automatically.
Apple container runtime
Use the gateway IP of the container's vmnet subnet (the .1, e.g. 192.168.64.1). Find it inside with ip route | grep default.
Docker on Linux (bare metal)
Add --add-host host.docker.internal:host-gateway, or use the bridge gateway (commonly 172.17.0.1).

Reachability — the host service must accept the connection

Correct addressing isn't enough — a service bound to localhost only will still refuse the container, because from the host's view the connection arrives from the VM or bridge IP, not loopback.

  • PostgreSQL: set listen_addresses (e.g. '*') in postgresql.conf, plus a matching pg_hba.conf line for the container subnet.
  • Redis: bind must include a non-loopback address. If you open it, set requirepass.
  • The host firewall must allow the container subnet.

Case 2 — service in another container

When the database or cache runs in its own container, address it by name — not by localhost, which only ever reaches the container's own loopback.

  • Same user-defined network: address by container or service name via built-in DNS, e.g. redis://redis:6379. The internal port is used directly — published -p ports are irrelevant container-to-container. This is the normal, portable case.
  • Different networks or runtimes: they can't see each other by name. Put them on a shared network, or fall back to host-IP routing (Case 1) via the host's published port.
  • A sibling on a shared network needs no host-gateway tricks — the connection never leaves the container network.

Case 3 — remote or managed service

The simplest case. Use the real hostname or IP — postgres://user:[email protected]:5432/..., redis://cache.internal:6379 — and the container makes an ordinary outbound connection. No host-gateway tricks needed.

  • The container has egress (the default), so outbound TCP works as usual.
  • DNS resolves the hostname.
  • The remote service's firewall must allow the container's egress IP — which after NAT is typically the host's IP, not the container's internal IP. This matters for IP allowlists on RDS or managed Redis.
  • TLS is in place if the service requires it.

Quick reference

Same host · Docker Desktop
host.docker.internal

Host service binds a non-loopback address.

Same host · Apple container
Subnet gateway IP (ip route)

Host service binds a non-loopback address.

Same host · Docker on Linux
host-gateway / bridge IP

Host service binds a non-loopback address.

Sibling container
Service or container name

Both on a shared user-defined network.

Remote / managed
Real hostname or IP

Egress allowed; remote firewall allows the host's NAT IP.