Respuesta rápida: levanta n8n y PostgreSQL con Docker Compose, publica n8n solo en 127.0.0.1 y pon NGINX con HTTPS delante. La clave está en el puerto del compose:
ports:
- "127.0.0.1:5678:5678"Así n8n no queda expuesto directamente a internet. Con WEBHOOK_URL=https://automatiza.ejemplo.com/ en el .env, los webhooks salen con la URL pública y no con localhost.
Nivel: intermedio · Requiere: Cloud Server Ubuntu con Docker Compose y un dominio apuntando a su IP
Automatizar tareas con n8n es relativamente simple en local. El problema aparece cuando quieres exponer flujos reales a Internet: webhooks, integraciones con APIs, formularios, CRMs, sistemas internos o herramientas de marketing.
Ahí ya no basta con ejecutar un contenedor y abrir un puerto. Necesitas una URL pública estable, HTTPS, una base de datos persistente, backups y una configuración que no deje expuestos servicios internos.
En esta guía vas a desplegar n8n self-hosted en un Cloud Server con Docker Compose, PostgreSQL, NGINX como reverse proxy y certificado TLS. El objetivo es tener una base sólida para ambientes productivos pequeños, pruebas serias o proyectos internos que necesitan automatización controlada.
¿Qué es n8n?
n8n es una herramienta de automatización de workflows. Permite conectar servicios, APIs, bases de datos y procesos internos mediante flujos visuales.
Puedes usarlo para tareas como:
- recibir un webhook y guardar datos en una base;
- sincronizar contactos entre herramientas;
- enviar alertas a Slack, email o Telegram;
- procesar formularios;
- ejecutar integraciones con APIs propias;
- automatizar tareas de soporte, ventas o infraestructura.
La ventaja del modo self-hosted es que controlas dónde corre la instancia, cómo se almacenan las credenciales y qué reglas de red aplicas.
¿Cuándo conviene usar n8n self-hosted?
Conviene usar n8n en tu propio servidor cuando necesitas más control que el que ofrece un servicio gestionado o cuando tus flujos trabajan con datos internos.
Algunos casos claros:
- automatizaciones internas de una empresa;
- integraciones con sistemas propios;
- webhooks que necesitan una URL estable;
- pruebas de automatización antes de escalar;
- flujos que requieren secretos, tokens o credenciales sensibles;
- proyectos donde quieres controlar backups, red y políticas de acceso.
No conviene exponer n8n sin HTTPS, sin autenticación o con puertos internos publicados directamente a Internet. n8n puede manejar credenciales sensibles, por lo que la seguridad inicial importa.
Requisitos previos
Para seguir esta guía necesitas:
- un Cloud Server con Ubuntu 22.04 LTS o 24.04 LTS;
- acceso SSH con un usuario con permisos
sudo; - un dominio o subdominio, por ejemplo
automatiza.ejemplo.com; - un registro DNS tipo
Aapuntando a la IP pública del servidor; - puertos
80y443abiertos para tráfico web; - puerto
22abierto solo para administración SSH; - Docker Engine y Docker Compose;
- NGINX;
- Certbot para emitir el certificado TLS.
En esta guía se usará:
80: HTTP, necesario para validación inicial y redirección;443: HTTPS, tráfico público real hacia n8n;5678: puerto interno de n8n, no debe publicarse a Internet;5432: puerto interno de PostgreSQL, no debe publicarse a Internet.
Paso 1: Preparar el servidor
Actualiza los paquetes base:
sudo apt update
sudo apt upgrade -yInstala herramientas necesarias:
sudo apt install -y ca-certificates curl gnupg ufw nginxConfigura reglas básicas de firewall. Si administras el servidor desde una IP fija, lo ideal es limitar SSH a esa IP:
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow from TU_IP_PUBLICA to any port 22 proto tcp
sudo ufw enable
sudo ufw status
Si todavía no conoces tu IP fija o estás configurando el servidor por primera vez, puedes permitir SSH temporalmente:
sudo ufw allow OpenSSHAdvertencia: antes de activar ufw, verifica que la regla de SSH esté bien configurada. Si cierras el puerto equivocado, puedes perder acceso al servidor.
[Imagen sugerida: preparación inicial del servidor con actualización, NGINX, UFW y SSH]
Paso 2: Instalar Docker Engine

Docker recomienda instalar Docker Engine desde su repositorio oficial en Ubuntu. Primero agrega la clave y el repositorio:
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
| sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" \
| sudo tee /etc/apt/sources.list.d/docker.list > /dev/nullLuego instala Docker y el plugin de Compose:
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-pluginVerifica que Docker funcione:
docker --version
docker compose versionOpcionalmente, agrega tu usuario al grupo docker para evitar usar sudo en cada comando:
sudo usermod -aG docker $USERDespués cierra sesión y vuelve a entrar por SSH.
Paso 3: Crear la estructura del proyecto
Crea un directorio para n8n:
sudo mkdir -p /opt/n8n
sudo chown -R $USER:$USER /opt/n8n
cd /opt/n8nGenera una clave fuerte para cifrar credenciales dentro de n8n:
openssl rand -base64 32Guarda ese valor. Lo vas a usar como N8N_ENCRYPTION_KEY.
Esta clave es importante: si la pierdes, puedes tener problemas para recuperar credenciales guardadas en n8n después de migraciones o restauraciones.

Paso 4: Crear el archivo .env
Crea un archivo .env:
nano .envPega una configuración como esta, ajustando dominio, contraseñas y zona horaria:
POSTGRES_DB=n8n
POSTGRES_USER=n8n
POSTGRES_PASSWORD=CAMBIAR_POR_UNA_PASSWORD_LARGA
N8N_HOST=automatiza.ejemplo.com
N8N_PROTOCOL=https
WEBHOOK_URL=https://automatiza.ejemplo.com/
N8N_PROXY_HOPS=1
N8N_ENCRYPTION_KEY=PEGAR_CLAVE_GENERADA_CON_OPENSSL
GENERIC_TIMEZONE=America/Argentina/Buenos_Aires
TZ=America/Argentina/Buenos_Aires
N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=trueNo uses contraseñas débiles ni valores de ejemplo en producción. El archivo .env contiene secretos y no debería subirse a un repositorio público.
Paso 5: Crear docker-compose.yml
En /opt/n8n, crea el archivo:
nano docker-compose.ymlPega esta configuración:
services:
postgres:
image: postgres:16-alpine
restart: unless-stopped
environment:
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- postgres_data:/var/lib/postgresql/data
networks:
- n8n_internal
n8n:
image: n8nio/n8n:latest
restart: unless-stopped
depends_on:
- postgres
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_HOST: ${N8N_HOST}
N8N_PROTOCOL: ${N8N_PROTOCOL}
WEBHOOK_URL: ${WEBHOOK_URL}
N8N_PROXY_HOPS: ${N8N_PROXY_HOPS}
N8N_ENCRYPTION_KEY: ${N8N_ENCRYPTION_KEY}
GENERIC_TIMEZONE: ${GENERIC_TIMEZONE}
TZ: ${TZ}
N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS: ${N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS}
volumes:
- n8n_data:/home/node/.n8n
ports:
- "127.0.0.1:5678:5678"
networks:
- n8n_internal
volumes:
postgres_data:
n8n_data:
networks:
n8n_internal:
driver: bridgeLa línea importante es esta:
ports:
- "127.0.0.1:5678:5678"Eso hace que n8n escuche solo en localhost. Internet no llega directamente al puerto 5678; el acceso público se hace por NGINX en 443.
En producción, conviene fijar una versión concreta de n8n en lugar de usar latest, por ejemplo cuando ya validaste una versión estable para tu flujo de trabajo. latest simplifica la guía, pero puede traer cambios inesperados en actualizaciones.

Paso 6: Iniciar n8n
Desde /opt/n8n, ejecuta:
docker compose up -dVerifica el estado:
docker compose ps
docker compose logs -f n8nPrueba localmente:
curl http://127.0.0.1:5678Si responde HTML o una redirección, n8n está levantado.

Paso 7: Configurar NGINX como reverse proxy
Crea un archivo de sitio para NGINX:
sudo nano /etc/nginx/sites-available/n8nPega esta configuración, cambiando el dominio:
server {
listen 80;
server_name automatiza.ejemplo.com;
location / {
proxy_pass http://127.0.0.1:5678;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
}
}Activa el sitio:
sudo ln -s /etc/nginx/sites-available/n8n /etc/nginx/sites-enabled/n8n
sudo nginx -t
sudo systemctl reload nginxAhora deberías poder abrir:
http://automatiza.ejemplo.comTodavía falta HTTPS. No uses credenciales reales ni conectes servicios externos hasta completar el certificado TLS.
Paso 8: Activar HTTPS con Certbot

Instala Certbot. En Ubuntu, una opción habitual es usar Snap:
sudo apt install -y snapd
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbotEmite el certificado para NGINX:
sudo certbot --nginx -d automatiza.ejemplo.comCertbot puede ajustar la configuración para usar HTTPS y redirigir HTTP a HTTPS.
Verifica renovación automática:
sudo certbot renew --dry-runA partir de este punto, la URL pública debería ser:
https://automatiza.ejemplo.comPaso 9: Configurar correctamente los webhooks
Cuando n8n está detrás de NGINX, hay una diferencia entre el puerto interno y la URL pública.
Internamente n8n escucha en:
http://127.0.0.1:5678Pero los servicios externos tienen que llamar a:
https://automatiza.ejemplo.com/webhook/...Por eso son importantes estas variables:
N8N_HOST=automatiza.ejemplo.com
N8N_PROTOCOL=https
WEBHOOK_URL=https://automatiza.ejemplo.com/
N8N_PROXY_HOPS=1Si WEBHOOK_URL queda mal configurada, n8n puede mostrar URLs con localhost, http o puertos internos. Eso rompe integraciones externas aunque el editor visual cargue bien.
Después de cambiar variables, reinicia los contenedores:
cd /opt/n8n
docker compose up -d
Paso 10: Probar que funciona
Desde el navegador, entra a:
https://automatiza.ejemplo.comCrea el usuario inicial de n8n y luego arma un flujo simple con un nodo Webhook.
Prueba la URL pública con curl:
curl -i https://automatiza.ejemplo.com/webhook/testLa ruta exacta dependerá del webhook que hayas creado. Lo importante es que la URL empiece con https://automatiza.ejemplo.com y no con localhost.
También puedes revisar logs:
docker compose logs -f n8n
sudo tail -f /var/log/nginx/access.log
sudo tail -f /var/log/nginx/error.log
Paso 11: Reforzar seguridad
Antes de usar n8n con datos reales, revisa estos puntos:
- mantén públicos solo
80y443; - no publiques
5678ni5432; - usa una
N8N_ENCRYPTION_KEYfuerte y persistente; - configura backups de los volúmenes
postgres_datayn8n_data; - usa contraseñas largas y únicas;
- mantén Docker, NGINX y el sistema operativo actualizados;
- revisa permisos del archivo
.env; - evita guardar tokens innecesarios en flujos de prueba;
- ejecuta auditorías de seguridad de n8n cuando corresponda;
- prueba restaurar backups, no solo generarlos.
n8n incluye una función de auditoría de seguridad que puede ayudar a detectar riesgos comunes. Según la documentación oficial, se puede ejecutar con:
docker compose exec n8n n8n auditBackups mínimos recomendados
Para una instalación simple, al menos necesitas respaldar:
- la base PostgreSQL;
- el volumen de datos de n8n;
- el archivo
.env; - el archivo
docker-compose.yml; - la configuración de NGINX.
Un backup básico de PostgreSQL podría verse así:
cd /opt/n8n
docker compose exec postgres pg_dump \
-U "$POSTGRES_USER" \
"$POSTGRES_DB" > backup-n8n.sqlEn algunos shells, las variables del .env no están cargadas automáticamente. Si el comando no toma los valores, puedes ejecutar:
source .envy luego repetir el backup.
Advertencia: guarda los backups fuera del servidor o en una ubicación separada. Un backup que vive únicamente en el mismo disco no te protege ante pérdida del servidor, borrado accidental o corrupción del volumen.

Problemas frecuentes
n8n muestra webhooks con localhost
Revisa estas variables:
N8N_HOST=automatiza.ejemplo.com
N8N_PROTOCOL=https
WEBHOOK_URL=https://automatiza.ejemplo.com/
N8N_PROXY_HOPS=1Después reinicia:
docker compose up -dEl navegador muestra error 502 Bad Gateway
NGINX no puede llegar a n8n. Verifica que el contenedor esté activo:
docker compose ps
docker compose logs n8nTambién comprueba que n8n responda localmente:
curl http://127.0.0.1:5678Certbot no puede emitir el certificado
Revisa que:
- el DNS apunte a la IP correcta;
- el puerto
80esté abierto; - NGINX esté activo;
- no haya otro servicio usando el puerto
80.
Puedes probar NGINX con:
sudo nginx -t
sudo systemctl status nginxPostgreSQL no inicia
Revisa logs:
docker compose logs postgresVerifica que no hayas cambiado POSTGRES_USER, POSTGRES_DB o POSTGRES_PASSWORD después de inicializar el volumen. En PostgreSQL, esos valores se usan al crear la base por primera vez; cambiarlos luego no modifica automáticamente la base ya creada.
El servidor queda sin acceso por SSH
Si activaste ufw sin permitir correctamente SSH, puedes perder acceso remoto. Antes de activar el firewall, confirma la regla:
sudo ufw statusSi usas el panel del proveedor cloud y tienes consola de emergencia, podrías corregirlo desde ahí. Aun así, es mejor prevenirlo.
Conclusión
n8n puede ser una pieza muy útil para automatizar procesos, pero cuando lo expones a Internet conviene tratarlo como cualquier aplicación de producción: dominio, HTTPS, base persistente, reverse proxy, firewall, backups y revisión de seguridad.
Con Docker Compose, PostgreSQL y NGINX puedes tener una instalación clara, mantenible y fácil de mover. Si necesitas un servidor para este tipo de despliegues, un Cloud Server de DonWeb te permite elegir Ubuntu, configurar tu stack y escalar recursos cuando tus automatizaciones crezcan.