Cómo instalar PostgreSQL con Docker
Índice de contenidos
- Puntos clave
- ¿Por qué ejecutar PostgreSQL en Docker?
- ¿Cómo es el docker-compose.yml con volumen persistente?
- ¿Qué variables de entorno necesita la imagen?
- ¿Cómo conectarse a PostgreSQL desde otros contenedores?
- ¿Cómo hacer copias de seguridad con pg_dump?
- ¿Cómo ajustar el rendimiento y el healthcheck?
- Preguntas frecuentes
- ¿Por qué no debo usar la etiqueta latest en producción?
- ¿Se pierden los datos si borro el contenedor?
- ¿Debo exponer el puerto 5432 a Internet?
- Conclusión
- Fuentes
PostgreSQL es la base de datos relacional de código abierto más avanzada, y en Docker se levanta con un único archivo docker-compose.yml. Defines un volumen persistente, la contraseña del superusuario y un healthcheck con pg_isready, y en segundos tienes un servidor en el puerto 5432 listo para que otros contenedores se conecten por el nombre del servicio.
PostgreSQL es la base de datos relacional más usada en proyectos self-hosted, y con Docker la tienes en marcha en menos de un minuto. En esta guía levantas un servidor PostgreSQL con un solo archivo docker-compose.yml, guardas los datos en un volumen persistente, configuras las variables de entorno imprescindibles, conectas otros contenedores por red interna, haces copias de seguridad con pg_dump y añades un healthcheck para que la base de datos arranque de forma fiable. La misma explicación está disponible en inglés.
Puntos clave
- PostgreSQL es la base de datos relacional de código abierto más avanzada; su última versión mayor, PostgreSQL 18, se publicó el 25 de septiembre de 2025.
- La imagen oficial
postgresen Docker Hub trae dos variantes: la basada en Debian (por defecto) y la de Alpine (postgres:18-alpine), mucho más ligera, con un consumo en reposo de unos 130 MB de RAM. - Fija una versión concreta como
postgres:18-alpineen vez de:latest, porque una etiqueta flotante puede saltar de versión mayor sin avisar durante un simple reinicio. - En PostgreSQL 18 la ruta de datos cambió: el volumen se monta ahora en
/var/lib/postgresql(antes era/var/lib/postgresql/data), un detalle que rompe muchas guías antiguas. - El servidor escucha en el puerto 5432 y los demás contenedores de la misma pila se conectan a él por el nombre del servicio (
db), sin necesidad de publicar el puerto en Internet.
¿Por qué ejecutar PostgreSQL en Docker?
PostgreSQL es un sistema de gestión de bases de datos objeto-relacional con más de 35 años de desarrollo a sus espaldas. Es la base de datos que está debajo de una parte enorme del ecosistema self-hosted: Nextcloud, Paperless-ngx, Wiki.js, Gitea o Outline la usan como almacén principal. Ejecutarla en un contenedor tiene una ventaja clara: en lugar de instalar paquetes en el sistema anfitrión, gestionar repositorios y arrastrar dependencias, arrancas una imagen ya preparada y aislada, y toda la configuración vive en un archivo que puedes versionar.
La imagen oficial resuelve el trabajo pesado por ti. La primera vez que arranca, ejecuta initdb, crea el usuario superadministrador y la base de datos inicial a partir de las variables de entorno, y deja el servidor escuchando en el puerto 5432. Si algún día quieres almacenar embeddings y hacer búsqueda semántica, existe una variante con la extensión pgvector, que tratamos en la guía de PostgreSQL con pgvector; aquí nos centramos en PostgreSQL puro como base de datos relacional de propósito general.
¿Cómo es el docker-compose.yml con volumen persistente?
Crea una carpeta para el proyecto y guarda dentro este docker-compose.yml. Cambia el valor cambia_esta_clave_segura por una contraseña propia y robusta antes de arrancar:
services:
db:
image: postgres:18-alpine
restart: unless-stopped
shm_size: 128mb
environment:
POSTGRES_USER: app
POSTGRES_PASSWORD: cambia_esta_clave_segura
POSTGRES_DB: appdb
volumes:
- pg_data:/var/lib/postgresql
ports:
- "127.0.0.1:5432:5432"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app -d appdb"]
interval: 10s
timeout: 5s
retries: 5
volumes:
pg_data:
Merece la pena detenerse en varios detalles. El volumen con nombre pg_data se monta en /var/lib/postgresql, la ruta correcta a partir de PostgreSQL 18; si copias una guía antigua que monta /var/lib/postgresql/data, el contenedor guardará los datos en el sitio equivocado y los perderás al recrearlo. Para entender la diferencia entre un volumen con nombre y un bind mount, revisa la guía sobre volúmenes y bind mounts en Docker. La opción shm_size: 128mb amplía la memoria compartida, porque Docker limita /dev/shm a 64 MB por defecto y las consultas paralelas o los índices grandes pueden quedarse cortos. Y al publicar el puerto como 127.0.0.1:5432:5432 lo dejas accesible solo desde la propia máquina, nunca expuesto a Internet.
Con el archivo listo, arranca la pila en segundo plano y comprueba el estado:
docker compose up -d
docker compose ps
docker compose logs -f db
La primera vez, PostgreSQL inicializa el directorio de datos y crea la base appdb, por lo que el arranque tarda unos segundos. Cuando el registro muestre database system is ready to accept connections, el servidor estará operativo.
¿Qué variables de entorno necesita la imagen?
La imagen se configura por completo con variables de entorno en el primer arranque. Solo una es obligatoria:
POSTGRES_PASSWORD: la contraseña del superusuario. No tiene valor por defecto, así que sin ella el contenedor se niega a arrancar.POSTGRES_USER: el nombre del superusuario. Si lo omites, se usapostgres.POSTGRES_DB: la base de datos que se crea al inicio. Si no la indicas, toma el mismo nombre quePOSTGRES_USER.POSTGRES_INITDB_ARGS: argumentos extra parainitdb, por ejemplo--data-checksumspara activar sumas de verificación que detectan corrupción en disco.
Un detalle importante: estas variables solo surten efecto la primera vez, cuando el volumen está vacío y se ejecuta initdb. Si cambias POSTGRES_PASSWORD con datos ya existentes, la contraseña no se actualizará sola; tendrás que cambiarla desde dentro con ALTER USER. Por eso conviene no meter contraseñas en texto plano dentro del docker-compose.yml de producción: lo recomendable es cargarlas desde un archivo .env o, mejor aún, con variables de entorno y secretos en Docker.
¿Cómo conectarse a PostgreSQL desde otros contenedores?
Aquí es donde Docker brilla. Todos los servicios definidos en el mismo docker-compose.yml comparten una red interna y se descubren por su nombre de servicio. Una aplicación en la misma pila se conecta a la base de datos usando db como host y 5432 como puerto, sin necesidad de publicar nada al exterior. La cadena de conexión típica sería:
postgres://app:cambia_esta_clave_segura@db:5432/appdb
Fíjate en que el host es db, no localhost ni una dirección IP: dentro de la red de Compose, el DNS interno de Docker resuelve db a la IP del contenedor de la base de datos. Para una app que dependa de PostgreSQL, lo ideal es que no arranque hasta que la base de datos esté sana; eso se consigue combinando el healthcheck anterior con depends_on, como se explica en la guía de healthchecks y políticas de reinicio.
Si prefieres administrar la base de datos con una interfaz web en vez de por línea de comandos, puedes añadir un cliente como Adminer o pgweb a la misma red; lo cubrimos en cómo administrar bases de datos con Adminer y pgweb. Y para una consulta rápida desde el propio contenedor, tienes psql a mano:
docker compose exec db psql -U app -d appdb
¿Cómo hacer copias de seguridad con pg_dump?
La regla de oro es que tus datos valen mucho más que el contenedor. El volumen pg_data guarda toda la base de datos, pero una copia lógica con pg_dump es más portátil y te permite restaurar en cualquier versión. Genera un volcado en formato personalizado (comprimido y apto para restauración selectiva) directamente desde el contenedor:
docker compose exec db pg_dump -U app -Fc appdb > appdb-$(date +%F).dump
Para restaurarlo en un servidor limpio, usa pg_restore sobre la base de datos ya creada:
cat appdb-2026-07-16.dump | docker compose exec -T db pg_restore -U app -d appdb --clean
Si gestionas varias bases de datos y quieres incluir también los roles y permisos globales, usa pg_dumpall en lugar de pg_dump. Automatiza el volcado con una tarea cron y guarda las copias fuera del servidor; una copia que vive en la misma máquina que la base de datos no es una copia de seguridad de verdad.
¿Cómo ajustar el rendimiento y el healthcheck?
Con la configuración por defecto, PostgreSQL reserva un shared_buffers de 128 MB, un valor conservador pensado para arrancar en cualquier sitio. En un servidor dedicado a la base de datos, la recomendación clásica es subirlo en torno al 25 % de la RAM del sistema. Puedes pasar parámetros de arranque sin tocar postgresql.conf añadiendo un command al servicio:
command: >
postgres
-c shared_buffers=256MB
-c max_connections=100
-c work_mem=16MB
El healthcheck que ya incluimos usa pg_isready, la herramienta oficial que comprueba si el servidor acepta conexiones. Con interval: 10s y retries: 5, Docker marca el contenedor como healthy en cuanto la base de datos responde, y como unhealthy si deja de hacerlo. Ese estado es justo lo que depends_on: condition: service_healthy necesita para que tus aplicaciones esperen a una base de datos realmente lista, en vez de fallar al conectar durante el arranque.
Preguntas frecuentes
¿Por qué no debo usar la etiqueta latest en producción?
Porque :latest apunta siempre a la última versión publicada y puede arrastrarte a un salto de versión mayor durante un reinicio rutinario, con cambios incompatibles en el formato de datos. Al fijar postgres:18-alpine te quedas en la rama 18 (la última mayor, de septiembre de 2025) y decides tú cuándo actualizar. Un salto entre versiones mayores de PostgreSQL requiere pg_upgrade o un volcado y restauración, nunca es automático.
¿Se pierden los datos si borro el contenedor?
No, siempre que uses un volumen con nombre como en esta guía. El contenedor es efímero, pero el volumen pg_data sobrevive a docker compose down y se vuelve a montar cuando recreas el servicio. Solo perderías los datos si ejecutas docker compose down -v, que elimina también los volúmenes, o si montas la ruta equivocada. Recuerda que en PostgreSQL 18 el volumen va en /var/lib/postgresql, no en /var/lib/postgresql/data.
¿Debo exponer el puerto 5432 a Internet?
No. Publicarlo como 127.0.0.1:5432:5432 lo deja accesible solo desde la propia máquina, que es lo habitual cuando la app y la base de datos conviven en el mismo servidor. Si de verdad necesitas acceso remoto, hazlo a través de una VPN o un túnel SSH y protégelo con una contraseña fuerte; exponer PostgreSQL directamente en la red pública es una de las causas más frecuentes de compromiso de datos.
Conclusión
Con un único docker-compose.yml tienes un servidor PostgreSQL persistente, con su volumen, sus variables de entorno y un healthcheck que garantiza arranques fiables. A partir de aquí, la base de datos queda lista para dar servicio al resto de tu infraestructura autoalojada: conecta tus aplicaciones por el nombre del servicio, añade un administrador web con Adminer o pgweb y, sobre todo, programa copias de seguridad periódicas con pg_dump y guárdalas fuera del servidor. Esa es la diferencia entre tener una base de datos y tener una base de datos que puedes recuperar.
Fuentes
- Imagen oficial de PostgreSQL en Docker Hub
- Documentación oficial de PostgreSQL
- Anuncio de PostgreSQL 18 (postgresql.org)
- Cambio de PGDATA y volumen en la imagen (docker-library/postgres, GitHub)
Ruta: Bases de datos y almacenamiento self-hosted con Docker