Por qué localhost falla entre contenedores Docker

¿Por qué localhost:5432 no funciona dentro de un contenedor Docker? Porque localhost no significa “la red”, significa “este contenedor”. Si tu backend busca la base ahí, se busca a sí mismo y devuelve Connection refused. La solución en Docker networking para contenedores es usar el nombre del servicio.

El networking de Docker para contenedores es el sistema interno de Docker que conecta contenedores aislados entre sí mediante una red virtual (el bridge) y un DNS propio que resuelve nombres de servicio a IPs. Sirve para que un contenedor encuentre a otro sin hardcodear direcciones. Lo gestiona el daemon de Docker en cada host, según explica la guía de Yasas Banuka publicada el 16 de junio de 2026.

En 30 segundos

  • localhost = este contenedor. Nunca apunta a otro contenedor ni al host. Por eso localhost:5432 da Connection refused.
  • Usá el nombre del servicio. La cadena correcta es jdbc:postgresql://postgres:5432/mydb, no localhost.
  • El bridge es un switch virtual. Docker lo crea al arrancar y conecta los contenedores de una misma red.
  • El DNS interno resuelve nombres. Docker traduce postgres a la IP real del contenedor, sin que vos la sepas.
  • Host a contenedor es otra cosa. Ahí sí necesitás port mapping (-p 5432:5432).

¿Por qué localhost:5432 falla cuando ejecuto mi contenedor Docker?

Ponele que tenés un backend Spring Boot que habla con Postgres, los dos en contenedores. Escribís la cadena de conexión igual que en tu notebook:

jdbc:postgresql://localhost:5432/mydb

Corrés la app. Connection refused.

Revisás y Postgres está corriendo. Lo ves en docker ps, te conectás a mano sin problema. Pero el contenedor del backend insiste en que no lo encuentra. Este error solo se llevó más horas de desarrollo que casi cualquier otro problema de Docker.

El tema es que localhost no quiere decir lo que pensás. Cuando tu backend dice localhost, está diciendo “buscá Postgres corriendo adentro mío”. Y Postgres no está adentro del backend. Está en otro contenedor, su propio mundo aislado. Relacionado: consumir APIs externas en contenedores.

¿Qué es localhost en un contenedor y por qué no significa “la red”?

Pensalo como dos departamentos en el mismo edificio. Cada uno tiene su puerta, sus ambientes, su dirección. Si estás parado en el 4B y decís “fijate en mi cocina si hay leche”, revisás la cocina del 4B. No la del 4A. Aunque estén pegados.

Cada contenedor es un departamento. localhost (o 127.0.0.1) siempre significa “este departamento”, nunca “el edificio”. Docker aísla la red de cada contenedor, así que cada uno tiene su propia interfaz de loopback. A diferencia de una máquina virtual completa, los contenedores comparten el kernel del host, pero su stack de red queda separado por namespaces.

¿Y entonces cómo se encuentran dos departamentos? Ahí entra el bridge.

¿Cómo funciona Docker Bridge, el switch virtual de los contenedores?

Cuando Docker arranca, crea una interfaz de red virtual en tu máquina llamada docker0. Funciona parecido a un switch de red físico (porque, en cierto modo, es uno). Cada contenedor que arranca se “enchufa” a ese switch con un par de interfaces virtuales y recibe una IP privada dentro de la subred del bridge.

El resultado: todos los contenedores en la misma red bridge pueden verse entre sí por IP. El problema es que esas IPs cambian cada vez que recreás un contenedor. Hardcodear 172.17.0.3 es pedirle a tu app que se rompa mañana. Por eso nadie usa IPs directas. Usás nombres. Más contexto en automatizar despliegues de imágenes Docker.

¿Cómo descubre un contenedor la IP de otro automáticamente?

Acá viene lo bueno: Docker trae un DNS interno. En una red definida por el usuario (la que crea docker-compose por vos, por ejemplo), cada contenedor se registra con el nombre de su servicio. Cuando tu backend pide postgres, el DNS de Docker resuelve ese nombre a la IP actual del contenedor de Postgres, sea cual sea.

Esto es service discovery sin que vos hagas nada. No configurás IPs, no tocás /etc/hosts, no inventás variables raras. Spring Boot pide postgres:5432 y Docker se encarga del resto. Eso sí: la red bridge default de Docker (la vieja, sin nombre) no tiene DNS por nombre de contenedor. Necesitás una red definida por el usuario o usar Compose, que ya te la arma.

¿Cuál es la cadena de conexión correcta para conectar contenedores?

Cambiás una palabra y dejás de pelear. En vez de localhost, el nombre del servicio:

jdbc:postgresql://postgres:5432/mydb

Si arrancás con docker run, primero creás la red y conectás ambos contenedores a ella: Lo explicamos a fondo en conectar contenedores a bases de datos.

docker network create mi-red
docker run --name postgres --network mi-red -d postgres
docker run --name backend --network mi-red -d mi-backend

Con docker-compose es más directo todavía, porque cada servicio del archivo ya queda en la misma red y el nombre del servicio es el hostname. Lo de costumbre es leer la cadena desde una variable de entorno (SPRING_DATASOURCE_URL) en vez de quemarla en el código.

EscenarioQué usás como hostNecesitás port mapping
Contenedor a contenedor (misma red)Nombre del servicio (postgres)No
Host a contenedorlocalhost o 127.0.0.1Sí (-p 5432:5432)
Contenedor a un servicio del hosthost.docker.internalNo (depende del SO)
Contenedor a internetEl dominio realNo
docker networking contenedores diagrama explicativo

¿Qué pasa cuando me conecto desde mi máquina host al contenedor?

Esto es distinto. Desde tu máquina (el host) hacia adentro de un contenedor, sí usás localhost, pero solo si publicaste el puerto. El flag -p 5432:5432 mapea el puerto 5432 del host al 5432 del contenedor. Sin ese mapeo, el contenedor está aislado y tu cliente local no llega.

Un detalle que muerde: dentro del contenedor, el servicio tiene que escuchar en 0.0.0.0, no en 127.0.0.1. Si un proceso bindea solo a 127.0.0.1, acepta conexiones únicamente de adentro del contenedor, y el port mapping no sirve de nada. Postgres con listen_addresses = '*' resuelve ese caso.

Errores comunes de networking en Docker en producción

  • Hardcodear localhost entre contenedores. El clásico. Funciona en tu cabeza, falla en Docker. Usá el nombre del servicio.
  • Olvidar el port mapping. Querés entrar desde el host y no publicaste el puerto. docker ps te muestra la columna PORTS vacía y ahí está la pista.
  • Contenedores en redes distintas. Si dos contenedores no comparten red, no se ven aunque tengan el nombre correcto. Verificá con docker network inspect.
  • Bindear a 127.0.0.1 dentro del contenedor. El servicio escucha solo adentro y rechaza todo lo que venga por el bridge o el port mapping.
  • Confiar en la red bridge default. No tiene DNS por nombre. Creá una red propia o usá Compose.

Cuando estos servicios viven en infraestructura real, la red del host también importa. Si corrés tus contenedores en un VPS o servidor con Docker, conviene un proveedor con red estable y soporte en español como donweb.com, porque un timeout de red intermitente se confunde fácil con un error de configuración de Docker y te hace perder horas buscando donde no es.

Preguntas Frecuentes

¿Por qué localhost:5432 no funciona en Docker?

Porque localhost dentro de un contenedor significa “este mismo contenedor”, no la red ni el host. Tu backend se busca a sí mismo y devuelve Connection refused. La base está en otro contenedor aislado, con su propia interfaz de loopback. Sobre eso hablamos en herramientas para CI/CD con Docker.

¿Cómo conecto dos contenedores Docker entre sí?

Poné ambos contenedores en la misma red definida por el usuario y usá el nombre del servicio como hostname. Con docker-compose ya quedan en la misma red automáticamente y el nombre del servicio funciona como dirección.

¿Qué es Docker bridge networking?

Es el modo de red por defecto de Docker. Crea un switch virtual (docker0) al que se conectan los contenedores, cada uno con una IP privada. Los contenedores en la misma red bridge se comunican entre sí por esa red interna.

¿Cuál es la diferencia entre localhost y el nombre del servicio en Docker?

localhost apunta siempre al contenedor que ejecuta el código. El nombre del servicio (como postgres) lo resuelve el DNS interno de Docker a la IP real del otro contenedor. Para hablar entre contenedores, usá el nombre del servicio.

¿Cómo me conecto desde el host a un contenedor?

Publicá el puerto con -p 5432:5432 y conectate a localhost:5432 desde tu máquina. El servicio dentro del contenedor tiene que escuchar en 0.0.0.0, no en 127.0.0.1, o el mapeo no recibe conexiones.

Conclusión

La mayoría de los problemas de Docker networking para contenedores se resuelven con un cambio de mentalidad: localhost es el contenedor, no la red. Una vez que internalizás eso, la cadena de conexión deja de ser magia. Para hablar entre contenedores, nombre del servicio. Para entrar desde el host, port mapping. Si seguís viendo Connection refused, revisá tres cosas en orden: que compartan red, que el puerto esté publicado y que el servicio escuche en 0.0.0.0. En ese orden te ahorrás las horas que casi todos perdimos alguna vez.

Fuentes

Te puede interesar...