Escribe algo para buscar...
PostgreSQL Self-Hosted con Docker y pgvector: Base de Datos para tus Servicios

PostgreSQL Self-Hosted con Docker y pgvector: Base de Datos para tus Servicios

En la arquitectura de alta disponibilidad con n8n que vimos anteriormente, uno de los requisitos era reemplazar SQLite por una base de datos real. PostgreSQL es la elección natural para un entorno self-hosted: es robusto, soporta concurrencia, y es compatible con prácticamente todos los servicios que iremos desplegando en esta serie.

Pero más allá de PostgreSQL estándar, en ECODING usamos la imagen pgvector — una variante que incluye soporte nativo para vectores. Esto nos permite usar la misma instancia para aplicaciones de IA sin levantar un servicio adicional.


¿Por qué pgvector y no postgres estándar?

La imagen oficial pgvector/pgvector:pg16 es PostgreSQL 16 con la extensión vector preinstalada. Esta extensión permite almacenar y consultar embeddings (representaciones numéricas de texto, imágenes o cualquier dato) directamente en la base de datos.

Si en algún momento conectas herramientas como n8n con nodos de IA, o despliegas aplicaciones RAG (Retrieval-Augmented Generation), ya tienes la infraestructura lista. No necesitas migrar a otra base de datos ni levantar una instancia separada como Qdrant o Pinecone para casos simples.

Para activar la extensión en cualquier base de datos:

CREATE EXTENSION IF NOT EXISTS vector;

Si nunca usas IA, pgvector se comporta exactamente igual que PostgreSQL estándar. No hay costo por tenerla instalada.


El docker-compose.yml

services:
  postgres:
    image: pgvector/pgvector:pg16
    container_name: postgres
    restart: unless-stopped
    environment:
      POSTGRES_USER: root
      POSTGRES_PASSWORD: TU_PASSWORD_SEGURO
      POSTGRES_DB: appdb
    volumes:
      - postgres_data:/var/lib/postgresql/data
    ports:
      - "127.0.0.1:5432:5432"
    networks:
      - backend-net

volumes:
  postgres_data:

networks:
  backend-net:
    external: true

Análisis de las decisiones de configuración

La imagen: pgvector/pgvector:pg16

image: pgvector/pgvector:pg16

El tag pg16 indica PostgreSQL 16 con pgvector. Si prefieres la imagen oficial sin pgvector, usa postgres:16. Ambas son intercambiables para uso general — la diferencia es solo la extensión adicional.

¿Cuándo usar cada una?

ImagenCuándo usarla
pgvector/pgvector:pg16Cuando tienes o planeas tener flujos de IA, embeddings, o búsqueda semántica
postgres:16Entorno puramente relacional, sin IA

container_name y hostname en la red

container_name: postgres

El container_name cumple dos funciones: define el nombre del contenedor en Docker (docker ps) y registra ese nombre como hostname adicional dentro de la red Docker. Esto significa que otros servicios pueden referenciarlo por ese nombre.

En el stack de n8n que vimos anteriormente, la variable de conexión es:

- DB_POSTGRESDB_HOST=postgres

Ese valor coincide con el container_name definido aquí. Sin container_name, el hostname en la red sería simplemente el nombre del servicio en el compose (postgres en este caso), pero con servicios que tienen nombres ambiguos o compuestos, fijarlo explícitamente evita confusiones.

restart: unless-stopped vs always

restart: unless-stopped

Esta diferencia es sutil pero importante:

PolíticaComportamiento
alwaysSe reinicia siempre, incluso si fue detenido manualmente
unless-stoppedSe reinicia tras fallas o reinicios del servidor, pero respeta un docker stop manual

Para una base de datos, unless-stopped es la elección correcta. Si necesitas detener PostgreSQL para mantenimiento (backup, upgrade de imagen), no quieres que Docker lo vuelva a levantar automáticamente mientras trabajas. Con always, tendría que hacer docker stop y luego contrarrestar el reinicio automático.

Para n8n usamos always porque si el proceso muere queremos recuperación total sin intervención. Para infraestructura que tocamos manualmente con más frecuencia, unless-stopped da más control.

Puerto: enlazar solo a localhost

La configuración original expone el puerto directamente:

ports:
  - "5432:5432"    # ⚠️ accesible desde cualquier IP del servidor

Esto significa que cualquier IP que llegue al servidor puede intentar conectarse a PostgreSQL en el puerto 5432. Para producción, la recomendación es enlazarlo solo a la interfaz local:

ports:
  - "127.0.0.1:5432:5432"    # solo accesible desde el propio servidor

Así, la base de datos solo es alcanzable desde el host local o desde dentro de la red Docker (backend-net). Si necesitas acceso remoto para administración, hazlo a través de un túnel SSH:

ssh -L 5432:localhost:5432 usuario@tu-servidor

Esto te permite conectar con cualquier cliente PostgreSQL (pgAdmin, DBeaver, psql) desde tu máquina local de forma segura.

Volumen local vs externo

volumes:
  postgres_data:    # volumen local gestionado por Docker

A diferencia del volumen n8n_data que definimos como external: true, aquí el volumen es gestionado por Docker Compose directamente. La diferencia práctica:

  • Volumen externo (external: true): debes crearlo manualmente antes de docker compose up. Si no existe, el comando falla. Útil cuando el volumen es compartido entre múltiples stacks.
  • Volumen local (sin external): Docker lo crea automáticamente si no existe al levantar el stack. Más simple para stacks independientes.

Para PostgreSQL, el volumen no es compartido con ningún otro servicio, así que no necesita ser externo. Si haces docker compose down, el volumen persiste — solo se elimina con docker compose down -v, que debes ejecutar conscientemente.

Usuario root como superusuario inicial

POSTGRES_USER: root
POSTGRES_PASSWORD: TU_PASSWORD_SEGURO
POSTGRES_DB: appdb

El POSTGRES_USER en la imagen de PostgreSQL crea el superusuario inicial con ese nombre. Usar root funciona, pero para producción es recomendable crear usuarios dedicados por aplicación con permisos mínimos. Esto limita el impacto si las credenciales de una aplicación se ven comprometidas:

-- Crear usuario dedicado para n8n
CREATE USER n8n_user WITH PASSWORD 'otra_password_segura';
CREATE DATABASE n8n_db OWNER n8n_user;
GRANT ALL PRIVILEGES ON DATABASE n8n_db TO n8n_user;

Así cada servicio tiene su propia base de datos y credenciales, sin acceso a las demás.


Bases de datos por servicio

La instancia de PostgreSQL actúa como servidor compartido para todos tus servicios self-hosted. La variable POSTGRES_DB define solo la base de datos inicial — puedes crear todas las que necesites después.

Estructura recomendada para la serie:

ServicioBase de datosUsuario
n8nn8n_dbn8n_user
Aplicación propiaappdbapp_user
Otros serviciosservicio_dbservicio_user

Levantar el stack

# La red debe existir (se crea una sola vez por servidor)
docker network create backend-net

# Levantar PostgreSQL
docker compose up -d

# Verificar que está corriendo
docker compose ps

# Conectarse a psql dentro del contenedor
docker exec -it postgres psql -U root -d appdb

# Ver logs
docker compose logs -f postgres

Conectar desde n8n

Si seguiste el post anterior de n8n, las variables de entorno ya apuntan a este servicio:

- DB_POSTGRESDB_HOST=postgres
- DB_POSTGRESDB_PORT=5432
- DB_POSTGRESDB_DATABASE=n8n_db
- DB_POSTGRESDB_USER=n8n_user
- DB_POSTGRESDB_PASSWORD=TU_PASSWORD_SEGURO

Ambos stacks deben estar en la misma red (backend-net) para que la resolución de hostname funcione. No es necesario exponer el puerto 5432 al host para que n8n se conecte — la comunicación ocurre internamente en la red Docker.


Consideraciones para producción

  • Backups automáticos: Los datos de PostgreSQL viven en el volumen postgres_data. Configura backups periódicos con pg_dump:
docker exec postgres pg_dump -U root n8n_db > backup_$(date +%Y%m%d).sql
  • Logs de conexiones lentas: Agrega command: postgres -c log_min_duration_statement=1000 para registrar queries que tarden más de 1 segundo.

  • Límite de conexiones: PostgreSQL 16 tiene un máximo de 100 conexiones concurrentes por defecto. Si tienes múltiples servicios conectados, considera aumentarlo en postgresql.conf o usar PgBouncer como pooler de conexiones.


En el próximo post de la serie veremos la configuración de Redis, que completa la infraestructura base para n8n en modo queue y para cualquier otro servicio que necesite caché o colas.

Related Posts

Introducción al flujo de trabajo en GitHub

Introducción al flujo de trabajo en GitHub

El flujo de GitHub Además de ser una plataforma de desarrollo de software colaborativo, GitHub ofrece también un flujo de trabajo diseñado para optimizar el uso de sus diversas características. Au

leer más
Instalación de n8n con Docker: Guía Completa

Instalación de n8n con Docker: Guía Completa

En esta guía explicaremos cómo instalar n8n utilizando Docker, la forma recomendada para la mayoría de casos de uso. Docker proporciona un entorno aislado y limpio, evita incompatibilidades en

leer más
Descargue y configurar el servidor OpenVPN en Ubuntu

Descargue y configurar el servidor OpenVPN en Ubuntu

InstalaciónDescargar openvpn-install.sh💻 $ wget https://git.io/vpn -O openvpn-install.sh... Saving to: ‘openvpn-install.sh’ openvpn-install.sh 100%[====

leer más
Comandos de Git

Comandos de Git

Git es un sistema de control de versiones que permite a los desarrolladores colaborar en proyectos de software y mantener un historial de cambios en el código fuente. A continuación, se describen algu

leer más
Desplegando n8n en una VM de GCP con Cloudflare Tunnel

Desplegando n8n en una VM de GCP con Cloudflare Tunnel

En esta guía explico cómo instalar y exponer n8n en una máquina virtual de Google Cloud Platform (GCP) utilizando Cloudflare Tunnel. La idea es mantener la instancia lo más ligera posible,

leer más
n8n en Producción: Alta Disponibilidad con Docker, Redis y PostgreSQL

n8n en Producción: Alta Disponibilidad con Docker, Redis y PostgreSQL

Si ya tienes n8n funcionando con Docker en su configuración básica, sabes que es una herramienta poderosa. Pero cuando los flujos de trabajo se vuelven críticos para tu operación — automatizaciones qu

leer más
Redis Self-Hosted con Docker: Caché y Colas para tus Servicios

Redis Self-Hosted con Docker: Caché y Colas para tus Servicios

Con PostgreSQL ya desplegado como base de datos persistente, el último componente de la infraestructura base es Redis. En el stack de [n8n en alta

leer más
Implementando SSO corporativo con Keycloak y OpenID Connect (paso a paso con un ejemplo práctico)

Implementando SSO corporativo con Keycloak y OpenID Connect (paso a paso con un ejemplo práctico)

El escenario: de auth legacy a SSO corporativo Partimos de una app interna de ejemplo:Nombre: secrets-admin URL: https://secrets-admin.example.com Tipo: aplicación web interna que gest

leer más
Descargar Nginx y configurar el Reverse Proxy en Ubuntu

Descargar Nginx y configurar el Reverse Proxy en Ubuntu

Paso 1: Actualizar repositorios Antes de comenzar, debemos asegurarnos de que los repositorios estén actualizados. Para ello, ejecutamos el siguiente comando en la terminal: sudo apt

leer más
Guía Completa del Servidor Hytale: Configuración y Administración

Guía Completa del Servidor Hytale: Configuración y Administración

Guía Completa del Servidor Hytale: Configuración y Administración ¿Quieres crear tu propio servidor de Hytale pero no sabes por dónde empezar? Esta guía te llevará paso a paso por todo lo que neces

leer más
Guía Completa de Markdown: Domina el Lenguaje de Marcado Ligero

Guía Completa de Markdown: Domina el Lenguaje de Marcado Ligero

¿Qué es Markdown? Markdown es un lenguaje de marcado ligero creado por John Gruber en 2004. Está diseñado para ser fácil de leer y escribir, utilizando una sintaxis de texto plano que se puede

leer más