n8n self-hosted con Docker y Traefik: instalación productiva paso a paso

Guía técnica para montar n8n self-hosted en producción con Docker Compose, Traefik como reverse proxy, HTTPS automático, backups y persistencia. Stack que aguanta carga real.

ACTUALIZADO: 21 DE MAYO DE 2026
6 min de lectura
D

DevActivo

n8n self-hosted en producción cuesta entre 10 y 30 USD/mes en infraestructura y te da workflows ilimitados, control total de datos y libertad de inyectar código arbitrario. Comparado con n8n Cloud (a partir de 20 USD/mes con límites por ejecución), self-hosted es mejor opción para volúmenes medios y altos.

En esta guía técnica te llevamos paso a paso por la instalación productiva de n8n con Docker Compose y Traefik como reverse proxy. Stack que tenemos corriendo para clientes con miles de ejecuciones diarias.

Por qué este stack específico

Combinamos n8n + Docker Compose + Traefik + Postgres + Cloudflare por estas razones:

  • Docker Compose: evita ensuciar el sistema y facilita deploy en cualquier servidor
  • Traefik: reverse proxy con HTTPS automático vía Let’s Encrypt, sin configurar manualmente
  • Postgres: motor de base de datos serio en lugar del SQLite que viene por default (frágil bajo carga)
  • Cloudflare delante: protección DDoS, CDN para assets estáticos, oculta tu IP real

Hay alternativas (Caddy en lugar de Traefik, Nginx Proxy Manager, k3s para Kubernetes) pero este stack es el que mejor balance da entre simplicidad y robustez.

Requisitos previos

  • VPS con Ubuntu 22.04 o 24.04 (recomendado: 2 vCPUs, 4 GB RAM mínimo para producción seria)
  • Dominio apuntando al VPS (registro A en tu DNS)
  • Cloudflare como DNS provider (opcional pero recomendado)
  • Docker y Docker Compose instalados
  • Puerto 80 y 443 abiertos en el firewall

Para instalar Docker en Ubuntu fresh:

curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER
newgrp docker

Estructura de directorios

Recomendamos esta organización:

/srv/docker/
├── traefik/
│   ├── docker-compose.yml
│   ├── .env
│   └── data/
│       ├── acme.json
│       └── traefik.yml
└── n8n/
    ├── docker-compose.yml
    ├── .env
    └── data/
        └── (volumen de n8n)

Paso 1: Configurar Traefik

Crea /srv/docker/traefik/data/traefik.yml:

api:
  dashboard: false

entryPoints:
  web:
    address: ":80"
    http:
      redirections:
        entryPoint:
          to: websecure
          scheme: https
  websecure:
    address: ":443"

providers:
  docker:
    endpoint: "unix:///var/run/docker.sock"
    exposedByDefault: false

certificatesResolvers:
  letsencrypt:
    acme:
      email: "[email protected]"
      storage: "/data/acme.json"
      tlsChallenge: {}

Crea /srv/docker/traefik/docker-compose.yml:

services:
  traefik:
    image: traefik:v3.1
    container_name: traefik
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./data/traefik.yml:/etc/traefik/traefik.yml:ro
      - ./data/acme.json:/data/acme.json
    networks:
      - proxy

networks:
  proxy:
    external: true

Prepara el archivo de certificados y arranca Traefik:

cd /srv/docker/traefik
touch data/acme.json
chmod 600 data/acme.json
docker network create proxy
docker compose up -d

Paso 2: Configurar n8n

Crea /srv/docker/n8n/.env:

# Dominio
N8N_HOST=automation.tudominio.com
N8N_PROTOCOL=https
N8N_PORT=5678
WEBHOOK_URL=https://automation.tudominio.com/

# Postgres
DB_TYPE=postgresdb
DB_POSTGRESDB_DATABASE=n8n
DB_POSTGRESDB_HOST=postgres
DB_POSTGRESDB_PORT=5432
DB_POSTGRESDB_USER=n8n_user
DB_POSTGRESDB_PASSWORD=password_seguro_largo

# Encryption key (generar único con: openssl rand -hex 32)
N8N_ENCRYPTION_KEY=tu_clave_de_32_caracteres

# Auth básico (recomendado en producción)
N8N_BASIC_AUTH_ACTIVE=true
N8N_BASIC_AUTH_USER=admin
N8N_BASIC_AUTH_PASSWORD=password_de_admin

# Timezone
GENERIC_TIMEZONE=America/Mexico_City
TZ=America/Mexico_City

# Email (para notificaciones de errores)
N8N_EMAIL_MODE=smtp
N8N_SMTP_HOST=smtp.mailgun.org
N8N_SMTP_PORT=587
[email protected]
N8N_SMTP_PASS=tu_password_smtp

Crea /srv/docker/n8n/docker-compose.yml:

services:
  postgres:
    image: postgres:16-alpine
    container_name: n8n_postgres
    restart: unless-stopped
    environment:
      POSTGRES_USER: ${DB_POSTGRESDB_USER}
      POSTGRES_PASSWORD: ${DB_POSTGRESDB_PASSWORD}
      POSTGRES_DB: ${DB_POSTGRESDB_DATABASE}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    networks:
      - n8n_internal
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER}"]
      interval: 10s
      timeout: 5s
      retries: 5

  n8n:
    image: n8nio/n8n:latest
    container_name: n8n
    restart: unless-stopped
    depends_on:
      postgres:
        condition: service_healthy
    environment:
      - N8N_HOST=${N8N_HOST}
      - N8N_PROTOCOL=${N8N_PROTOCOL}
      - N8N_PORT=${N8N_PORT}
      - WEBHOOK_URL=${WEBHOOK_URL}
      - DB_TYPE=${DB_TYPE}
      - DB_POSTGRESDB_DATABASE=${DB_POSTGRESDB_DATABASE}
      - DB_POSTGRESDB_HOST=${DB_POSTGRESDB_HOST}
      - DB_POSTGRESDB_PORT=${DB_POSTGRESDB_PORT}
      - DB_POSTGRESDB_USER=${DB_POSTGRESDB_USER}
      - DB_POSTGRESDB_PASSWORD=${DB_POSTGRESDB_PASSWORD}
      - N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY}
      - N8N_BASIC_AUTH_ACTIVE=${N8N_BASIC_AUTH_ACTIVE}
      - N8N_BASIC_AUTH_USER=${N8N_BASIC_AUTH_USER}
      - N8N_BASIC_AUTH_PASSWORD=${N8N_BASIC_AUTH_PASSWORD}
      - GENERIC_TIMEZONE=${GENERIC_TIMEZONE}
      - TZ=${TZ}
      - N8N_EMAIL_MODE=${N8N_EMAIL_MODE}
      - N8N_SMTP_HOST=${N8N_SMTP_HOST}
      - N8N_SMTP_PORT=${N8N_SMTP_PORT}
      - N8N_SMTP_USER=${N8N_SMTP_USER}
      - N8N_SMTP_PASS=${N8N_SMTP_PASS}
    volumes:
      - n8n_data:/home/node/.n8n
    networks:
      - n8n_internal
      - proxy
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.n8n.rule=Host(`${N8N_HOST}`)"
      - "traefik.http.routers.n8n.entrypoints=websecure"
      - "traefik.http.routers.n8n.tls.certresolver=letsencrypt"
      - "traefik.http.services.n8n.loadbalancer.server.port=5678"

volumes:
  postgres_data:
  n8n_data:

networks:
  n8n_internal:
  proxy:
    external: true

Arranca:

cd /srv/docker/n8n
docker compose up -d

Espera 30-60 segundos a que Traefik provisione el certificado HTTPS. Después accede a https://automation.tudominio.com y entrarás al setup inicial de n8n.

Paso 3: Hardening de seguridad

Lo mínimo para producción seria:

Firewall UFW

sudo ufw allow ssh
sudo ufw allow http
sudo ufw allow https
sudo ufw enable

Fail2ban contra brute force SSH

sudo apt install fail2ban -y
sudo systemctl enable fail2ban
sudo systemctl start fail2ban

SSH solo con llave (deshabilitar password)

En /etc/ssh/sshd_config setea PasswordAuthentication no y reinicia ssh.

Updates automáticos

sudo apt install unattended-upgrades -y
sudo dpkg-reconfigure -plow unattended-upgrades

Paso 4: Backups

n8n self-hosted sin backups es ruleta rusa. Esto es lo mínimo:

Backup diario de Postgres:

# /srv/scripts/backup-n8n.sh
#!/bin/bash
DATE=$(date +%Y-%m-%d_%H-%M)
BACKUP_DIR=/srv/backups/n8n
mkdir -p $BACKUP_DIR

docker exec n8n_postgres pg_dump -U n8n_user n8n | gzip > $BACKUP_DIR/n8n_$DATE.sql.gz

# Mantén solo últimos 14 días
find $BACKUP_DIR -name "n8n_*.sql.gz" -mtime +14 -delete

Programa con cron:

crontab -e
# Agregar:
0 3 * * * /srv/scripts/backup-n8n.sh

Para producción seria, también sincronizar a almacenamiento externo (S3, Backblaze B2, o segundo VPS).

Paso 5: Monitoreo

Mínimo viable:

  • Uptime monitoring externo: UptimeRobot free tier checa cada 5 min
  • Logs: docker logs n8n --tail 200 --follow cuando algo falla
  • Errors via email: n8n ya envía notificaciones cuando un workflow falla si configuras SMTP

Para escalas mayores: Grafana + Prometheus + Sentry. Pero para arranque, lo de arriba alcanza.

Performance tuning

Para n8n con muchas ejecuciones simultáneas:

Workers separados: n8n soporta modo “queue” donde main process recibe webhooks y workers paralelos procesan ejecuciones. Activa con:

# En .env
EXECUTIONS_MODE=queue
QUEUE_BULL_REDIS_HOST=redis

Y agrega un servicio Redis al compose. Después puedes escalar workers horizontalmente:

docker compose up -d --scale n8n_worker=4

Costos reales mensuales

VPS típico para n8n productivo:

  • Hetzner CX22 (2 vCPU, 4 GB RAM, 40 GB SSD): 6 USD/mes
  • DigitalOcean Basic Droplet (2 vCPU, 4 GB): 24 USD/mes
  • Linode 4GB Shared: 24 USD/mes
  • Hetzner CX32 (4 vCPU, 8 GB RAM) para volumen alto: 12 USD/mes

Hetzner gana por relación precio/performance. DigitalOcean por UX y comunidad.

Cloudflare es free para uso normal. Mailgun free tier 100 emails/día suficiente para alertas.

Total realista: 6-24 USD/mes para 10K-100K ejecuciones mensuales.

Cuándo n8n Cloud es mejor

Self-hosted no siempre gana:

  • No tienes nadie con experiencia básica de DevOps en tu equipo
  • Tu volumen es muy bajo (menos de 1,000 ejecuciones/mes)
  • Tu data no es sensible y prefieres cero mantenimiento
  • Necesitas SLA empresarial con soporte garantizado

Para todo lo demás, self-hosted es la elección correcta.

Quieres que lo instalemos por ti

Si quieres saltarte el setup y empezar a construir workflows el día 1, en DevActivo ofrecemos instalación productiva completa de n8n self-hosted (con todo lo descrito arriba: Postgres, Traefik, backups, monitoreo, Cloudflare) por 400 USD una sola vez. Incluye 30 días de soporte para ajustes y capacitación de tu equipo.

O si quieres todo el ecosistema (n8n + automatizaciones + agentes IA + integraciones), ver nuestro servicio completo de automatización con n8n e IA.

Servicios relacionados: