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 A apuntando a la IP pública del servidor;
  • puertos 80 y 443 abiertos para tráfico web;
  • puerto 22 abierto 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 -y

Instala herramientas necesarias:

sudo apt install -y ca-certificates curl gnupg ufw nginx

Configura 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
Paso 1: preparar el servidor antes de instalar nada

Si todavía no conoces tu IP fija o estás configurando el servidor por primera vez, puedes permitir SSH temporalmente:

sudo ufw allow OpenSSH

Advertencia: 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

Paso 2: instalar Docker Engine en el servidor

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/null

Luego 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-plugin

Verifica que Docker funcione:

docker --version
docker compose version

Opcionalmente, agrega tu usuario al grupo docker para evitar usar sudo en cada comando:

sudo usermod -aG docker $USER

Despué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/n8n

Genera una clave fuerte para cifrar credenciales dentro de n8n:

openssl rand -base64 32

Guarda 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 3: crear la estructura de directorios del proyecto

Paso 4: Crear el archivo .env

Crea un archivo .env:

nano .env

Pega 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=true

No 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.yml

Pega 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: bridge

La 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 5: escribir el archivo Compose con n8n y PostgreSQL en red interna

Paso 6: Iniciar n8n

Desde /opt/n8n, ejecuta:

docker compose up -d

Verifica el estado:

docker compose ps
docker compose logs -f n8n

Prueba localmente:

curl http://127.0.0.1:5678

Si responde HTML o una redirección, n8n está levantado.

Paso 6: iniciar n8n y comprobar que responde en local antes de exponerlo

Paso 7: Configurar NGINX como reverse proxy

Crea un archivo de sitio para NGINX:

sudo nano /etc/nginx/sites-available/n8n

Pega 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 nginx

Ahora deberías poder abrir:

http://automatiza.ejemplo.com

Todavía falta HTTPS. No uses credenciales reales ni conectes servicios externos hasta completar el certificado TLS.




Paso 8: Activar HTTPS con Certbot

Paso 8: activar HTTPS con Certbot sobre el dominio configurado

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/certbot

Emite el certificado para NGINX:

sudo certbot --nginx -d automatiza.ejemplo.com

Certbot puede ajustar la configuración para usar HTTPS y redirigir HTTP a HTTPS.

Verifica renovación automática:

sudo certbot renew --dry-run

A partir de este punto, la URL pública debería ser:

https://automatiza.ejemplo.com

Paso 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:5678

Pero 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=1

Si 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 9: configurar los webhooks con la URL pública y los saltos de proxy correctos

Paso 10: Probar que funciona

Desde el navegador, entra a:

https://automatiza.ejemplo.com

Crea 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/test

La 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 10: probar que funciona abriendo la URL con HTTPS, creando el usuario inicial, lanzando un webhook de prueba y revisando los logs

Paso 11: Reforzar seguridad

Antes de usar n8n con datos reales, revisa estos puntos:

  • mantén públicos solo 80 y 443;
  • no publiques 5678 ni 5432;
  • usa una N8N_ENCRYPTION_KEY fuerte y persistente;
  • configura backups de los volúmenes postgres_data y n8n_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 audit

Backups 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.sql

En algunos shells, las variables del .env no están cargadas automáticamente. Si el comando no toma los valores, puedes ejecutar:

source .env

y 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.

Paso 11: arquitectura final reforzada, con NGINX y TLS delante y n8n y PostgreSQL en la red interna del Cloud Server

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=1

Después reinicia:

docker compose up -d

El navegador muestra error 502 Bad Gateway

NGINX no puede llegar a n8n. Verifica que el contenedor esté activo:

docker compose ps
docker compose logs n8n

También comprueba que n8n responda localmente:

curl http://127.0.0.1:5678

Certbot no puede emitir el certificado

Revisa que:

  • el DNS apunte a la IP correcta;
  • el puerto 80 esté abierto;
  • NGINX esté activo;
  • no haya otro servicio usando el puerto 80.

Puedes probar NGINX con:

sudo nginx -t
sudo systemctl status nginx

PostgreSQL no inicia

Revisa logs:

docker compose logs postgres

Verifica 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 status

Si 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.

Cloud Servers by Donweb

Ya tienes n8n publicado con HTTPS y la base cerrada. Falta el servidor donde vive.
Alojamiento ultra rápido, escalable y con alta disponibilidad.

  • Performance que te sorprenderá
  • Rápida escalabilidad y sin limitaciones
  • Arquitectura de alta disponibilidad
  • Soporte experto y ejecutivos de cuenta
  • Pagos en tu moneda y facturación local

Instala n8n en un Cloud Server