Cómo instalar n8n en un VPS paso a paso (Docker, PostgreSQL y HTTPS)

               

Qué vas a tener al final de esta guía

Una instancia de n8n corriendo en tu propio VPS, con PostgreSQL como base de datos, HTTPS válido con renovación automática y webhooks accesibles desde internet. Es la configuración que aguanta producción, no la de “probar cinco minutos”.

Si lo que buscas es entender antes cuánta RAM necesitas, parte por los requisitos de servidor para n8n. Si quieres saber si te conviene autohospedar o pagar la nube, mira la comparativa de costos en pesos chilenos.

Antes de empezar: los tres errores que arruinan la instalación

Casi todas las instalaciones de n8n que fallan a los dos meses fallan por lo mismo. Vale la pena leer esto antes de tocar la consola.

  1. Quedarse con SQLite. n8n usa SQLite por defecto. Funciona para probar, pero se degrada con volumen de ejecuciones y complica los respaldos en caliente. Para producción va PostgreSQL, y hay que decidirlo antes de la primera ejecución: migrar después es un trabajo aparte.
  2. No guardar la N8N_ENCRYPTION_KEY. Esa clave es la que descifra todas tus credenciales guardadas (tokens de API, claves de Google, contraseñas SMTP). Si la pierdes, tus credenciales quedan inservibles aunque tengas respaldo de la base de datos. Se genera una vez y se guarda en tu gestor de contraseñas.
  3. Exponer el puerto 5678 directo a internet. n8n no está pensado para recibir tráfico público sin nada delante. Va detrás de un proxy inverso con TLS.

Paso 1: prepara el VPS

Conéctate por SSH como root y deja el sistema al día:

apt update && apt upgrade -y
apt install -y ca-certificates curl gnupg ufw

Crea un usuario sin privilegios de root para el día a día:

adduser n8nadmin
usermod -aG sudo n8nadmin

Deja el firewall con lo mínimo abierto. Nota que no abrimos el 5678: n8n solo será accesible a través del proxy.

ufw allow OpenSSH
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable

Paso 2: instala Docker

curl -fsSL https://get.docker.com | sh
usermod -aG docker n8nadmin

Cierra la sesión SSH y vuelve a entrar como n8nadmin para que tome el grupo docker. Verifica:

docker --version
docker compose version

Paso 3: apunta tu dominio al VPS

En el DNS de tu dominio crea un registro A apuntando a la IP del servidor:

n8n.tudominio.cl.    A    203.0.113.10

Esto no es opcional. n8n sin un dominio con HTTPS no puede recibir webhooks, y sin webhooks pierdes la mitad de para qué sirve: no hay disparadores desde formularios, ni desde Stripe, ni desde WhatsApp, ni desde ningún servicio externo. Espera a que propague antes de seguir:

dig +short n8n.tudominio.cl

Paso 4: arma la estructura de archivos

mkdir -p ~/n8n && cd ~/n8n

Genera la clave de cifrado y una contraseña para PostgreSQL:

openssl rand -hex 32   # esta es tu N8N_ENCRYPTION_KEY
openssl rand -hex 24   # esta es tu POSTGRES_PASSWORD

Copia la primera a tu gestor de contraseñas ahora. No después.

Crea el archivo .env:

POSTGRES_USER=n8n
POSTGRES_PASSWORD=pega_aqui_la_segunda_clave
POSTGRES_DB=n8n

N8N_ENCRYPTION_KEY=pega_aqui_la_primera_clave
N8N_HOST=n8n.tudominio.cl

Protégelo:

chmod 600 .env

Paso 5: el docker-compose.yml

Tres servicios: PostgreSQL para los datos, n8n para la aplicación, y Caddy como proxy inverso (se encarga solo del certificado SSL de Let’s Encrypt, incluida la renovación).

services:
  postgres:
    image: postgres:16-alpine
    restart: unless-stopped
    environment:
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DB: ${POSTGRES_DB}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ['CMD-SHELL', 'pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}']
      interval: 10s
      timeout: 5s
      retries: 10

  n8n:
    image: docker.n8n.io/n8nio/n8n
    restart: unless-stopped
    environment:
      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}
      N8N_ENCRYPTION_KEY: ${N8N_ENCRYPTION_KEY}
      N8N_HOST: ${N8N_HOST}
      N8N_PORT: 5678
      N8N_PROTOCOL: https
      WEBHOOK_URL: https://${N8N_HOST}/
      N8N_EDITOR_BASE_URL: https://${N8N_HOST}/
      GENERIC_TIMEZONE: America/Santiago
      TZ: America/Santiago
      N8N_RUNNERS_ENABLED: "true"
      N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS: "true"
      EXECUTIONS_DATA_PRUNE: "true"
      EXECUTIONS_DATA_MAX_AGE: 336
    volumes:
      - n8n_data:/home/node/.n8n
    depends_on:
      postgres:
        condition: service_healthy

  caddy:
    image: caddy:2-alpine
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy_data:/data
      - caddy_config:/config
    depends_on:
      - n8n

volumes:
  postgres_data:
  n8n_data:
  caddy_data:
  caddy_config:

Un par de decisiones que conviene entender:

  • GENERIC_TIMEZONE: America/Santiago — sin esto, los nodos Schedule y Cron corren en UTC. Tus automatizaciones “de las 9 de la mañana” se dispararían a las 5 o 6 AM según el horario de verano.
  • EXECUTIONS_DATA_MAX_AGE: 336 — borra el historial de ejecuciones con más de 14 días (336 horas). Sin esto, la base crece sin freno y en unos meses te come el disco.
  • WEBHOOK_URL y N8N_EDITOR_BASE_URL — le dicen a n8n qué URL pública mostrar. Sin ellas, la interfaz te entrega URLs de webhook con localhost adentro, que no sirven para nada.
  • N8N_RUNNERS_ENABLED: "true" — habilita los task runners, que ejecutan el código de los nodos Code en un proceso aislado. Es la forma recomendada actualmente.

Paso 6: el Caddyfile

En la misma carpeta, un archivo llamado Caddyfile con exactamente esto:

n8n.tudominio.cl {
    reverse_proxy n8n:5678
}

Eso es todo. Caddy pide el certificado a Let’s Encrypt al arrancar y lo renueva solo. No hay que configurar certbot ni cron.

Paso 7: levanta el stack

docker compose up -d
docker compose logs -f n8n

Cuando veas que n8n terminó de arrancar, abre https://n8n.tudominio.cl en el navegador. Te va a pedir crear la cuenta de propietario. Créala con una contraseña fuerte: esa cuenta controla toda la instancia.

Paso 8: verifica que los webhooks funcionan de verdad

Este paso se salta seguido y es el que más problemas causa después. Crea un flujo nuevo, agrega un nodo Webhook, y mira la URL de producción que te muestra. Tiene que empezar con https://n8n.tudominio.cl/webhook/. Si aparece localhost o una IP, revisa WEBHOOK_URL en el .env.

Actívalo y pruébalo desde tu máquina:

curl -X POST https://n8n.tudominio.cl/webhook/tu-ruta   -H "Content-Type: application/json"   -d '{"prueba": "ok"}'

Paso 9: respaldos

Hay dos cosas que respaldar, y son distintas.

La base de datos (flujos, credenciales cifradas, historial):

docker compose exec -T postgres pg_dump -U n8n n8n | gzip > ~/backups/n8n-$(date +%F).sql.gz

La clave de cifrado, que vive en el volumen n8n_data:

docker compose exec n8n cat /home/node/.n8n/config

Un respaldo de la base sin la clave de cifrado no te devuelve las credenciales. Guarda las dos cosas, y en lugares distintos.

Automatiza el volcado diario con cron:

0 3 * * * cd /home/n8nadmin/n8n && docker compose exec -T postgres pg_dump -U n8n n8n | gzip > /home/n8nadmin/backups/n8n-$(date +%F).sql.gz

Paso 10: actualizar sin perder los flujos

cd ~/n8n
docker compose exec -T postgres pg_dump -U n8n n8n | gzip > ~/backups/pre-update-$(date +%F).sql.gz
docker compose pull
docker compose up -d

Los flujos y credenciales viven en PostgreSQL y en el volumen, no en la imagen. Actualizar la imagen no los toca. Aun así, el volcado previo cuesta diez segundos y te salva de una migración de esquema que salga mal.

Cuándo esto ya no alcanza: modo cola

La configuración de arriba corre todo en un solo proceso. Aguanta bien hasta unas decenas de ejecuciones concurrentes. Cuando empieces a ver ejecuciones encoladas o timeouts, toca pasar a modo cola: se agrega Redis como intermediario y n8n reparte el trabajo entre procesos worker separados.

Los cambios de fondo son EXECUTIONS_MODE=queue, un servicio Redis con QUEUE_BULL_REDIS_HOST, y uno o más contenedores extra corriendo n8n worker. Es un salto de arquitectura, no un ajuste — pero es la razón por la que conviene partir con PostgreSQL desde el día uno: los workers necesitan una base compartida, y SQLite no sirve para eso.

Resumen de lo que no puedes olvidar

  • PostgreSQL desde el inicio, no SQLite.
  • N8N_ENCRYPTION_KEY guardada fuera del servidor.
  • Dominio con HTTPS, o los webhooks no funcionan.
  • Puerto 5678 cerrado al mundo, solo accesible por el proxy.
  • Zona horaria America/Santiago.
  • Poda de ejecuciones activada.
  • Respaldo de base y de clave de cifrado.

Si prefieres que llegue instalado

Todo lo anterior toma entre una y tres horas la primera vez, y algo menos si ya manejas Docker. En nuestros VPS para n8n entregamos el servidor con n8n, PostgreSQL y Caddy ya configurados, el subdominio con SSL activo y la clave de cifrado respaldada, con infraestructura en Chile y soporte en español. Si prefieres armarlo tú desde cero, un VPS estándar también te sirve — esta guía funciona igual.

Ir a Blog