Saudações.
Esse tutorial é um guia rápido de instalação do N8N versão 2 modo fila com taskrunners.
Arquivos do guia:
- https://github.com/patrickbrandao/n8n-builder/
- https://github.com/patrickbrandao/n8n-builder/tree/main/n8n-deploy
Pré-requisitos (constam em outros artigos aqui do blog):
- Instalação do Linux (Debian);
- Internet no servidor (sua VPS ou host);
- Docker CE instalado;
- Traefik como proxy reverso;
1 – Sobre N8N versão 2
O N8N (eni eiti eni) é um sistema de construção de automações no-code e low-code usando fluxos visuais, ligando visualmente componentes uns aos outros para criar programas.
A versão 2 implementou algumas mudanças, entre elas, a mais drástica foi a separação da execução de códigos Python e Javascript em containers separados de sandbox que ele nomeou como taskrunners.
Diagrama de relação entre serviços (containers) na versão 2:

Com isso a estrutura de containers ficou assim:
- editor (main): Roda o núcleo do N8N, gestão completa e disparo de eventos (triggers);
- webhook: Roda o servidor web (HTTP) para disparo de eventos baseados na chamada de URLs e Webhooks (webhook trigger, form trigger);
- worker: Detecta o disparo de eventos e inicia a execução do workflow node a node, é o serviço que faz o trabalho pesado, todos os nodes do tipo code de Javascript e Python são enviados para execução no taskrunner;
- taskrunner: Se conecta ao worker para receber trabalhos de execução de códigos Javascript e Python, retorna os dados gerados e informações da execução;
- redis: Provê o canal de comunicação pub-sub entre todos os serviços acima e serve de cache de dados;
- postgresql: Provê o banco de dados persistente para cadastro de tudo (logins, credenciais, workflows, logs de execução, etc).
O serviço de webhook é opcional mas altamente recomendado para separar a carga de entrada das webhooks do editor, assim o editor fica com recursos reservados à administração do N8N enquanto que o webhook pode escalar por meio de réplicas.
Os containers dos 6 serviços tem diferentes naturezas de escalonamento:
- editor (main): Por padrão não escala, não replicável, pode escalar por meio de licença especial que permite o ambiente multi-main que balanceia a carga HTTP das ações administrativas. Devido ao fato do main rodar o núcleo duro do N8N que dispara quase todos os tipos de triggers das automações, ao rodar várias instâncias do editor uma delas será eleita a principal (master) para assumir a tarefa de disparo de triggers enquanto as demais atual apenas como balanceamento de carga das chamadas ao backend vindas do frontend;
- webhook: Replicável, o balanceamento de conexões de entrada é feito pelo Swarm e em casos mais avançados por cluster de proxy reverso;
- worker: Replicável, o balanceamento da carga é feita internamente entre os workers que disputam serviços na mensageria do redis;
- taskrunner: Replicável, o taskrunner requer o endereço do worker a qual ele se conectará e portanto o balanceamento é feito pelo Swarm;
- redis: Não replicável, todos os containers do N8N precisam se comunicar por ele, para escalar o redis é necessário montar um cluster redis;
- postgres: Não replicável, semelhante ao redis, requer cluster postgres separado;
2 – Preparativos
Nesse capítulo vou executar o N8N parte por parte para ambiente de estudos das partes isoladamente.
2.1 – Configurações
Personalize a variável EMAIL para que o LetsEncrypt funcione corretamente. Vou salvar o email de contato no arquivo /etc/email do host:
# Email de registro no letsencrypt
EMAIL="voce@seudominio.com.br";
# Gravar no arquivo para consulta
echo "$EMAIL" > /etc/email;
2.2 – Rede Docker
Rede Docker para containers do N8N.
Arquivo: /root/n8n-deploy/run-01-network-public.sh
# Rede Docker (bridge local)
docker network create \
-d bridge \
\
-o "com.docker.network.bridge.name"="br-net-public" \
-o "com.docker.network.bridge.enable_icc"="true" \
-o "com.docker.network.driver.mtu"="1500" \
\
--subnet 10.249.0.0/16 --gateway 10.249.255.254 \
\
network_public;
2.3 – Proxy Reverso – Traefik
Container do Traefik para proxy reverso com HTTPs automático.
Arquivo: /root/n8n-deploy/run-02-traefic-app.sh
# Email de contato para o certificado LetsEncrypt:
EMAIL="voce@seudominio.com.br";
[ -f /etc/email ] && EMAIL=$(head -1 /etc/email);
# Imagem do traefik, baixar atualizada:
docker pull traefik:latest;
# Diretorio de dados persistentes:
mkdir -p /storage/traefik-app/letsencrypt;
mkdir -p /storage/traefik-app/logs;
mkdir -p /storage/traefik-app/config;
# Renovar/rodar:
docker rm -f traefik-app 2>/dev/null;
docker run \
-d --restart=always \
--name traefik-app -h traefik-app.intranet.br \
--tmpfs /run:rw,noexec,nosuid,size=8m \
--tmpfs /tmp:rw,noexec,nosuid,size=8m \
--read-only \
--cpus="8.0" --memory=4g --memory-swap=4g \
\
--network network_public \
\
-p 80:80 \
-p 443:443 \
\
-v /var/run/docker.sock:/var/run/docker.sock:ro \
-v /storage/traefik-app/letsencrypt:/etc/letsencrypt \
-v /storage/traefik-app/config:/etc/traefik \
-v /storage/traefik-app/logs:/logs \
\
traefik:latest \
\
--global.checkNewVersion=false \
--global.sendAnonymousUsage=false \
\
--api.insecure=true \
\
--log.level=INFO \
--log.filePath=/logs/error.log \
\
--accessLog.filePath=/logs/access.log \
\
--entrypoints.web.address=:80 \
--entrypoints.web.http.redirections.entryPoint.to=websecure \
--entrypoints.web.http.redirections.entryPoint.scheme=https \
--entrypoints.web.http.redirections.entryPoint.permanent=true \
--entrypoints.websecure.address=:443 \
\
--providers.docker=true \
--providers.file.directory=/etc/traefik \
\
--certificatesresolvers.letsencrypt.acme.email=$EMAIL \
--certificatesresolvers.letsencrypt.acme.storage=/etc/letsencrypt/acme.json \
--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web;
2.4 – Banco de dados PostgreSQL
Vamos criar um banco de dados PostgreSQL chamado “n8n-pgsql“.
Arquivo: /root/n8n-deploy/run-03-n8n-postgresql.sh
# Credenciais de acesso ao PG
POSTGRES_USER="postgres";
POSTGRES_PASSWORD="tulipasql";
POSTGRES_DB="n8n";
# Pasta para o volume
mkdir -p /storage/n8n-pgsql;
chown -R 999:999 /storage/n8n-pgsql;
# Rodar:
docker pull pgvector/pgvector:pg18-trixie;
docker run \
-d --restart=always \
--name n8n-pgsql -h n8n-pgsql.intranet.br \
--read-only --cpus="2.0" --memory=2g --memory-swap=2g --shm-size=1g \
\
--network network_public \
\
--tmpfs /run:rw,noexec,nosuid,size=128m \
--tmpfs /tmp:rw,noexec,nosuid,size=128m \
\
-v /storage/n8n-pgsql:/var/lib/postgresql/data \
\
-e POSTGRES_USER=$POSTGRES_USER \
-e POSTGRES_PASSWORD=$POSTGRES_PASSWORD \
-e POSTGRES_DB=$POSTGRES_DB \
-e PGDATA=/var/lib/postgresql/data/pgdata \
\
--health-cmd="pg_isready -U postgres" \
--health-interval=5s \
--health-timeout=5s \
--health-retries=10 \
\
--entrypoint "docker-entrypoint.sh" \
\
pgvector/pgvector:pg18-trixie \
postgres \
--max_connections=8192 \
--wal_level=minimal \
--max_wal_senders=0 \
--port=5432;
2.5 – Redis
O Redis é vital para o N8N, vamos criar o container chamado “n8n-redis“.
Arquivo: /root/n8n-deploy/run-04-n8n-redis.sh
# Pasta de persistencia RDB e AOF:
mkdir -p /storage/n8n-redis;
chown -R 999:999 /storage/n8n-redis;
# Baixar imagem atualizada do Redis (https://hub.docker.com/_/redis):
docker pull redis:latest;
# Remover container atual:
docker rm -f n8n-redis 2>/dev/null;
# Criar container do redis:
docker run \
-d --restart=always \
--name n8n-redis -h n8n-redis.intranet.br \
--read-only --cpus="1.0" --memory=1g --memory-swap=1g \
\
--network network_public \
\
-v /storage/n8n-redis:/data \
-w /data \
\
--health-cmd="redis-cli ping" \
--health-interval=1s \
--health-timeout=3s \
\
redis:latest \
redis-server \
--tcp-backlog 8192 --tcp-keepalive 30 --timeout 0 \
--dir /data --save 16 1 --save 12 10 --save 6 100 \
--rdbcompression no --appendonly yes --appendfsync everysec;
3 – Variáveis de ambiente
O N8N possui uma vastidão de variáveis de ambientes mas elas podem ser divididas de acordo com suas finalidades e quais serviços precisam delas.
Variáveis com valor semelhante ao valor padrão estarão em AZUL e os valores alterados e personalizados de VERMELHO.
Você pode omitir todas as variáveis em AZUL sem problemas, isso economiza espaço na configuração.
3.1 – Modo fila (1 variável)
O antigo modo simples baseado no sqlite foi substituído pelo modo fila que faz uso do Redis e PostgreSQL por meio da técnica Claim Check Pattern (sinais em tempo real no Redis pub/sub e dados de transações no SQL).
Dados para acesso ao Redis e PG do modelo fila foram definidos na criação dos containers no capítulo 2.
Usadas pelo editor, webhook e worker, não são usadas pelo task-runner.
| Variável | Valor |
| EXECUTIONS_MODE | queue |
| EXECUTIONS_TIMEOUT Padrão -1 (eterno), limite em segundos, evita acumulo de workflows travados Valor em segundos | 1800 |
| EXECUTIONS_TIMEOUT_MAX Recomendável 7200 (2h) para execuções longas Valor em segundos | 3600 |
3.2 – Acesso a Redis (1 variável)
Usados pelo editor, webhook e worker, não é usado pelo task-runner.
Variáveis do Redis:
| Variável | Valor |
| QUEUE_BULL_REDIS_HOST | n8n-redis |
| QUEUE_BULL_REDIS_CLUSTER_NODES Quando houver cluster redis, sintaxe: redis-1:6379,redis-2:6379 | (vazio) |
| QUEUE_BULL_REDIS_DNS_LOOKUP_STRATEGY | LOOKUP |
| QUEUE_BULL_REDIS_PORT | 6379 |
| QUEUE_BULL_REDIS_TLS | false |
| QUEUE_BULL_REDIS_DB Altere para usar um Redis compartilhado com outros sistemas | 0 |
| QUEUE_BULL_REDIS_KEEP_ALIVE | false |
| QUEUE_BULL_REDIS_KEEP_ALIVE_DELAY | 5000 |
| QUEUE_BULL_REDIS_KEEP_ALIVE_INTERVAL | 5000 |
| QUEUE_BULL_REDIS_RECONNECT_ON_FAILOVER | true |
| QUEUE_BULL_REDIS_USERNAME | (vazio) |
| QUEUE_BULL_REDIS_PASSWORD | (vazio) |
| QUEUE_BULL_REDIS_TIMEOUT_THRESHOLD | 10_000 |
| QUEUE_BULL_REDIS_SLOT_REFRESH_TIMEOUT | 1_000 |
| QUEUE_BULL_REDIS_SLOT_REFRESH_INTERVAL | 5_000 |
| QUEUE_BULL_PREFIX Prefixo das chaves de cache | bull |
| N8N_GRACEFUL_SHUTDOWN_TIMEOUT | 30 |
| QUEUE_BULL_REDIS_DUALSTACK Se alterado para true, permite uso de IPv6 se presente | false |
| QUEUE_HEALTH_CHECK_ACTIVE Mude para true se o Redis sofre risco de sair do ar | false |
| QUEUE_HEALTH_CHECK_PORT | 5678 |
| N8N_REDIS_KEY_PREFIX | n8n |
| QUEUE_WORKER_LOCK_DURATION | 60_000 |
| QUEUE_WORKER_LOCK_RENEW_TIME | 10_000 |
| QUEUE_WORKER_STALLED_INTERVAL | 30_000 |
3.3 – Acesso a Postgres (3 variáveis)
Usados pelo editor, webhook e worker, não é usado pelo task-runner.
| Variável | Valor |
| DB_TYPE | postgresdb |
| DB_POSTGRESDB_HOST | n8n-pgsql |
| DB_POSTGRESDB_PORT | 5432 |
| DB_POSTGRESDB_DATABASE | n8n |
| DB_POSTGRESDB_USER | postgres |
| DB_POSTGRESDB_PASSWORD | tulipasql |
| DB_POSTGRESDB_SCHEMA | public |
| DB_POSTGRESDB_POOL_SIZE Tuning: Recomendo aumentar para 32 | 2 |
| DB_POSTGRESDB_SSL_ENABLED | false |
| DB_POSTGRESDB_SSL_CA | (vazio) |
| DB_POSTGRESDB_SSL_CERT | (vazio) |
| DB_POSTGRESDB_SSL_KEY | (vazio) |
| DB_POSTGRESDB_SSL_REJECT_UNAUTHORIZED | true |
| DB_POSTGRESDB_CONNECTION_TIMEOUT Valor em milissegundos, timeout com o PG | 20_000 |
| DB_POSTGRESDB_IDLE_CONNECTION_TIMEOUT Valor em milissegundos, encerra conexões adicionais inativas | 30_000 |
| DB_POSTGRESDB_STATEMENT_TIMEOUT Valor em milissegundos, limite de execução de uma query | 300_000 |
O N8N não envia operações de vaccum para o postgres, lembre de fazer essa rotina mensalmente.
3.4 – Opções globais (2 variáveis)
Variáveis de uso global e necessárias para todos os serviços: editor, webhook, worker, e task-runner.
| Variável | Valor |
| GENERIC_TIMEZONE Padrão: America/New_York | America/Sao_Paulo |
| TZ Padrão herdado do sistema local | America/Sao_Paulo |
3.5 – Opções gerais (5 variáveis)
Variáveis usadas pelo editor, webhook e worker, não são usadas no task-runner.
| Variável | Valor |
| N8N_PATH | / |
| N8N_DEFAULT_LOCALE | en |
| N8N_ENCRYPTION_KEY Padrão vazio, usado para protege credenciais | tulipa |
| NODE_ENV Requer especificação, opções: test, development ou production | production |
| N8N_DIAGNOSTICS_ENABLED Padrão true mas não vamos enviar dados para a N8N | false |
| N8N_USER_FOLDER Padrão $HOME do usuário node | /data |
| N8N_LOG_LEVEL | info |
| N8N_LOG_CRON_ACTIVE_INTERVAL | 0 |
| N8N_LOG_FILE_COUNT_MAX | 100 |
| N8N_LOG_FILE_SIZE_MAX | 16 |
| N8N_LOG_FILE_LOCATION | logs/n8n.log |
| N8N_LOG_OUTPUT | console,file |
| N8N_LOG_FORMAT | text |
| N8N_LOG_SCOPES | (vazio) |
| N8N_DIAGNOSTICS_POSTHOG_API_KEY | (chave da n8n) |
| N8N_DIAGNOSTICS_POSTHOG_API_HOST | (url posthog) |
| N8N_DIAGNOSTICS_CONFIG_FRONTEND | (url da n8n) |
| N8N_DIAGNOSTICS_CONFIG_BACKEND | (url da n8n) |
| N8N_METRICS | true |
| N8N_METRICS_PREFIX | n8n_ |
| N8N_METRICS_INCLUDE_DEFAULT_METRICS | true |
| N8N_METRICS_INCLUDE_WORKFLOW_ID_LABEL | false |
| N8N_METRICS_INCLUDE_NODE_TYPE_LABEL | false |
| N8N_METRICS_INCLUDE_CREDENTIAL_TYPE_LABEL | false |
| N8N_METRICS_INCLUDE_API_ENDPOINTS | false |
| N8N_METRICS_INCLUDE_API_PATH_LABEL | false |
| N8N_METRICS_INCLUDE_API_METHOD_LABEL | false |
| N8N_METRICS_INCLUDE_API_STATUS_CODE_LABEL | false |
| N8N_METRICS_INCLUDE_CACHE_METRICS | false |
| N8N_METRICS_INCLUDE_MESSAGE_EVENT_BUS_METRICS | false |
| N8N_METRICS_INCLUDE_QUEUE_METRICS | false |
| N8N_METRICS_QUEUE_METRICS_INTERVAL | 20 |
| N8N_METRICS_ACTIVE_WORKFLOW_METRIC_INTERVAL | 60 |
| N8N_METRICS_INCLUDE_WORKFLOW_NAME_LABEL | false |
| N8N_METRICS_INCLUDE_WORKFLOW_STATISTICS | false |
| N8N_METRICS_WORKFLOW_STATISTICS_INTERVAL | 300 |
| N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS | true |
| N8N_CACHE_BACKEND Opções: memory, redis, auto (padrão, prefere Redis) | auto |
| N8N_CACHE_MEMORY_MAX_SIZE Tamanho máximo de mensagens na memória em bytes | 3145728 |
| N8N_CACHE_MEMORY_TTL Tempo de vida em segundos de mensagens na memória em ms | 3600000 |
| N8N_CACHE_REDIS_KEY_PREFIX Prefixo da chave no Redis para mensagens na memória | cache |
| N8N_HIRING_BANNER_ENABLED Desative apenas se estiver em modo desenvolvedor | true |
3.6 – Opções de servidor http (4 variáveis)
Variáveis usadas apenas pelos serviços que abrem a porta HTTP para webhooks.
Usados pelo editor e webhook, não é usado pelo worker e task-runner.
| Variável | Valor |
| WEBHOOK_URL | (a explicar) |
| N8N_HOST | (a explicar) |
| N8N_PORT | 5678 |
| N8N_LISTEN_ADDRESS | :: |
| N8N_PROTOCOL Padrão: http | https |
| N8N_PROXY_HOPS Padrão: 0 | 1 |
| N8N_SSL_CERT | (vazio) |
| N8N_SSL_KEY | (vazio) |
| N8N_PAYLOAD_SIZE_MAX Valor em MB | 16 |
| N8N_FORMDATA_FILE_SIZE_MAX | 200 |
3.6 – Opções exclusivas do editor (7 variáveis)
Usados somente pelo editor (frontend e backend).
| Variável | Valor |
| OFFLOAD_MANUAL_EXECUTIONS_TO_WORKERS Será transformada em hard coded em breve, pinar para deixar pronto | true |
| N8N_EDITOR_BASE_URL | (a explicar) |
| N8N_DISABLE_UI | false |
| N8N_SECURE_COOKIE Para permitir acesso HTTP direto na porta do N8N, deixe em true (padrão) ou omita para restringir o acesso apenas por HTTPs | false |
| N8N_AI_PROVIDER | openai |
| N8N_AI_OPENAI_API_KEY | (vazio) |
| N8N_AI_TIMEOUT_MAX Padrão 3.600.000 ms (1h, muito tempo), recomendo 900000 (15min) | 900000 |
| N8N_AI_ALLOW_SENDING_PARAMETER_VALUES | true |
| N8N_ENDPOINT_REST | rest |
| N8N_ENDPOINT_FORM | form |
| N8N_ENDPOINT_FORM_TEST | form-test |
| N8N_ENDPOINT_FORM_WAIT | form-waiting |
| N8N_ENDPOINT_WEBHOOK | webhook |
| N8N_ENDPOINT_WEBHOOK_TEST | webhook-test |
| N8N_ENDPOINT_WEBHOOK_WAIT | webhook-waiting |
| N8N_ENDPOINT_MCP | mcp |
| N8N_ENDPOINT_MCP_TEST | mcp-test |
| N8N_DISABLE_PRODUCTION_MAIN_PROCESS | false |
| N8N_ADDITIONAL_NON_UI_ROUTES | (vazio) |
| N8N_ENDPOINT_HEALTH | /healthz |
| EXECUTIONS_DATA_HARD_DELETE_BUFFER Valor em horas | 1 |
| EXECUTIONS_DATA_MAX_AGE Valor em horas | 336 |
| EXECUTIONS_DATA_PRUNE | true |
| EXECUTIONS_DATA_PRUNE_HARD_DELETE_INTERVAL Valor em minutos | 15 |
| EXECUTIONS_DATA_PRUNE_MAX_COUNT | 10_000 |
| EXECUTIONS_DATA_PRUNE_SOFT_DELETE_INTERVAL Valor em minutos | 60 |
| EXECUTIONS_DATA_SAVE_MANUAL_EXECUTIONS | true |
| N8N_VERSION_NOTIFICATIONS_ENABLED Desativa notificações sobre novas versões do N8N | false |
| N8N_VERSION_NOTIFICATIONS_ENDPOINT | (url da n8n) |
| N8N_VERSION_NOTIFICATIONS_WHATS_NEW_ENABLED Desativa notificações de novos recursos dos updates recentes | false |
| N8N_VERSION_NOTIFICATIONS_WHATS_NEW_ENDPOINT | (url da n8n) |
| N8N_VERSION_NOTIFICATIONS_INFO_URL | (url da n8n) |
N8N_PUBLIC_API_DISABLED | false |
| N8N_PUBLIC_API_ENDPOINT | api |
| N8N_PUBLIC_API_SWAGGERUI_DISABLED | true |
| N8N_PUSH_BACKEND Padrão websocket bidirecional ou sse para unidirecional | websocket |
| WORKFLOWS_DEFAULT_NAME | My workflow |
| N8N_TEMPLATES_ENABLED | true |
| N8N_TEMPLATES_HOST | (url n8n) |
| N8N_DYNAMIC_TEMPLATES_HOST | (url n8n) |
3.7 – Opções do editor e worker (3 variáveis)
Usados pelo editor e worker, não é usado pelo webhook e task-runner.
| Variável | Valor |
| N8N_RUNNERS_MODE | external |
| EXECUTIONS_DATA_SAVE_ON_ERROR Opções: all, none, padrão all | all |
| EXECUTIONS_DATA_SAVE_ON_PROGRESS Padrão: false | true |
| EXECUTIONS_DATA_SAVE_ON_SUCCESS Opções: all, none, padrão none | all |
| N8N_COMMUNITY_PACKAGES_ENABLED | true |
| N8N_COMMUNITY_PACKAGES_REGISTRY | https://registry.npmjs.org |
| N8N_REINSTALL_MISSING_PACKAGES | false |
| N8N_UNVERIFIED_PACKAGES_ENABLED | true |
| N8N_VERIFIED_PACKAGES_ENABLED | true |
| N8N_COMMUNITY_PACKAGES_PREVENT_LOADING | false |
| N8N_PYTHON_ENABLED | true |
3.8 – Opções exclusivas do worker (2 variáveis)
Variáveis usadas somente pelo worker.
| Variável | Valor |
| N8N_RUNNERS_BROKER_LISTEN_ADDRESS Padrão 127.0.0.1, não escuta na rede local | 0.0.0.0 |
| N8N_RUNNERS_ENABLED Legado da v2, descontinuada na v2 e hard-coded como true | true |
| N8N_CONCURRENCY_PRODUCTION_LIMIT Execuções ilimitadas em -1 ou especifique o limite de paralelismo por worker | -1 |
| N8N_CONCURRENCY_EVALUATION_LIMIT | -1 |
| CODE_ENABLE_STDOUT Mude para true para permitir que node Code use a saida stdout | false |
3.9 – Opções exclusivas do task-runner (2 variáveis)
Variáveis usadas pelo task-runner.
| Variável | Valor |
| N8N_RUNNERS_TASK_BROKER_URI | (a explicar) |
| N8N_RUNNERS_HEALTH_CHECK_SERVER_ENABLED | true |
| N8N_RUNNERS_HEALTH_CHECK_SERVER_HOST | true |
| N8N_RUNNERS_HEALTH_CHECK_SERVER_PORT | true |
| N8N_RUNNERS_GRANT_TOKEN | true |
| N8N_RUNNERS_MAX_PAYLOAD Padrão: 1024 * 1024 * 1024 = 1.073.741.824 bytes (1 GB) | 1073741824 |
| N8N_RUNNERS_MAX_CONCURRENCY Padrão: 10, causa gargalos em burst de tarefas | 128 |
| N8N_RUNNERS_AUTO_SHUTDOWN_TIMEOUT | 0 |
| N8N_RUNNERS_PATH | /runners |
| N8N_RUNNERS_BROKER_PORT | 5679 |
| N8N_RUNNERS_MAX_OLD_SPACE_SIZE | (vazio) |
| N8N_RUNNERS_TASK_TIMEOUT | 300 |
| N8N_RUNNERS_TASK_REQUEST_TIMEOUT | 60 |
| N8N_RUNNERS_HEARTBEAT_INTERVAL | 30 |
| N8N_RUNNERS_INSECURE_MODE | false |
| N8N_RUNNERS_LAUNCHER_LOG_LEVEL | debug |
3.9 – Opções do worker e task-runner (2 variáveis)
Usados pelo worker e task-runner.
| Variável | Valor |
| N8N_RUNNERS_AUTH_TOKEN Padrão vazio, especificar por segurança | tulipa |
| N8N_RUNNERS_ENABLED Legado da v2, descontinuada na v2 e hard-coded como true | true |
3.10 – Opções de gerenciamento de usuários e SMTP (4 variáveis)
Usados pelo editor para envio de emails (notificações, convites, recuperação de senha).
| Variável | Valor |
| N8N_EMAIL_MODE | smtp |
| N8N_SMTP_HOST Endereço do servidor SMTP | (informe) |
| N8N_SMTP_PORT Porta do protocolo SMTP, 465=SMTP+SSL, 587=SMTP+StartTLS | 465 |
| N8N_SMTP_SSL Padrão true, altere para false se for usar a porta 587 | true |
| N8N_SMTP_STARTTLS Padrão true, altere para false se for usar a porta 465 | true |
| N8N_SMTP_SENDER Email de remetente original | (informe) |
| N8N_SMTP_USER Nome de usuário no serviço SMTP | (informe) |
| N8N_SMTP_PASS Senha de autenticação SMTP | (informe) |
| N8N_SMTP_OAUTH_SERVICE_CLIENT | (vazio) |
| N8N_SMTP_OAUTH_PRIVATE_KEY | (vazio) |
| N8N_UM_EMAIL_TEMPLATES_PWRESET | 3600 |
| N8N_UM_EMAIL_TEMPLATES_INVITE | 3600 |
| N8N_UM_EMAIL_TEMPLATES_WORKFLOW_SHARED | (vazio) |
| N8N_UM_EMAIL_TEMPLATES_WORKFLOW_AUTODEACTIVATED | (vazio) |
| N8N_UM_EMAIL_TEMPLATES_CREDENTIALS_SHARED | (vazio) |
| N8N_UM_EMAIL_TEMPLATES_PROJECT_SHARED | (vazio) |
| N8N_UM_EMAIL_TEMPLATES_WORKFLOW_FAILURE | (vazio) |
| N8N_INVITE_LINKS_EMAIL_ONLY | false |
| N8N_USER_MANAGEMENT_JWT_SECRET | (vazio) |
| N8N_USER_MANAGEMENT_JWT_DURATION_HOURS | 168 |
| N8N_USER_MANAGEMENT_JWT_REFRESH_TIMEOUT_HOURS | 0 |
| N8N_SMTP_OAUTH_SERVICE_CLIENT | (vazio) |
| N8N_SMTP_OAUTH_PRIVATE_KEY | (vazio) |
3.11 – Opções da licença enterprise (4 variáveis)
Quando a licença enterprise é ativada você pode usar novos recursos localmente.
Use esse link para adquirir a licença: https://n8n.io/enterprise/
As variáveis para instalar a licença devem ser informadas em todos os serviços do n8n ( editor, worker e webhook, menos o task-runner:
| Variável | Valor |
| N8N_LICENSE_ACTIVATION_KEY | (chave aqui) |
| N8N_LICENSE_AUTO_RENEW_ENABLED | true |
| N8N_LICENSE_DETACH_FLOATING_ON_SHUTDOWN | true |
| N8N_LICENSE_TENANT_ID | 1 |
| N8N_LICENSE_CERT | (vazio) |
| N8N_LICENSE_SERVER_URL | (url da n8n) |
As variáveis de controle de recursos enterprise são:
| Variável | Valor |
| N8N_AI_ENABLED | true |
| N8N_AI_ASSISTANT_BASE_URL | (url chatbot) |
| N8N_AI_ANTHROPIC_KEY | (sua chave) |
| N8N_AI_PERSIST_BUILDER_SESSIONS | true |
| N8N_PERSONALIZATION_ENABLED | true |
| LANGSMITH_API_KEY | (vazio) |
| LANGSMITH_TRACING | true |
| LANGSMITH_MINIMAL_TRACING | false |
| LANGSMITH_ENDPOINT | (url LS) |
4 – Entendendo o Task-Runner
O runner executará em container separado, esse modo é chamado de EXTERNAL.
Diferenças:
- internal: O task-runner é executado como processo filho do processo que executa o workflow;
- Vantagens: simples, rápido;
- Desvantagens: inseguro, pode quebrar o sistema inteiro;
- external: O task-runner é executado em serviço separado e isolado, recebe apenas os dados objetivos para execução de código JS e PY e cria um sandbox;
- Vantagens: seguro, isolado, resiliente;
- Desvantagens: lento, podem induzir uma demora de até 3 segundos na execução do workflow;
Vou abordar o modo external pois é a tendência de evolução do N8N.
Quando o worker é iniciado com a configuração N8N_RUNNERS_MODE=external ele precisará abrir a porta 5679/tcp para atuar como servidor broker:
- Porta em N8N_RUNNERS_BROKER_PORT=5679;
- IP de escuta em N8N_RUNNERS_BROKER_LISTEN_ADDRESS=0.0.0.0;
O worker não poderá executar nenhum “node code” até que 1 runner se concte a ele.
Essa lógica permite que os containers dos runners trabalhem remotamente em servidores diferentes dos servidores de worker, editor e webhook.
O task-runner precisa saber o endereço IP e porta do worker a qual ele se conectará para coletar trabalho, o endereço é definido na variável:
- N8N_RUNNERS_TASK_BROKER_URI, exemplo: http://n8n-worker:5679
Vários runners podem apontar para um mesmo worker.
O ideal é trabalhar com no mínimo 2 réplicas de workers e 4 réplicas de runners.
5 – Endereços de acesso
O N8N pode ser executado em ambiente privado sem HTTPs ou em ambiente público com homologação completa (HTTPs + Certificado reconhecido globalmente).
5.1 – Executando N8N em ambiente privado
As seguintes variáveis devem ser configuradas para acessar o N8N diretamente na porta HTTP (sem criptografia) e sem URL pública:
| Variável | Valor |
| N8N_HOST IPv4, IPv6 ou nome de DNS do servidor | 192.168.14.199 |
| WEBHOOK_URL URL do servidor webhook | http://192.168.14.199 |
| N8N_PROXY_HOPS Sem proxy-reverso entre o navegador e o N8N | 0 |
| N8N_EDITOR_BASE_URL URL para geração de links nas automações | http://192.168.14.199 |
| N8N_SECURE_COOKIE Para permitir acesso HTTP direto na porta do N8N | false |
O acesso será na porta HTTP direta do N8N (N8N_PORT=5678).
Exemplo de acesso ao editor: http://192.168.14.199:5678/
O container de webhook precisará de outra porta redirecionada para a mesma porta 5678 ou ser publicada por meio de um túnel (CloudFlare, Akamai, webhook-relay).
5.2 – Executando N8N em ambiente público
Será necessário configurar o DNS corretamente, os seguintes nomes serão necessários:
| Nome de DNS (FQDN) | Serviço |
| n8n.seudominio.com.br | Editor do N8N – Administração |
| ws.seudominio.com.br | Webhook – Servidor HTTP das automações |
As variáveis devem ser preenchidas assim:
| Variável | Valor |
| N8N_HOST IPv4, IPv6 ou nome de DNS do servidor | n8n.seudominio.com.br |
| WEBHOOK_URL URL do servidor webhook | https://ws.seudominio.com.br |
| N8N_PROXY_HOPS Com proxy-reverso entre o navegador e o N8N | 1 |
| N8N_EDITOR_BASE_URL URL para geração de links nas automações | https://n8n.seudominio.com.br |
O acesso será na porta HTTPs (tcp/443) do proxy-reverso (Traefik) que encaminhará para o container do editor na porta http 5678 (N8N_PORT=5678).
Exemplo de acesso ao editor: https://n8n.seudominio.com.br
Exemplo de acesso ao webhook: https://ws.seudominio.com.br
5.3 – Sufixos dos serviços webhook
O servidor de webhook responde pelas URLs providas pelas automações e faz a separação por pasta na URL, acessos:
- Trigger webhook: Sufixo padrão “webhook“, pode ser personalizado na variável N8N_ENDPOINT_WEBHOOK.
- URL: https://ws.seudominio.com.br/webhook/
- Alternativa: definir como N8N_EDITOR_BASE_URL=v1, fica assim:
- URL: https://ws.seudominio.com.br/v1/
- Trigger MCP-Server: Sufixo padrão “mcp“, pode ser personalizado na variável N8N_ENDPOINT_MCP.
- URL: https://ws.seudominio.com.br/mcp/
- Trigger Form: Sufixo padrão “form“, pode ser personalizado na variável N8N_ENDPOINT_FORM.
- URL: https://ws.seudominio.com.br/form/
Não altere a menos que seja proposital e planejado pois pode quebrar automações antigas e ou importadas.
6 – Executando o N8N
Vamos partir para a criação dos serviços com tudo que organizamos até aqui usando o N8N em uma URL pública (HTTPs provido por Traefik e LetsEncrypt).
6.1 – Pasta do projeto
Crie uma pasta para o projeto, nele iremos colocar todos os arquivos necessários para rodar independente do estilo (eu prefiro “docker run”).
Diretório: /root/n8n-deploy:
# Diretorio do projeto
mkdir -p /root/n8n-deploy;
6.2 – Pasta dos volumes
Você pode usar qualquer volume em qualquer diretório, o importante é fixar o UID/GID da pasta principal do volume para 1000 (usuário node dentro do container).
Arquivo: /root/n8n-deploy/run-11-datadir.sh
# Pasta para volume dos containers
mkdir -p /storage/n8n-app;
mkdir -p /storage/n8n-app/editor;
mkdir -p /storage/n8n-app/worker;
mkdir -p /storage/n8n-app/webhook;
mkdir -p /storage/n8n-app/runner;
# Corrigir permissoes:
chown -R 1000:1000 /storage/n8n-app;
6.3 – Versão do N8N
Vou usar a versão estável 2.11.3 na tag docker.n8n.io/n8nio/n8n:2.11.3, é importante evitar a tag “docker.n8n.io/n8nio/n8n:latest” pois podem haver updates que quebram funcionalidades.
Imagens:
- N8N: docker.n8n.io/n8nio/n8n:2.11.3
- Runner: n8nio/runners:2.11.3
Arquivo: /root/n8n-deploy/run-12-pull-image.sh
# Baixar imagem docker do N8N
docker pull docker.n8n.io/n8nio/n8n:2.11.3;
# Baixar imagem docker do Runner
docker pull n8nio/runners:2.11.3;
6.4 – Arquivos .env
Vamos criar um arquivo .env para cada grupo de variáveis baseado nos serviços que farão leitura deles, assim teremos uma configuração mais pontual e segura.
Variáveis que afetam todos os serviços.
Arquivo: /root/n8n-deploy/.env-n8n-global
GENERIC_TIMEZONE=America/Sao_Paulo
TZ=America/Sao_PauloVariáveis de todos os serviços para modo queue.
Arquivo: /root/n8n-deploy/.env-n8n-queue
EXECUTIONS_MODE=queue
EXECUTIONS_TIMEOUT=1800Variáveis de acesso ao Redis.
Arquivo: /root/n8n-deploy/.env-n8n-redis
QUEUE_BULL_REDIS_HOST=n8n-redisVariáveis de acesso ao Postgres.
Arquivo: /root/n8n-deploy/.env-n8n-postgres
DB_TYPE=postgresdb
DB_POSTGRESDB_HOST=n8n-pgsql
DB_POSTGRESDB_PASSWORD=tulipasqlVariáveis de todos os serviços do N8N.
Arquivo: /root/n8n-deploy/.env-n8n-services
N8N_ENCRYPTION_KEY=tulipa
NODE_ENV=production
N8N_DIAGNOSTICS_ENABLED=false
N8N_USER_FOLDER=/data
N8N_METRICS=trueVariáveis exclusivas do editor.
Arquivo: /root/n8n-deploy/.env-n8n-editor
N8N_EDITOR_BASE_URL=https://n8n.seudominio.com.br/
N8N_SECURE_COOKIE=false
N8N_AI_TIMEOUT_MAX=900000
N8N_VERSION_NOTIFICATIONS_ENABLED=false
N8N_VERSION_NOTIFICATIONS_WHATS_NEW_ENABLED=false
N8N_PUBLIC_API_SWAGGERUI_DISABLED=true
OFFLOAD_MANUAL_EXECUTIONS_TO_WORKERS=trueVariáveis de serviços WEB (editor e webhook).
Arquivo: /root/n8n-deploy/.env-n8n-web
WEBHOOK_URL=https://ws.seudominio.com.br/
N8N_HOST=n8n.seudominio.com.br
N8N_PROTOCOL=https
N8N_PROXY_HOPS=1Variáveis dos serviços de workflow (editor e worker).
Arquivo: /root/n8n-deploy/.env-n8n-core
N8N_RUNNERS_MODE=external
EXECUTIONS_DATA_SAVE_ON_PROGRESS=true
EXECUTIONS_DATA_SAVE_ON_SUCCESS=allVariáveis exclusivas do worker.
Arquivo: /root/n8n-deploy/.env-n8n-worker
N8N_RUNNERS_BROKER_LISTEN_ADDRESS=0.0.0.0
N8N_RUNNERS_ENABLED=trueVariáveis exclusivas do task-runner.
Arquivo: /root/n8n-deploy/.env-n8n-runner
N8N_RUNNERS_TASK_BROKER_URI=http://n8n-worker:5679
N8N_RUNNERS_MAX_CONCURRENCY=128Variáveis para comunicação entre editor, worker e task-runner.
Arquivo: /root/n8n-deploy/.env-n8n-tasks
N8N_RUNNERS_AUTH_TOKEN=tulipaVariáveis para
gestão de usuários e envio de emails, usadas somente pelo editor.
Arquivo: /root/n8n-deploy/.env-n8n-manager
N8N_SMTP_HOST=smtp.seudominio.com.br
N8N_SMTP_USER=voce@seudominio.com.br
N8N_SMTP_PASS=sua-senha-segura
N8N_SMTP_SENDER=voce@seudominio.com.brVariáveis para recursos enterprise, usadas apenas no editor, worker e worker.
Arquivo: /root/n8n-deploy/.env-n8n-enterprise
N8N_AI_ENABLED=true
N8N_AI_ASSISTANT_BASE_URL=https://n8n-ai-agent.seudominio.com.br
N8N_AI_ANTHROPIC_KEY=sk-ant-....sua-chave-aqui...
N8N_AI_PERSIST_BUILDER_SESSIONS=true6.5 – Executando o editor (main)
Script no arquivo /root/n8n-deploy/run-21-editor.sh
# Nome de DNS para acesso HTTPs
# - Importar da variavel N8N_HOST no arquivo .env
. /root/n8n-deploy/.env-n8n-web;
# Remover container atual:
docker rm -f n8n-editor 2>/dev/null;
# Rodando:
docker run -d \
--name n8n-editor -h n8n-editor.intranet.br \
--cpus=4 --memory=4g --memory-swap=4g --shm-size=1g \
--tmpfs /run:rw,noexec,nosuid,size=512m \
--tmpfs /tmp:rw,noexec,nosuid,size=512m \
\
--network network_public \
\
--env-file /root/n8n-deploy/.env-n8n-global \
--env-file /root/n8n-deploy/.env-n8n-queue \
--env-file /root/n8n-deploy/.env-n8n-redis \
--env-file /root/n8n-deploy/.env-n8n-postgres \
--env-file /root/n8n-deploy/.env-n8n-services \
--env-file /root/n8n-deploy/.env-n8n-manager \
--env-file /root/n8n-deploy/.env-n8n-enterprise \
\
--env-file /root/n8n-deploy/.env-n8n-editor \
--env-file /root/n8n-deploy/.env-n8n-web \
--env-file /root/n8n-deploy/.env-n8n-core \
--env-file /root/n8n-deploy/.env-n8n-tasks \
\
-v /storage/n8n-app/editor:/data \
\
--label "traefik.enable=true" \
--label "traefik.http.routers.n8n-editor.rule=Host(\`$N8N_HOST\`)" \
--label "traefik.http.routers.n8n-editor.entrypoints=web,websecure" \
--label "traefik.http.routers.n8n-editor.tls=true" \
--label "traefik.http.routers.n8n-editor.tls.certresolver=letsencrypt" \
--label "traefik.http.services.n8n-editor.loadbalancer.server.port=5678" \
\
docker.n8n.io/n8nio/n8n:2.11.3;
6.6 – Executando o webhook
Execução muito parecida com a do editor, difere pelo comando “webhook” no container. A o nome para redirecionamento no Traefik será retirado da variável WEBHOOK_URL.
Script no arquivo /root/n8n-deploy/run-22-webhook.sh
# Nome de DNS para acesso HTTPs
# - Importar da variavel N8N_HOST no arquivo .env
. /root/n8n-deploy/.env-n8n-web;
FQDN_WEBHOOK=$(echo $WEBHOOK_URL | cut -f3 -d/);
# Remover container atual:
docker rm -f n8n-webhook 2>/dev/null;
# Rodando:
docker run -d \
--name n8n-webhook -h n8n-webhook.intranet.br \
--cpus=4 --memory=4g --memory-swap=4g --shm-size=1g \
--tmpfs /run:rw,noexec,nosuid,size=512m \
--tmpfs /tmp:rw,noexec,nosuid,size=512m \
\
--network network_public \
\
--env-file /root/n8n-deploy/.env-n8n-global \
--env-file /root/n8n-deploy/.env-n8n-queue \
--env-file /root/n8n-deploy/.env-n8n-redis \
--env-file /root/n8n-deploy/.env-n8n-postgres \
--env-file /root/n8n-deploy/.env-n8n-services \
--env-file /root/n8n-deploy/.env-n8n-enterprise \
\
--env-file /root/n8n-deploy/.env-n8n-web \
\
-v /storage/n8n-app/webhook:/data \
\
--label "traefik.enable=true" \
--label "traefik.http.routers.n8n-webhook.rule=Host(\`$FQDN_WEBHOOK\`)" \
--label "traefik.http.routers.n8n-webhook.entrypoints=web,websecure" \
--label "traefik.http.routers.n8n-webhook.tls=true" \
--label "traefik.http.routers.n8n-webhook.tls.certresolver=letsencrypt" \
--label "traefik.http.services.n8n-webhook.loadbalancer.server.port=5678" \
\
docker.n8n.io/n8nio/n8n:2.11.3 webhook;
6.7 – Executando o worker
O worker precisa se conectar ao Redis, Postgres e aguardar o Task-Runner se conectar nele. O container deve rodar o comando “worker“.
Script no arquivo /root/n8n-deploy/run-23-worker.sh
# Remover container atual:
docker rm -f n8n-worker 2>/dev/null;
# Rodando:
docker run -d \
--name n8n-worker -h n8n-worker.intranet.br \
--cpus=4 --memory=4g --memory-swap=4g --shm-size=1g \
--tmpfs /run:rw,noexec,nosuid,size=512m \
--tmpfs /tmp:rw,noexec,nosuid,size=512m \
\
--network network_public \
\
--env-file /root/n8n-deploy/.env-n8n-global \
--env-file /root/n8n-deploy/.env-n8n-queue \
--env-file /root/n8n-deploy/.env-n8n-redis \
--env-file /root/n8n-deploy/.env-n8n-postgres \
--env-file /root/n8n-deploy/.env-n8n-services \
--env-file /root/n8n-deploy/.env-n8n-enterprise \
\
--env-file /root/n8n-deploy/.env-n8n-core \
--env-file /root/n8n-deploy/.env-n8n-worker \
--env-file /root/n8n-deploy/.env-n8n-tasks \
\
-v /storage/n8n-app/worker:/data \
\
docker.n8n.io/n8nio/n8n:2.11.3 worker;
6.8 – Executando o task-runner
O task-runner requer uma atenção especial à variável N8N_RUNNERS_TASK_BROKER_URI que deve apontar para o nome do container do worker na porta 5679.
Script no arquivo /root/n8n-deploy/run-24-runner.sh
# Remover container atual:
docker rm -f n8n-runner 2>/dev/null;
# Rodando:
docker run -d \
--name n8n-runner -h n8n-runner.intranet.br \
--cpus=4 --memory=4g --memory-swap=4g --shm-size=1g \
--tmpfs /run:rw,noexec,nosuid,size=512m \
--tmpfs /tmp:rw,noexec,nosuid,size=512m \
\
--network network_public \
\
--env-file /root/n8n-deploy/.env-n8n-global \
\
--env-file /root/n8n-deploy/.env-n8n-runner \
--env-file /root/n8n-deploy/.env-n8n-tasks \
\
-v /storage/n8n-app/runner:/data \
\
n8nio/runners:2.11.3;
6.9 – Execução final
Rode os scripts:
# Rodar scripts para implementar N8N:
bash "/root/n8n-deploy/run-01-network-public.sh";
bash "/root/n8n-deploy/run-02-traefic-app.sh";
bash "/root/n8n-deploy/run-03-n8n-postgresql.sh";
bash "/root/n8n-deploy/run-04-n8n-redis.sh";
bash "/root/n8n-deploy/run-11-datadir.sh";
bash "/root/n8n-deploy/run-12-pull-image.sh";
bash "/root/n8n-deploy/run-21-editor.sh";
bash "/root/n8n-deploy/run-22-webhook.sh";
bash "/root/n8n-deploy/run-23-worker.sh";
bash "/root/n8n-deploy/run-24-runner.sh";Agora todos os serviços estão rodando.
Exportando arquivos do tutorial em formato MarkDown.
Arquivo (execute após criar): /root/n8n-deploy/export-markdown.sh
# Exportar projeto em markdown
(
echo '# N8N v2 Deploy';
echo;
echo '## Arquivos ENV';
for envfile in /root/n8n-deploy/.env*; do
echo "### $envfile";
echo;
echo '```env'; cat $envfile; echo '```';
echo;
done;
echo;
echo '## Scripts';
for script in /root/n8n-deploy/run*; do
echo "### $script";
echo;
echo '```bash'; cat $script; echo '```';
echo;
done;
echo;
) > /root/n8n-deploy/README.md;
7 – Primeiro contato
Após rodar os containers, abra o navegador no endereço https://n8n.seudominio.com.br para cadastrar o login de administrador.
Você pode automatizar esse setup de usuário administrador.
Arquivo (execute após criar): /root/n8n-deploy/run-51-setup-admin.sh
# Nome de DNS para acesso HTTPs
# - Importar da variavel N8N_HOST no arquivo .env
. /root/n8n-deploy/.env-n8n-web;
# Dados do formulario
# Template JSON
JSON_DATA='{
"email": "admin@acme.com",
"firstName": "Acme",
"lastName": "Jobs",
"password": "Acme@123"
}';
echo "# Definir login administrativo:";
echo;
echo "# URL: https://$N8N_HOST/rest/owner/setup";
echo;
echo "$JSON_DATA";
echo;
# Acionar API:
curl --insecure \
-X POST \
-H 'Accept: application/json, text/plain, */*' \
-H 'Content-Type: application/json' \
-d "$JSON_DATA" \
-o "/tmp/n8n-instance-setup.json" \
"https://$N8N_HOST/rest/owner/setup";
8 – Stack para Docker Compose standalone
Agora vamos empacotar nosso setup para simplificar a implementação usando Docker Compose em um servidor sem swarm, ou seja, o Docker standalone.
8.1 – Preparativos – Rede e Traefik
Nessa stack vamos colocar o Traefik (container traefik-app) e a rede Docker (network_public). Troque o e-mail voce@seudomino.com.br pelo seu e-mail verdadeiro.
Arquivo: /root/n8n-deploy/docker-compose-traefik-standalone.yml
networks:
network_public:
name: network_public
driver: bridge
driver_opts:
com.docker.network.bridge.name: "br-net-public"
com.docker.network.bridge.enable_icc: "true"
com.docker.network.driver.mtu: "1500"
ipam:
driver: default
config:
- subnet: 10.249.0.0/16
gateway: 10.249.255.254
services:
traefik-app:
image: traefik:latest
container_name: traefik-app
hostname: traefik-app.intranet.br
restart: always
cpus: 4
mem_limit: 4g
memswap_limit: 4g
shm_size: 1g
read_only: true
tmpfs:
- /run:rw,noexec,nosuid,size=2m
- /tmp:rw,noexec,nosuid,size=2m
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- /storage/traefik-app/letsencrypt:/etc/letsencrypt
- /storage/traefik-app/config:/etc/traefik
- /storage/traefik-app/logs:/logs
networks:
- network_public
command:
# Global
- "--global.checkNewVersion=false"
- "--global.sendAnonymousUsage=false"
# API / Dashboard (acesso inseguro - use apenas em ambiente controlado)
- "--api.insecure=true"
# Logs de erro
- "--log.level=INFO"
- "--log.filePath=/logs/error.log"
# Logs de acesso
- "--accessLog.filePath=/logs/access.log"
# Entrypoint HTTP (porta 80) com redirect automático para HTTPS
- "--entrypoints.web.address=:80"
- "--entrypoints.web.http.redirections.entryPoint.to=websecure"
- "--entrypoints.web.http.redirections.entryPoint.scheme=https"
- "--entrypoints.web.http.redirections.entryPoint.permanent=true"
# Entrypoint HTTPS (porta 443)
- "--entrypoints.websecure.address=:443"
# Providers
- "--providers.docker=true"
- "--providers.file.directory=/etc/traefik"
# Certificados Let's Encrypt via HTTP Challenge
- "--certificatesresolvers.letsencrypt.acme.email=voce@seudominio.com.br"
- "--certificatesresolvers.letsencrypt.acme.storage=/etc/letsencrypt/acme.json"
- "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
Aplicar stack:
# Implementar Traefik e rede network_public:
docker compose -f /root/n8n-deploy/docker-compose-traefik-standalone.yml up -d;
# [+] up 2/2
# ✔ Network network_public Created
# ✔ Container traefik-app Created
# Para destruir:
# docker compose -f /root/n8n-deploy/docker-compose-traefik.yml down;
8.2 – Stack básica dos scripts
Essa stack tem os mesmos argumentos dos scripts anteriores, fazendo referência aos arquivos .env-* das variáveis de ambiente e usando volumes montados em /storage/.
Para rodar com sucesso, crie os arquivos .env-* e a stack abaixo.
Troque os nomes de DNS de seudomino.com.br pelo seus nomes.
Arquivo: /root/n8n-deploy/docker-compose-n8n-standalone.yml
networks:
network_public:
external: true
x-n8n-common: &n8n-common
image: docker.n8n.io/n8nio/n8n:2.11.3
restart: always
cpus: 4
mem_limit: 4g
memswap_limit: 4g
shm_size: 1g
tmpfs:
- /run:rw,noexec,nosuid,size=512m
- /tmp:rw,noexec,nosuid,size=512m
networks:
- network_public
env_file:
- .env-n8n-global
- .env-n8n-queue
- .env-n8n-redis
- .env-n8n-postgres
- .env-n8n-services
services:
# ───────────────────────────────────────── PostgreSQL
n8n-pgsql:
image: pgvector/pgvector:pg18-trixie
container_name: n8n-pgsql
hostname: n8n-pgsql.intranet.br
restart: always
read_only: true
cpus: "2.0"
mem_limit: 2g
memswap_limit: 2g
shm_size: 1g
networks:
- network_public
tmpfs:
- /run:rw,noexec,nosuid,size=128m
- /tmp:rw,noexec,nosuid,size=128m
volumes:
- /storage/n8n-pgsql:/var/lib/postgresql/data
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: tulipasql
POSTGRES_DB: n8n
PGDATA: /var/lib/postgresql/data/pgdata
healthcheck:
test: ["CMD", "pg_isready", "-U", "postgres"]
interval: 5s
timeout: 5s
retries: 10
entrypoint: ["docker-entrypoint.sh"]
command:
- postgres
- --max_connections=8192
- --wal_level=minimal
- --max_wal_senders=0
- --port=5432
# ───────────────────────────────────────── Redis
n8n-redis:
image: redis:latest
container_name: n8n-redis
hostname: n8n-redis.intranet.br
restart: always
read_only: true
cpus: "1.0"
mem_limit: 1g
memswap_limit: 1g
working_dir: /data
networks:
- network_public
volumes:
- /storage/n8n-redis:/data
command: >
redis-server
--tcp-backlog 8192
--tcp-keepalive 30
--timeout 0
--dir /data
--save 16 1
--save 12 10
--save 6 100
--rdbcompression no
--appendonly yes
--appendfsync everysec
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 1s
timeout: 3s
retries: 5
# ───────────────────────────────────────── N8N Editor
n8n-editor:
<<: *n8n-common
container_name: n8n-editor
hostname: n8n-editor.intranet.br
depends_on:
n8n-pgsql:
condition: service_healthy
n8n-redis:
condition: service_healthy
env_file:
- .env-n8n-global
- .env-n8n-queue
- .env-n8n-redis
- .env-n8n-postgres
- .env-n8n-services
- .env-n8n-manager
- .env-n8n-enterprise
- .env-n8n-editor
- .env-n8n-web
- .env-n8n-core
- .env-n8n-tasks
volumes:
- /storage/n8n-app/editor:/data
labels:
traefik.enable: "true"
traefik.http.routers.n8n-editor.rule: "Host(`n8n.seudominio.com.br`)"
traefik.http.routers.n8n-editor.entrypoints: "web,websecure"
traefik.http.routers.n8n-editor.tls: "true"
traefik.http.routers.n8n-editor.tls.certresolver: "letsencrypt"
traefik.http.services.n8n-editor.loadbalancer.server.port: "5678"
# ───────────────────────────────────────── N8N Webhook
n8n-webhook:
<<: *n8n-common
container_name: n8n-webhook
hostname: n8n-webhook.intranet.br
command: webhook
depends_on:
n8n-pgsql:
condition: service_healthy
n8n-redis:
condition: service_healthy
env_file:
- .env-n8n-global
- .env-n8n-queue
- .env-n8n-redis
- .env-n8n-postgres
- .env-n8n-services
- .env-n8n-enterprise
- .env-n8n-web
volumes:
- /storage/n8n-app/webhook:/data
labels:
traefik.enable: "true"
traefik.http.routers.n8n-webhook.rule: "Host(`ws.seudominio.com.br`)"
traefik.http.routers.n8n-webhook.entrypoints: "web,websecure"
traefik.http.routers.n8n-webhook.tls: "true"
traefik.http.routers.n8n-webhook.tls.certresolver: "letsencrypt"
traefik.http.services.n8n-webhook.loadbalancer.server.port: "5678"
# ───────────────────────────────────────── N8N Worker
n8n-worker:
<<: *n8n-common
container_name: n8n-worker
hostname: n8n-worker.intranet.br
command: worker
depends_on:
n8n-pgsql:
condition: service_healthy
n8n-redis:
condition: service_healthy
env_file:
- .env-n8n-global
- .env-n8n-queue
- .env-n8n-redis
- .env-n8n-postgres
- .env-n8n-services
- .env-n8n-enterprise
- .env-n8n-core
- .env-n8n-worker
- .env-n8n-tasks
volumes:
- /storage/n8n-app/worker:/data
# ───────────────────────────────────────── N8N Task Runner
n8n-runner:
image: n8nio/runners:2.11.3
container_name: n8n-runner
hostname: n8n-runner.intranet.br
restart: always
cpus: 4
mem_limit: 4g
memswap_limit: 4g
shm_size: 1g
tmpfs:
- /run:rw,noexec,nosuid,size=512m
- /tmp:rw,noexec,nosuid,size=512m
networks:
- network_public
env_file:
- /root/n8n-deploy/.env-n8n-global
- /root/n8n-deploy/.env-n8n-runner
- /root/n8n-deploy/.env-n8n-tasks
volumes:
- /storage/n8n-app/runner:/data
Aplicar stack:
# Implementar N8N standalone:
docker compose -f /root/n8n-deploy/docker-compose-n8n-standalone.yml up -d;
# [+] up 6/6
# ✔ Container n8n-redis Healthy 1.8s
# ✔ Container n8n-runner Created 0.1s
# ✔ Container n8n-pgsql Healthy 5.8s
# ✔ Container n8n-worker Created 0.0s
# ✔ Container n8n-editor Created 0.0s
# ✔ Container n8n-webhook Created 0.0s
# Para destruir:
# docker compose -f /root/n8n-deploy/docker-compose-n8n-standalone.yml down;
8.3 – Stack final com variáveis incorporadas
Essa é a minha técnica favorita pois me permite criar um único arquivo do compose para o serviço. Preservei os nomes dos containers e os volumes montados.
Arquivo: /root/n8n-deploy/docker-compose-n8n-std-inline.yml
# ----------------------------------------- ENVs
x-env-global: &env-global
GENERIC_TIMEZONE: America/Sao_Paulo
TZ: America/Sao_Paulo
x-env-queue: &env-queue
EXECUTIONS_MODE: queue
EXECUTIONS_TIMEOUT: "1800"
x-env-redis: &env-redis
QUEUE_BULL_REDIS_HOST: n8n-redis
x-env-postgres: &env-postgres
DB_TYPE: postgresdb
DB_POSTGRESDB_HOST: n8n-pgsql
DB_POSTGRESDB_PASSWORD: tulipasql
x-env-services: &env-services
N8N_ENCRYPTION_KEY: tulipa
NODE_ENV: production
N8N_DIAGNOSTICS_ENABLED: "false"
N8N_USER_FOLDER: /data
N8N_METRICS: "true"
x-env-manager: &env-manager
N8N_SMTP_HOST: smtp.seudominio.com.br
N8N_SMTP_USER: voce@seudominio.com.br
N8N_SMTP_PASS: sua-senha-segura
N8N_SMTP_SENDER: voce@seudominio.com.br
x-env-enterprise: &env-enterprise
N8N_AI_ENABLED: "true"
N8N_AI_ASSISTANT_BASE_URL: https://n8n-ai-agent.seudominio.com.br
N8N_AI_ANTHROPIC_KEY: sk-ant-....sua-chave-aqui...
N8N_AI_PERSIST_BUILDER_SESSIONS: "true"
x-env-core: &env-core
N8N_RUNNERS_MODE: external
EXECUTIONS_DATA_SAVE_ON_PROGRESS: "true"
EXECUTIONS_DATA_SAVE_ON_SUCCESS: all
x-env-editor: &env-editor
N8N_EDITOR_BASE_URL: https://n8n.seudominio.com.br/
N8N_SECURE_COOKIE: false
N8N_AI_TIMEOUT_MAX: 900000
N8N_VERSION_NOTIFICATIONS_ENABLED: "false"
N8N_VERSION_NOTIFICATIONS_WHATS_NEW_ENABLED: "false"
N8N_PUBLIC_API_SWAGGERUI_DISABLED: "true"
OFFLOAD_MANUAL_EXECUTIONS_TO_WORKERS: "true"
x-env-web: &env-web
WEBHOOK_URL: https://ws.seudominio.com.br/
N8N_HOST: n8n.seudominio.com.br
N8N_PROTOCOL: https
N8N_PROXY_HOPS: "1"
x-env-tasks: &env-tasks
N8N_RUNNERS_AUTH_TOKEN: tulipa
x-env-worker: &env-worker
N8N_RUNNERS_BROKER_LISTEN_ADDRESS: 0.0.0.0
N8N_RUNNERS_ENABLED: "true"
x-env-runner: &env-runner
N8N_RUNNERS_TASK_BROKER_URI: http://n8n-worker:5679
N8N_RUNNERS_MAX_CONCURRENCY: 128
# ----------------------------------------- Shared Sets
x-n8n-common: &n8n-common
image: docker.n8n.io/n8nio/n8n:2.11.3
restart: always
cpus: 4
mem_limit: 4g
memswap_limit: 4g
shm_size: 1g
tmpfs:
- /run:rw,noexec,nosuid,size=512m
- /tmp:rw,noexec,nosuid,size=512m
networks:
- network_public
# ----------------------------------------- Deploy
networks:
network_public:
external: true
services:
# ----------------------------------------- PostgreSQL
n8n-pgsql:
image: pgvector/pgvector:pg18-trixie
container_name: n8n-pgsql
hostname: n8n-pgsql.intranet.br
restart: always
read_only: true
cpus: "2.0"
mem_limit: 2g
memswap_limit: 2g
shm_size: 1g
networks:
- network_public
tmpfs:
- /run:rw,noexec,nosuid,size=128m
- /tmp:rw,noexec,nosuid,size=128m
volumes:
- /storage/n8n-pgsql:/var/lib/postgresql/data
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: tulipasql
POSTGRES_DB: n8n
PGDATA: /var/lib/postgresql/data/pgdata
healthcheck:
test: ["CMD", "pg_isready", "-U", "postgres"]
interval: 5s
timeout: 5s
retries: 10
entrypoint: ["docker-entrypoint.sh"]
command:
- postgres
- --max_connections=8192
- --wal_level=minimal
- --max_wal_senders=0
- --port=5432
# ----------------------------------------- Redis
n8n-redis:
image: redis:latest
container_name: n8n-redis
hostname: n8n-redis.intranet.br
restart: always
read_only: true
cpus: "1.0"
mem_limit: 1g
memswap_limit: 1g
working_dir: /data
networks:
- network_public
volumes:
- /storage/n8n-redis:/data
command: >
redis-server
--tcp-backlog 8192
--tcp-keepalive 30
--timeout 0
--dir /data
--save 16 1
--save 12 10
--save 6 100
--rdbcompression no
--appendonly yes
--appendfsync everysec
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 1s
timeout: 3s
retries: 5
# ----------------------------------------- N8N Editor
# env: global + queue + redis + postgres + services
# + editor + web + core + tasks
n8n-editor:
<<: *n8n-common
container_name: n8n-editor
hostname: n8n-editor.intranet.br
depends_on:
n8n-pgsql:
condition: service_healthy
n8n-redis:
condition: service_healthy
environment:
<<: [*env-global, *env-queue, *env-redis, *env-postgres,
*env-services, *env-manager, *env-enterprise,
*env-editor, *env-web, *env-core, *env-tasks]
volumes:
- /storage/n8n-app/editor:/data
labels:
traefik.enable: "true"
traefik.http.routers.n8n-editor.rule: "Host(`n8n.seudominio.com.br`)"
traefik.http.routers.n8n-editor.entrypoints: "web,websecure"
traefik.http.routers.n8n-editor.tls: "true"
traefik.http.routers.n8n-editor.tls.certresolver: "letsencrypt"
traefik.http.services.n8n-editor.loadbalancer.server.port: "5678"
# ----------------------------------------- N8N Webhook
# env: global + queue + redis + postgres + services + web
n8n-webhook:
<<: *n8n-common
container_name: n8n-webhook
hostname: n8n-webhook.intranet.br
command: webhook
depends_on:
n8n-pgsql:
condition: service_healthy
n8n-redis:
condition: service_healthy
environment:
<<: [*env-global, *env-queue, *env-redis, *env-postgres,
*env-services, *env-web]
volumes:
- /storage/n8n-app/webhook:/data
labels:
traefik.enable: "true"
traefik.http.routers.n8n-webhook.rule: "Host(`ws.seudominio.com.br`)"
traefik.http.routers.n8n-webhook.entrypoints: "web,websecure"
traefik.http.routers.n8n-webhook.tls: "true"
traefik.http.routers.n8n-webhook.tls.certresolver: "letsencrypt"
traefik.http.services.n8n-webhook.loadbalancer.server.port: "5678"
# ----------------------------------------- N8N Worker
# env: global + queue + redis + postgres + services
# + core + worker + tasks
n8n-worker:
<<: *n8n-common
container_name: n8n-worker
hostname: n8n-worker.intranet.br
command: worker
depends_on:
n8n-pgsql:
condition: service_healthy
n8n-redis:
condition: service_healthy
environment:
<<: [*env-global, *env-queue, *env-redis, *env-postgres,
*env-services, *env-core, *env-worker, *env-tasks]
volumes:
- /storage/n8n-app/worker:/data
# ----------------------------------------- N8N Task Runner
# env: global + runner + tasks
n8n-runner:
image: n8nio/runners:2.11.3
container_name: n8n-runner
hostname: n8n-runner.intranet.br
restart: always
cpus: 4
mem_limit: 4g
memswap_limit: 4g
shm_size: 1g
tmpfs:
- /run:rw,noexec,nosuid,size=512m
- /tmp:rw,noexec,nosuid,size=512m
networks:
- network_public
environment:
<<: [*env-global, *env-runner, *env-tasks]
volumes:
- /storage/n8n-app/runner:/data
Aplicar stack:
# Implementar N8N standalone inline:
docker compose -f /root/n8n-deploy/docker-compose-n8n-std-inline.yml up -d;
# [+] up 6/6
# ✔ Container n8n-redis Healthy 1.8s
# ✔ Container n8n-runner Created 0.1s
# ✔ Container n8n-pgsql Healthy 5.8s
# ✔ Container n8n-worker Created 0.0s
# ✔ Container n8n-editor Created 0.0s
# ✔ Container n8n-webhook Created 0.0s
# Para destruir:
# docker compose -f /root/n8n-deploy/docker-compose-n8n-std-inline.yml down;
8.4 – Stack final incorporada sem task-runner
Bom… o task-runner, modo external, adiciona segurança e uma latência muito irritante na execução dos códigos Javascript e Python. Enquanto ainda é possível usar o modo internal, a melhor opção para performance é abrir mão da segurança.
As alterações para usar o modo legado internal são:
- Nas variáveis de .env-n8n-core (env-core), mudar para:
- N8N_RUNNERS_MODE=internal
- N8N_RUNNERS_ENABLED=true
- As variáveis de .env-n8n-worker não serão necessárias, desconsiderar:
- N8N_RUNNERS_BROKER_LISTEN_ADDRESS=0.0.0.0
- N8N_RUNNERS_ENABLED=true
- Não precisa rodar o serviço (container) do task-runner (sem .env-n8n-runner).
Problemas:
- Se o código Javascript abusar da memória RAM o container pode travar;
- Códigos em Python 3 não irão funcionar (somente com runner);
Nova stack:
Arquivo: /root/n8n-deploy/docker-compose-n8n-std-inline-internal.yml
# ----------------------------------------- ENVs
x-env-global: &env-global
GENERIC_TIMEZONE: America/Sao_Paulo
TZ: America/Sao_Paulo
x-env-queue: &env-queue
EXECUTIONS_MODE: queue
EXECUTIONS_TIMEOUT: "1800"
x-env-redis: &env-redis
QUEUE_BULL_REDIS_HOST: n8n-redis
x-env-postgres: &env-postgres
DB_TYPE: postgresdb
DB_POSTGRESDB_HOST: n8n-pgsql
DB_POSTGRESDB_PASSWORD: tulipasql
x-env-services: &env-services
N8N_ENCRYPTION_KEY: tulipa
NODE_ENV: production
N8N_DIAGNOSTICS_ENABLED: "false"
N8N_USER_FOLDER: /data
N8N_METRICS: "true"
x-env-manager: &env-manager
N8N_SMTP_HOST: smtp.seudominio.com.br
N8N_SMTP_USER: voce@seudominio.com.br
N8N_SMTP_PASS: sua-senha-segura
N8N_SMTP_SENDER: voce@seudominio.com.br
x-env-enterprise: &env-enterprise
N8N_AI_ENABLED: "true"
N8N_AI_ASSISTANT_BASE_URL: https://n8n-ai-agent.seudominio.com.br
N8N_AI_ANTHROPIC_KEY: sk-ant-....sua-chave-aqui...
N8N_AI_PERSIST_BUILDER_SESSIONS: "true"
x-env-core: &env-core
N8N_RUNNERS_MODE: internal
N8N_RUNNERS_ENABLED: "true"
EXECUTIONS_DATA_SAVE_ON_PROGRESS: "true"
EXECUTIONS_DATA_SAVE_ON_SUCCESS: all
x-env-editor: &env-editor
N8N_EDITOR_BASE_URL: https://n8n.seudominio.com.br/
N8N_SECURE_COOKIE: false
N8N_AI_TIMEOUT_MAX: 900000
N8N_VERSION_NOTIFICATIONS_ENABLED: "false"
N8N_VERSION_NOTIFICATIONS_WHATS_NEW_ENABLED: "false"
N8N_PUBLIC_API_SWAGGERUI_DISABLED: "true"
OFFLOAD_MANUAL_EXECUTIONS_TO_WORKERS: "true"
x-env-web: &env-web
WEBHOOK_URL: https://ws.seudominio.com.br/
N8N_HOST: n8n.seudominio.com.br
N8N_PROTOCOL: https
N8N_PROXY_HOPS: "1"
x-env-tasks: &env-tasks
N8N_RUNNERS_AUTH_TOKEN: tulipa
# ----------------------------------------- Shared Sets
x-n8n-common: &n8n-common
image: docker.n8n.io/n8nio/n8n:2.11.3
restart: always
cpus: 4
mem_limit: 4g
memswap_limit: 4g
shm_size: 1g
tmpfs:
- /run:rw,noexec,nosuid,size=512m
- /tmp:rw,noexec,nosuid,size=512m
networks:
- network_public
# ----------------------------------------- Deploy
networks:
network_public:
external: true
services:
# ----------------------------------------- PostgreSQL
n8n-pgsql:
image: pgvector/pgvector:pg18-trixie
container_name: n8n-pgsql
hostname: n8n-pgsql.intranet.br
restart: always
read_only: true
cpus: "2.0"
mem_limit: 2g
memswap_limit: 2g
shm_size: 1g
networks:
- network_public
tmpfs:
- /run:rw,noexec,nosuid,size=128m
- /tmp:rw,noexec,nosuid,size=128m
volumes:
- /storage/n8n-pgsql:/var/lib/postgresql/data
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: tulipasql
POSTGRES_DB: n8n
PGDATA: /var/lib/postgresql/data/pgdata
healthcheck:
test: ["CMD", "pg_isready", "-U", "postgres"]
interval: 5s
timeout: 5s
retries: 10
entrypoint: ["docker-entrypoint.sh"]
command:
- postgres
- --max_connections=8192
- --wal_level=minimal
- --max_wal_senders=0
- --port=5432
# ----------------------------------------- Redis
n8n-redis:
image: redis:latest
container_name: n8n-redis
hostname: n8n-redis.intranet.br
restart: always
read_only: true
cpus: "1.0"
mem_limit: 1g
memswap_limit: 1g
working_dir: /data
networks:
- network_public
volumes:
- /storage/n8n-redis:/data
command: >
redis-server
--tcp-backlog 8192
--tcp-keepalive 30
--timeout 0
--dir /data
--save 16 1
--save 12 10
--save 6 100
--rdbcompression no
--appendonly yes
--appendfsync everysec
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 1s
timeout: 3s
retries: 5
# ----------------------------------------- N8N Editor
# env: global + queue + redis + postgres + services
# + editor + web + core + tasks
n8n-editor:
<<: *n8n-common
container_name: n8n-editor
hostname: n8n-editor.intranet.br
depends_on:
n8n-pgsql:
condition: service_healthy
n8n-redis:
condition: service_healthy
environment:
<<: [*env-global, *env-queue, *env-redis, *env-postgres,
*env-services, *env-manager, *env-enterprise,
*env-editor, *env-web, *env-core, *env-tasks]
volumes:
- /storage/n8n-app/editor:/data
labels:
traefik.enable: "true"
traefik.http.routers.n8n-editor.rule: "Host(`n8n.seudominio.com.br`)"
traefik.http.routers.n8n-editor.entrypoints: "web,websecure"
traefik.http.routers.n8n-editor.tls: "true"
traefik.http.routers.n8n-editor.tls.certresolver: "letsencrypt"
traefik.http.services.n8n-editor.loadbalancer.server.port: "5678"
# ----------------------------------------- N8N Webhook
# env: global + queue + redis + postgres + services + web
n8n-webhook:
<<: *n8n-common
container_name: n8n-webhook
hostname: n8n-webhook.intranet.br
command: webhook
depends_on:
n8n-pgsql:
condition: service_healthy
n8n-redis:
condition: service_healthy
environment:
<<: [*env-global, *env-queue, *env-redis, *env-postgres,
*env-services, *env-web]
volumes:
- /storage/n8n-app/webhook:/data
labels:
traefik.enable: "true"
traefik.http.routers.n8n-webhook.rule: "Host(`ws.seudominio.com.br`)"
traefik.http.routers.n8n-webhook.entrypoints: "web,websecure"
traefik.http.routers.n8n-webhook.tls: "true"
traefik.http.routers.n8n-webhook.tls.certresolver: "letsencrypt"
traefik.http.services.n8n-webhook.loadbalancer.server.port: "5678"
# ----------------------------------------- N8N Worker
# env: global + queue + redis + postgres + services
# + core + tasks
n8n-worker:
<<: *n8n-common
container_name: n8n-worker
hostname: n8n-worker.intranet.br
command: worker
depends_on:
n8n-pgsql:
condition: service_healthy
n8n-redis:
condition: service_healthy
environment:
<<: [*env-global, *env-queue, *env-redis, *env-postgres,
*env-services, *env-core, *env-tasks]
volumes:
- /storage/n8n-app/worker:/data
Aplicar stack:
# Implementar N8N standalone inline:
docker compose -f /root/n8n-deploy/docker-compose-n8n-std-inline-internal.yml up -d;
# [+] up 6/6
# ✔ Container n8n-redis Healthy 1.8s
# ✔ Container n8n-pgsql Healthy 5.8s
# ✔ Container n8n-worker Created 0.0s
# ✔ Container n8n-editor Created 0.0s
# ✔ Container n8n-webhook Created 0.0s
# Para destruir:
# docker compose -f /root/n8n-deploy/docker-compose-n8n-std-inline-internal.yml down;
9 – Stack para Docker Swarm
Agora vem a parte divertida: rodar o N8N com escala horizontal.
Para isso a stack sofrerá as seguintes alterações:
- Prefixo: no Swarm as stacks tem um nome de serviço que é usado como prefixo para o nome dos objetos (rede, serviços, volumes), assim simplifica-se o nome na stack.
- Limite de recursos: sessão “deploy” da stack;
- Rede: sem IP especificado para evitar conflitos;
- Réplicas: o serviços worker, webhook e runners serão replicados 4 vezes cada, você pode diminuir ou aumentar de acordo com sua carga de trabalho.
Arquivo: /root/n8n-deploy/docker-compose-swarm.yml
docker stack deploy -c docker-compose-swarm.yml n8n
x-env-global: &env-global
GENERIC_TIMEZONE: America/Sao_Paulo
TZ: America/Sao_Paulo
x-env-queue: &env-queue
EXECUTIONS_MODE: queue
EXECUTIONS_TIMEOUT: "1800"
x-env-redis: &env-redis
QUEUE_BULL_REDIS_HOST: redis
x-env-postgres: &env-postgres
DB_TYPE: postgresdb
DB_POSTGRESDB_HOST: pgsql
DB_POSTGRESDB_PASSWORD: tulipasql
x-env-services: &env-services
N8N_ENCRYPTION_KEY: tulipa
NODE_ENV: production
N8N_DIAGNOSTICS_ENABLED: "false"
N8N_USER_FOLDER: /data
N8N_METRICS: "true"
x-env-editor: &env-editor
N8N_EDITOR_BASE_URL: https://n8n.cloud05.tmsoft.com.br/
N8N_SECURE_COOKIE: false
N8N_AI_TIMEOUT_MAX: 900000
N8N_VERSION_NOTIFICATIONS_ENABLED: "false"
N8N_VERSION_NOTIFICATIONS_WHATS_NEW_ENABLED: "false"
N8N_PUBLIC_API_SWAGGERUI_DISABLED: "true"
OFFLOAD_MANUAL_EXECUTIONS_TO_WORKERS: "true"
x-env-web: &env-web
WEBHOOK_URL: https://ws.cloud05.tmsoft.com.br/
N8N_HOST: n8n.cloud05.tmsoft.com.br
N8N_PROTOCOL: https
N8N_PROXY_HOPS: "1"
x-env-core: &env-core
N8N_RUNNERS_MODE: external
EXECUTIONS_DATA_SAVE_ON_PROGRESS: "true"
EXECUTIONS_DATA_SAVE_ON_SUCCESS: all
x-env-tasks: &env-tasks
N8N_RUNNERS_AUTH_TOKEN: tulipa
x-env-worker: &env-worker
N8N_RUNNERS_BROKER_LISTEN_ADDRESS: 0.0.0.0
N8N_RUNNERS_ENABLED: "true"
x-env-runner: &env-runner
N8N_RUNNERS_TASK_BROKER_URI: http://worker:5679
N8N_RUNNERS_MAX_CONCURRENCY: 128
x-n8n-common: &n8n-common
image: docker.n8n.io/n8nio/n8n:2.11.3
networks:
- intranet
networks:
intranet:
name: intranet
driver: overlay
attachable: true
driver_opts:
com.docker.network.driver.mtu: "1450"
volumes:
pgsql:
redis:
editor:
webhook:
worker:
runner:
services:
# ----------------------------------------- PostgreSQL
pgsql:
image: pgvector/pgvector:pg18-trixie
read_only: true
networks:
- intranet
volumes:
- pgsql:/var/lib/postgresql/data
- type: tmpfs
target: /run
tmpfs:
size: 134217728
- type: tmpfs
target: /tmp
tmpfs:
size: 134217728
- type: tmpfs
target: /dev/shm
tmpfs:
size: 1073741824
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: tulipasql
POSTGRES_DB: n8n
PGDATA: /var/lib/postgresql/data/pgdata
healthcheck:
test: ["CMD", "pg_isready", "-U", "postgres"]
interval: 5s
timeout: 5s
retries: 10
entrypoint: ["docker-entrypoint.sh"]
command:
- postgres
- --max_connections=8192
- --wal_level=minimal
- --max_wal_senders=0
- --port=5432
deploy:
replicas: 1
placement:
constraints:
- node.hostname == manager-01
resources:
limits:
cpus: "2"
memory: 2G
reservations:
cpus: "0.5"
memory: 512M
restart_policy:
condition: any
delay: 5s
max_attempts: 0
# ----------------------------------------- Redis
redis:
image: redis:latest
read_only: true
working_dir: /data
networks:
- intranet
volumes:
- redis:/data
command: >
redis-server
--tcp-backlog 8192
--tcp-keepalive 30
--timeout 0
--dir /data
--save 16 1
--save 12 10
--save 6 100
--rdbcompression no
--appendonly yes
--appendfsync everysec
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 1s
timeout: 3s
retries: 5
deploy:
replicas: 1
placement:
constraints:
- node.hostname == manager-01
resources:
limits:
cpus: "1"
memory: 1G
reservations:
cpus: "0.25"
memory: 256M
restart_policy:
condition: any
delay: 5s
max_attempts: 0
# ----------------------------------------- N8N Editor
editor:
<<: *n8n-common
volumes:
- editor:/data
- type: tmpfs
target: /run
tmpfs:
size: 536870912
- type: tmpfs
target: /tmp
tmpfs:
size: 536870912
environment:
<<: [*env-global, *env-queue, *env-redis, *env-postgres, *env-services, *env-editor, *env-web, *env-core, *env-tasks]
deploy:
replicas: 1
placement:
constraints:
- node.hostname == manager-01
resources:
limits:
cpus: "4"
memory: 4G
reservations:
cpus: "1"
memory: 1G
restart_policy:
condition: any
delay: 5s
max_attempts: 0
labels:
traefik.enable: "true"
traefik.http.routers.n8n-editor.rule: "Host(`n8n.seudominio.com.br`)"
traefik.http.routers.n8n-editor.entrypoints: "web,websecure"
traefik.http.routers.n8n-editor.tls: "true"
traefik.http.routers.n8n-editor.tls.certresolver: "letsencrypt"
traefik.http.services.n8n-editor.loadbalancer.server.port: "5678"
# ----------------------------------------- N8N Webhook
webhook:
<<: *n8n-common
command: webhook
volumes:
- webhook:/data
- type: tmpfs
target: /run
tmpfs:
size: 536870912
- type: tmpfs
target: /tmp
tmpfs:
size: 536870912
environment:
<<: [*env-global, *env-queue, *env-redis, *env-postgres, *env-services, *env-web]
deploy:
replicas: 4
update_config:
parallelism: 1
delay: 10s
order: start-first
rollback_config:
parallelism: 1
order: start-first
resources:
limits:
cpus: "4"
memory: 4G
reservations:
cpus: "0.5"
memory: 512M
restart_policy:
condition: any
delay: 5s
max_attempts: 0
labels:
traefik.enable: "true"
traefik.http.routers.n8n-webhook.rule: "Host(`ws.seudominio.com.br`)"
traefik.http.routers.n8n-webhook.entrypoints: "web,websecure"
traefik.http.routers.n8n-webhook.tls: "true"
traefik.http.routers.n8n-webhook.tls.certresolver: "letsencrypt"
traefik.http.services.n8n-webhook.loadbalancer.server.port: "5678"
# ----------------------------------------- N8N Worker
worker:
<<: *n8n-common
command: worker
volumes:
- worker:/data
- type: tmpfs
target: /run
tmpfs:
size: 536870912
- type: tmpfs
target: /tmp
tmpfs:
size: 536870912
environment:
<<: [*env-global, *env-queue, *env-redis, *env-postgres, *env-services, *env-core, *env-worker, *env-tasks]
deploy:
replicas: 4
update_config:
parallelism: 1
delay: 10s
order: start-first
rollback_config:
parallelism: 1
order: start-first
resources:
limits:
cpus: "4"
memory: 4G
reservations:
cpus: "0.5"
memory: 512M
restart_policy:
condition: any
delay: 5s
max_attempts: 0
# ----------------------------------------- N8N Task Runner
runner:
image: n8nio/runners:2.11.3
networks:
- intranet
volumes:
- runner:/data
- type: tmpfs
target: /run
tmpfs:
size: 536870912
- type: tmpfs
target: /tmp
tmpfs:
size: 536870912
environment:
<<: [*env-global, *env-runner, *env-tasks]
deploy:
replicas: 4
update_config:
parallelism: 1
delay: 10s
order: start-first
rollback_config:
parallelism: 1
order: start-first
resources:
limits:
cpus: "4"
memory: 4G
reservations:
cpus: "0.5"
memory: 512M
restart_policy:
condition: any
delay: 5s
max_attempts: 0
Pronto, seu N8N está completo dentro do padrão da versão 2 e com todas as possibilidades para fazer o deploy.
“Precisa se perder para achar
lugares que não se acham,
se não todos saberiam onde fica.“
Capitão Barbossa – Piratas do Caribe
Terminamos por hoje!
Patrick Brandão, patrickbrandao@gmail.com
