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.
- 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.
- 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. - 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_URLyN8N_EDITOR_BASE_URL— le dicen a n8n qué URL pública mostrar. Sin ellas, la interfaz te entrega URLs de webhook conlocalhostadentro, 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_KEYguardada 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.
