Arquitectura n8n + PostgreSQL

El problema de SQLite en Render y cómo PostgreSQL lo soluciona 💾

Una guía visual sobre por qué perdías tus datos en Render y cómo PostgreSQL garantiza su persistencia

El Problema: SQLite en Render

¿Por qué desaparecían tus datos?

SQLite en Render

SQLite guarda los datos en un archivo dentro del contenedor. En Render, los contenedores son efímeros - se destruyen con cada actualización.

Contenedor reinicia = Datos perdidos

Render Reinicia Siempre

Render recrea los contenedores frecuentemente: por actualizaciones, cambios de configuración, o simplemente por mantenimiento del servicio.

Cada reinicio = SQLite se borra

El Ciclo de Pérdida en Render

1. Despliegas n8n con SQLite en Render
2. Creas workflows y guardas credenciales
3. Render reinicia el contenedor (actualización, mantenimiento, etc.)
4. Todo desaparece - el archivo SQLite se destruye
5. Vuelves a empezar desde cero 😢

¿Por qué desapareció todo?

El crimen de la "Memoria de Pez" en Render

1. El problema de la "Memoria de Pez" (SQLite en Render)

El Escenario:

Render (y muchos servicios cloud) tratan a los contenedores como efímeros. Piensa en ellos como habitaciones de hotel.

SQLite:

Es un archivo (database.sqlite) que vive dentro de esa habitación.

El Desastre:

Cuando Render hace un "re-deploy" (actualización o reinicio), es como si hiciera el checkout del hotel y quemara la habitación. Todo lo que estaba adentro (el archivo SQLite con sus flujos y ejecuciones) se destruye. Se crea una habitación nueva, limpia y vacía.

2. La Solución: PostgreSQL (El Cerebro Externo)

🐘

Postgres

En lugar de guardar los datos dentro de la habitación (contenedor), contratamos una caja fuerte externa blindada.

🔌

La Conexión

n8n (la aplicación) se conecta por un "cable" (red interna) a esta caja fuerte.

El Resultado

Si n8n se reinicia, se actualiza o explota, no importa. Al volver a encenderse, se conecta a la caja fuerte y ahí está todo.

3. La Llave Maestra (N8N_ENCRYPTION_KEY)

Esta variable es la llave de la caja fuerte. Si reinstalan todo pero pierden esta clave, perderán el acceso a todas las credenciales (APIs, contraseñas) guardadas en n8n, aunque tengan la base de datos.

¡Guárdenla como oro!

La Solución: PostgreSQL

Persistencia garantizada, sin importar cuántas veces reinicie

PostgreSQL: La Caja Fuerte Externa

PostgreSQL guarda tus datos fuera del contenedor de n8n, ya sea en un volumen Docker persistente o como servicio independiente en Render. Tus datos sobreviven a cualquier reinicio.

Como Contenedor Docker

Usando docker-compose, PostgreSQL corre en un contenedor separado con volúmenes persistentes. Los datos se guardan en el disco físico de tu servidor.

✓ Datos Persistentes

Como Servicio en Render

Render ofrece PostgreSQL como servicio completamente independiente. n8n se conecta a esta base de datos externa y tus datos están siempre seguros.

✓ Separación Total

Arquitectura del Sistema

Cómo se separan las "cajas" (servicios) para proteger tu información

graph TD
    subgraph SERVER ["Servidor / Docker Host"]
        style SERVER fill:#f9f9f9,stroke:#333,stroke-width:2px
        
        subgraph NETWORK ["Red Interna Privada"]
            style NETWORK fill:#e1f5fe,stroke:#0277bd,stroke-dasharray: 5 5
            
            N8N[("🚀 Contenedor n8n
(Procesamiento / Stateless)")] PG[("🐘 Contenedor PostgreSQL
(Base de Datos / Stateful)")] end DISK[("💾 Disco Físico del Servidor
(Volumen Docker)")] N8N -- "Lee/Escribe Datos (Puerto 5432)" --> PG PG -- "Guarda Datos Permanentemente" --> DISK style N8N fill:#ff6b6b,stroke:#c0392b,color:white style PG fill:#3498db,stroke:#2980b9,color:white style DISK fill:#2ecc71,stroke:#27ae60,color:white end INTERNET((Internet)) --> N8N
🚀

n8n

Puede reiniciarse sin perder datos

🐘

PostgreSQL

Base de datos externa persistente

💾

Volumen Docker

Datos seguros en el disco físico

El Código Simplificado

docker-compose.yml - Solo n8n + PostgreSQL

Este archivo despliega n8n + PostgreSQL de forma simple, sin proxies reversos ni complejidades adicionales. Solo dos servicios: n8n y la base de datos.

docker-compose.yml
services:
  #################################################################
  # SERVICIO 1: PostgreSQL (La solución al problema de SQLite)
  #################################################################
  postgres:
    image: postgres:17-alpine
    restart: unless-stopped
    
    environment:
      - POSTGRES_USER=${POSTGRES_USER}
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
      - POSTGRES_DB=${POSTGRES_DB}
    
    # 💾 CLAVE: Volumen persistente
    # Los datos se guardan en el disco, NO en el contenedor
    volumes:
      - postgres_data:/var/lib/postgresql/data
    
    networks:
      - n8n-internal
    
    # Verificación de salud
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
      start_period: 30s
      interval: 10s
      timeout: 5s
      retries: 5

  #################################################################
  # SERVICIO 2: n8n (La aplicación)
  #################################################################
  n8n:
    image: n8nio/n8n:latest
    restart: unless-stopped
    
    # Puerto expuesto para acceder a n8n
    ports:
      - "5678:5678"
    
    environment:
      # Configuración para usar PostgreSQL (NO SQLite)
      - DB_TYPE=postgresdb
      - DB_POSTGRESDB_HOST=postgres
      - DB_POSTGRESDB_PORT=5432
      - DB_POSTGRESDB_DATABASE=${POSTGRES_DB}
      - DB_POSTGRESDB_USER=${POSTGRES_USER}
      - DB_POSTGRESDB_PASSWORD=${POSTGRES_PASSWORD}
      
      # Llave de encriptación (¡Guárdala!)
      - N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY}
      
      # Configuración general
      - N8N_HOST=${N8N_HOST}
      - N8N_PORT=5678
      - N8N_PROTOCOL=https
      - NODE_ENV=production
      - WEBHOOK_URL=https://${N8N_HOST}/
      - GENERIC_TIMEZONE=${GENERIC_TIMEZONE}
      
    volumes:
      - n8n_data:/home/node/.n8n
      
    networks:
      - n8n-internal
    
    # Espera a que PostgreSQL esté lista
    depends_on:
      postgres:
        condition: service_healthy

#################################################################
# INFRAESTRUCTURA
#################################################################
networks:
  n8n-internal:
    driver: bridge

volumes:
  n8n_data:
  postgres_data:  # ¡Datos persistentes aquí!

El Archivo .env

Configuración de Variables (Secreto)

Este archivo es secreto

Nunca debe compartirse públicamente. Aquí definimos los valores reales.

.env
# Dominio donde vivirá la app
N8N_HOST=n8n.adcon.dev
N8N_PORT=5678

# Zona horaria (Muy importante para automatizaciones que corren a cierta hora)
GENERIC_TIMEZONE=America/Mazatlan

# Credenciales de la Base de Datos (El usuario y pass que usará Postgres)
POSTGRES_USER=alba_crooks
POSTGRES_PASSWORD=jkhivqakg3m2zmzhw8v3hwzu
POSTGRES_DB=n8n

# ¡LA LLAVE MAESTRA! 
# Si pierdes esto, pierdes acceso a tus credenciales de Google/Slack/etc dentro de n8n.
N8N_ENCRYPTION_KEY=IsXnOohoz1UpSirWZfPrYD7YMp+UgLYHWS8+buDKJhgXyj9Mlb20B6eCBINEc6Sn7VSoquwdwAd5cF/dM4PUSw==

Dos Caminos, Una Solución

¿Por qué Docker Compose y Render PostgreSQL resuelven lo mismo?

El Problema Central

Tanto Docker Compose con PostgreSQL como Render con PostgreSQL como servicio solucionan exactamente el mismo problema: la pérdida de datos de SQLite en contenedores efímeros.

La Solución es la Misma: Separación de Responsabilidades

🐳

Docker Compose

Creas dos contenedores separados:

  • n8n (Stateless): Puede destruirse y recrearse
  • PostgreSQL (Stateful): Guarda datos en un volumen Docker persistente
  • Los datos viven en el disco físico del servidor (/var/lib/docker/volumes/)
☁️

Render PostgreSQL

Creas dos servicios separados:

  • n8n Web Service (Stateless): Puede reiniciarse sin perder datos
  • PostgreSQL Service (Stateful): Servicio gestionado por Render
  • Los datos viven en la infraestructura de Render (separada de n8n)

El Concepto Clave: Separación de Datos y Aplicación

En ambos casos, la solución es la misma:

📦
Aplicación

n8n es efímero y puede reiniciarse sin consecuencias

↔️
Separación

Se conectan por red, pero viven en lugares diferentes

💾
Base de Datos

PostgreSQL es persistente y guarda todo de forma permanente

La magia no está en Docker o Render, está en usar PostgreSQL como servicio externo

Comparación Lado a Lado

Aspecto Docker Compose Render PostgreSQL
Dónde viven los datos Volumen Docker en tu servidor Infraestructura de Render (gestionada)
Quién gestiona la DB Tú (manualmente) Render (automático)
Backups Debes configurarlos tú Automáticos (según el plan)
Escalabilidad Limitada a tu servidor Fácil escalado (cambiar plan)
Problema que resuelve ✅ Pérdida de datos SQLite ✅ Pérdida de datos SQLite
Principio arquitectónico Separación App ↔ DB Separación App ↔ DB
🎯

Conclusión

No importa si usas Docker Compose en tu servidor o PostgreSQL como servicio en Render: ambos implementan el mismo patrón arquitectónico de separación entre aplicación y datos.

La clave está en que PostgreSQL (la base de datos) viva separada e independiente de n8n (la aplicación). Así, cuando n8n se reinicia o actualiza, tus datos están seguros en otro lugar.

Persistencia garantizada
Arquitectura resiliente
Listo para producción
Desarrollado con usando Docker, PostgreSQL y n8n