Instalando N8N no MacOS

há 1 mês 25

Saudações.

Vou ensinar como rodar o N8N direto no MacOS, sem Docker, sem container, sem dependências externas na Internet.

Antigamente a Nodemation (n8n) criava o aplicativo do N8N para desktop mas infelizmente descontinuaram o método, passando a operar somente em Docker e com foco em nuvem.

Nesse link você encontra como realizar o processo de compilação a partir dos fontes para construção da imagem OCI (Docker) do zero:

E nesse link você aprende sobre os modos de execução do N8N:

Aqui vou focar na execução baseada nos fontes para personalizações e tunings profundos.

Pré-requisitos:

  • Computador Apple Silicon: Mac Mini ou notebook Apple com MacOS;
  • Acesso à Internet durante os procedimentos.

1 – Preparação

Vou isolar a execução dentro da estrutura do brew.

Abra o Terminal do MacOS:

  • Aplicativos => Utilitários => Terminal;

Execute os procedimentos de instalação do brew em:

Após instalar o brew, feche o terminal e abra-o novamente.

Se preferir, alterne o shell padrão para o bash em vez do csh:

Requer senha para alterar o shell, após alterar feche o Terminal e abra novamente.

Personalizando formato do shell:

BASH (MacOS)

# Banco e cinza #export PS1='\[\033[0;99m\][\[\033[0;90m\]\u\[\033[0;99m\]@\[\033[0;99m\]\h\[\033[0;99m\]] \[\033[1;38m\]\w\[\033[0;99m\] \$\[\033[0m\] '; # Verde e Amarelo export PS1='\[\033[0;99m\][\[\033[0;92m\]\u\[\033[0;99m\]@\[\033[0;93m\]\h\[\033[0;99m\]] \[\033[1;38m\]\w\[\033[0;99m\] \$\[\033[0m\] '; # Colocar personalizacao sempre que iniciar um novo shell: egrep -q PS1 ~/.bash_profile 2>/dev/null || \ /bin/echo "export PS1='$PS1';" >> ~/.bash_profile;

Feche o Terminal e abra novamente!

Atualizando brew antes de continuar:

BASH (MacOS)

# Atualizar brew: brew update; brew upgrade;

Garantir os binários do brew no caminho de busca dos programas no Terminal:

BASH (MacOS)

# Colocar homebrew no PATH egrep -q '/opt/homebrew/bin' ~/.bash_profile 2>/dev/null || \ /bin/echo "export PATH='/opt/homebrew/bin:$PATH';" >> ~/.bash_profile;

Feche o Terminal e abra novamente!

A pasta padrão do ecosistema brew é em: /opt/homebrew

Instalando programas necessários no brew:

BASH (MacOS)

# Uv brew install uv; # Git brew install git; # Python (necessário para algumas dependências, v3.14) brew install python3; # Jq - interpretador JSON brew install jq; #- Node.js - atual: 25 #- brew install node; # Node.js - versao 24 requerida pelo n8n brew install node@24; # Instalar Corepack (ignore erros) brew install corepack; brew unlink corepack; brew link --overwrite corepack;

2 – Compilar N8N do zero

O N8N é escrito em TypeScript (NodeJS), logo vamos precisar da pilha TS para preparar os fontes para execução.

2.1 – Baixando código fonte do N8N

Observem bem a versão do N8N que você irá usar. Link para conferir versões disponíveis:

BASH (MacOS)

# Diretorio para rodar o programa: /opt/homebrew/n8n-current mkdir -p /opt/homebrew/n8n-current; # Entrar no diretorio: cd /opt/homebrew/n8n-current; # Baixar do git a versao desejada: N8N_VERSION="1.121.2"; git clone \ --branch release/$N8N_VERSION \ --single-branch https://github.com/n8n-io/n8n.git . || echo "Falhou no git";

Crie a chave de criptografia do N8N, usada para proteger canais e credenciais internas:

BASH (MacOS)

# Config minima estatica: # tulipa ou md5(tulipa) = 52169089a52705298a67f2f8d9895c76 mkdir -p ~/.n8n; ( echo '{'; echo ' "encryptionKey": "tulipa"'; echo '}'; ) > ~/.n8n/config; # Permissoes fechadas: chmod 600 /Users/patrickbrandao/.n8n/config;

2.2 – Preparando ambiente do projeto

Ajustes necessários para sincronizar as versões corretas do node e npm.

BASH (MacOS)

# Entrar no diretorio dos fontes: cd /opt/homebrew/n8n-current; # Ativar corepack: corepack enable; # Selecionar versao do pnpm ~ 10.18.3 (muda a cada update do n8n): corepack prepare pnpm@10.23.0 --activate; # Garantir versao 24 do node como padrão do sistema: brew unlink node 2>/dev/null; brew link node@24 2>/dev/null; brew link --overwrite node@24 2>/dev/null; # Conferindo node 24: # Conferindo versões dos programas: node --version; # v24.11.1 # Conferindo caminho dos binarios: which node; # /opt/homebrew/bin/node # Conferindo binário real do comando 'node': readlink -f /opt/homebrew/bin/node; # /opt/homebrew/Cellar/node@24/24.11.1/bin/node # Retirar node 25 instalado pelo corepack brew uninstall --ignore-dependencies node@25 2>/dev/null; # Apontar node do corepack para a versao 24 mkdir -p /opt/homebrew/opt/node/bin; ln -sf \ /opt/homebrew/Cellar/node@24/24.11.1/bin/node \ /opt/homebrew/opt/node/bin/node; # Colocar corepack no projeto: corepack up;

2.3 – Compilando

Essa é a parte demorada, onde tod

BASH (MacOS)

# Entrar no diretorio dos fontes: cd /opt/homebrew/n8n-current; # Ajuste de permissoes: chmod -R u+rwX /opt/homebrew/n8n-current; # Instalar dependencias infinitas, essa é a parte que DEMORA MUITO ~5min: pnpm --loglevel verbose install; # Vai terminar com a mensagem na ultima linha: # "Done in 43s using pnpm v10.18.3" # (coloque aqui sua etapa de personalizacao dos fontes) # ... # Construindo projeto unificado, DEMORA MUITO ~15min: pnpm --loglevel verbose build; pnpm --loglevel verbose build:n8n;

Após esse processo será produzida a pasta:

  • ./compiled: /opt/homebrew/n8n-current/compiled

Esse é o diretório que deve ser exportado para adição em container Docker e enviado para produção.

2.4 – Exportando projeto compilado

Vamos usar a pasta “compiled” para instalar o n8n no local definitivo em /opt/homebrew/n8n-app

BASH (MacOS)

# Criar diretorio final: mkdir -p /opt/homebrew/n8n-app; # Entrar no diretorio final: cd /opt/homebrew/n8n-app; # Copiar projeto compilado para pasta atual: rsync -ravp /opt/homebrew/n8n-current/compiled/ /opt/homebrew/n8n-app/; # Rodando versão compilada para teste: # /opt/homebrew/n8n-app/bin/n8n start; # CONTROL+C para interromper o teste.

2.5 – Compilando Task-Runner JavaScript

Nota: Etapa é opcional, faça somente se você precisar do Task-Runner para o MacOS.

BASH (MacOS)

# Entrar no diretorio dos fontes: cd /opt/homebrew/n8n-current; # Instalar task-runner Javascript mkdir -p /opt/homebrew/tmp/runners; rsync -ravp dist/task-runner-javascript /opt/homebrew/tmp/runners/; # Compilar Task-Runners cd /opt/homebrew/tmp/runners/task-runner-javascript; corepack enable pnpm; # Ajustar package.json node -e "const pkg = require('./package.json'); \ Object.keys(pkg.dependencies || {}).forEach(k => { \ const val = pkg.dependencies[k]; \ if (val === 'catalog:' || val.startsWith('catalog:') || val.startsWith('workspace:')) \ delete pkg.dependencies[k]; \ }); \ Object.keys(pkg.devDependencies || {}).forEach(k => { \ const val = pkg.devDependencies[k]; \ if (val === 'catalog:' || val.startsWith('catalog:') || val.startsWith('workspace:')) \ delete pkg.devDependencies[k]; \ }); \ delete pkg.devDependencies; \ require('fs').writeFileSync('./package.json', JSON.stringify(pkg, null, 2));"; # Instalar pacoate 'moment' rm -f node_modules/.modules.yaml; pnpm add moment@2.30.1 --prod --no-lockfile; # Caminho do Task-Runner Javascript: ls -lah /opt/homebrew/tmp/runners/task-runner-javascript/dist/start.js; # Colocar Task-Runner junto com o N8N pronto rsync -ravp /opt/homebrew/tmp/runners /opt/homebrew/n8n-app/; # Remover diretorio temporario do runners rm -rf /opt/homebrew/tmp/runners;

2.6 – Compilando Task-Runner Launcher

Nota: Etapa é opcional, faça somente se você precisar do Task-Runner para o MacOS.

O Task-Runner Launcher é responsável pelo gerenciamento da execução dos Task-Runners e pela comunicação com o processo worker do N8N.

BASH (MacOS)

# Pasta temporaria para compilacao # - Remover e recriar pasta temporaria rm -rf /opt/homebrew/tmp; mkdir -p /opt/homebrew/tmp; cd /opt/homebrew/tmp; # Instalar Go brew install go; # Converir versao do Go go version; # go version go1.25.4 darwin/arm64 # Obter codigo-fonte do Task-Runner-Launcher git clone https://github.com/n8n-io/task-runner-launcher.git; cd /opt/homebrew/tmp/task-runner-launcher; # Compilar (modo simples) #- go build -o task-runner-launcher ./cmd/launcher; # Compilar com otimizações GOOS=darwin GOARCH=arm64 go \ build -ldflags="-s -w" \ -o task-runner-launcher ./cmd/launcher; # Conferindo tipo do binario compilado: file ./task-runner-launcher; # ./task-runner-launcher: Mach-O 64-bit executable arm64 # Conferindo binario pronto (o erro abaixo significa que funcionou): ./task-runner-launcher --version; # 2025/11/25 01:21:20 ERROR Failed to load config: # AuthToken: missing required value: N8N_RUNNERS_AUTH_TOKEN # Distribuir binario TRL para estrutura do brew: mkdir -p /opt/homebrew/n8n-app/runners; rm -rf /opt/homebrew/n8n-app/runners/task-runner-launcher; cp -av ./task-runner-launcher /opt/homebrew/n8n-app/runners/task-runner-launcher; # Criar link simbolico no caminho oficial ln -sf \ /opt/homebrew/n8n-app/runners/task-runner-launcher \ /opt/homebrew/bin/task-runner-launcher; # Limpar diretorio usado na compilacao: cd /opt/homebrew; rm -rf /opt/homebrew/tmp;

3 – Preparativos para o modo fila

Para rodar o N8N em modo fila vamos precisar do Redis e do PostgreSQL no nosso MacOS.

3.1 – PostgreApp

A melhor forma de provisionar um serviço de banco de dados no MacOS é com o PGAPP:

Procedimentos:

  • Garanta a existência de um serviço PostgreSQL 18
  • Garanta que o serviço está marcado para iniciar automaticamente;
  • Garanta que o PostgresApp está marcado para iniciar automaticamente no MacOS.

Tela do PGAPP:

O próximo passo é criar o banco de dados do N8N no serviço PostgreSQL 18. Conecte-se no banco de dados postgres com usuário postgres e execute:

psql -U postgres

-- Criar usuario exclusivo para o n8n chamado "n8n_local_user": CREATE USER n8n_local_user WITH PASSWORD 'n8nsql2025' CREATEDB LOGIN; -- criar db e usuario do n8n chamado "n8n_local_db": CREATE DATABASE n8n_local_db WITH OWNER = n8n_local_user ENCODING = 'UTF8' TABLESPACE = pg_default IS_TEMPLATE = False CONNECTION LIMIT = -1; -- Conectar no banco "n8n_local_db": \c n8n_local_db; -- Conceder todos os privilégios ao usuario "n8n_local_user" no banco "n8n_local_db" GRANT ALL PRIVILEGES ON DATABASE n8n_local_db TO n8n_local_user; -- Adicionar extensao (ignore alerta, se ja existir otimo): CREATE EXTENSION IF NOT EXISTS pg_stat_statements; -- Conceder privilégios no schema público GRANT ALL ON SCHEMA public TO n8n_local_user; -- Garantir privilégios em tabelas futuras ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO n8n_local_user; ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON SEQUENCES TO n8n_local_user; ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON FUNCTIONS TO n8n_local_user; -- Verificar se o usuário foi criado \du n8n_local_user; -- Verificar se o banco foi criado \l n8n_local_db; -- Verificar privilégios no banco \l+ n8n_local_db; -- Sair \q

Serviço PostgreSQL criado:

  • Endereço do servidor PostgreSQL: localhost (127.0.0.1 ou ::1) porta 5432
  • Usuário e senha de acesso: n8n_local_user senha n8nsql2025
  • Banco de dados chamado: n8n_local_db

Se desejar uma administração visual do banco de dados, instale o pgAdmin para MacOS:

3.2 – Redis Server

O Redis pode ser instalado usando o próprio brew:

BASH (MacOS)

# Entrar no diretorio do brew: cd /opt/homebrew/; # Remover redis nativo, se presente: brew uninstall redis 2>/dev/null; # Instalando Redis: brew tap redis/redis; brew install --cask redis; # Conferindo configuração padrão: cat /opt/homebrew/etc/redis.conf | egrep -v '^(#|$)'; # Garantir existencia do diretorio de dados: mkdir -p /opt/homebrew/var/db/redis;

Nenhuma configuração especial é requerida no Redis.

Parar criar serviço do Redis no gestor de serviços do MacOS (Launcher) crie o arquivo:

  • ~/Library/LaunchAgents/com.redis-server.plist

Com o seguinte conteúdo:

~/Library/LaunchAgents/com.redis-server.plist

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Label</key> <string>com.redis-server</string> <key>ProgramArguments</key> <array> <string>/opt/homebrew/bin/redis-server</string> <string>--bind '0.0.0.0 ::'</string> <string>--port 6379</string> <string>--set-proc-title no</string> <string>--tcp-backlog 8192</string> <string>--tcp-keepalive 30</string> <string>--timeout 0</string> <string>--save 900 1</string> <string>--save 300 10</string> <string>--save 60 10000</string> <string>--dir /opt/homebrew/var/db/redis/</string> <string>--rdbcompression no</string> <string>--rdbchecksum yes</string> <string>--dbfilename data.rdb</string> <string>--appendonly yes</string> <string>--appendfsync everysec</string> <string>--appendfilename data.aof</string> </array> <key>WorkingDirectory</key> <string>/opt/homebrew/var/db/redis</string> <key>EnvironmentVariables</key> <dict> <key>TZ</key><string>America/Sao_Paulo</string> </dict> <key>RunAtLoad</key> <true/> <key>KeepAlive</key> <true/> <key>StandardOutPath</key> <string>/tmp/redis-server-stdout.log</string> <key>StandardErrorPath</key> <string>/tmp/redis-server-error.log</string> </dict> </plist>

Registrar serviço e iniciar:

BASH (MacOS)

# Parar o serviço: launchctl stop com.redis-server; # Descarregar: launchctl unload ~/Library/LaunchAgents/com.redis-server.plist; # Limpar logs echo > /tmp/redis-server-stdout.log; echo > /tmp/redis-server-error.log; # Carregar no cadastro de serviços: launchctl load ~/Library/LaunchAgents/com.redis-server.plist; # Parar o serviço (execute e aguarde uns 15s) launchctl stop com.redis-server; # Iniciar o serviço launchctl start com.redis-server; # Verificar status launchctl list | grep redis; # rodando: 59073 0 com.redis-server # parado.: - 0 com.redis-server # Ver logs tail -n 20 /tmp/redis-server-stdout.log; tail -n 20 /tmp/redis-server-error.log; # Acompanhar logs tail -f /tmp/redis-server-stdout.log /tmp/redis-server-error.log;

Serviço Redis criado:

  • Endereço do servidor Redis: localhost (127.0.0.1 ou ::1) porta 6379
  • Usuário e senha de acesso: (sem senha)

Testando serviço Redis:

BASH (MacOS)

redis-cli -h localhost -p 6379; SET teste 123 # OK GET teste "123" DEL teste (integer) 1 GET teste (nil) exit

4 – Rodando N8N no modo fila no MacOS

Antes de continuar é necessário entender as variáveis de ambiente envolvidas.

4.1 – Variáveis de ambiente

Variáveis de ambiente que devem estar presentes em todos os serviços do N8N:

VariávelObjetivo
EXECUTIONS_MODEPadrão “regular”, alterar para queue
N8N_ENCRYPTION_KEYtulipa
TZAmerica/Sao_Paulo
GENERIC_TIMEZONEAmerica/Sao_Paulo
DB_TYPETipo de banco de dados, padrão “sqlite”, alterar para “postgresdb“.
DB_POSTGRESDB_HOSTEndereço IP/DNS do servidor PG, localhost
DB_POSTGRESDB_PORTPorta TCP do servidor PG, 5432
DB_POSTGRESDB_USERUsuário de autenticação, n8n_local_user
DB_POSTGRESDB_PASSWORDSenha de autenticação, n8nsql2025
DB_POSTGRESDB_DATABASENome do banco de dados, n8n_local_db
DB_POSTGRESDB_SCHEMANome do esquema, public
QUEUE_BULL_REDIS_HOSTEndereço do servidor Redis, localhost
QUEUE_BULL_REDIS_PORTPorta do servidor Redis, 6379
QUEUE_BULL_REDIS_DBNúmero do DB no Redis (0), mudar para 8
QUEUE_BULL_REDIS_PASSWORDSenha do Redis, deixar sem (padrão)
QUEUE_BULL_REDIS_DUALSTACKPermitir IPv4 e IPv6 na conexão, true
QUEUE_HEALTH_CHECK_ACTIVEVerificar serviço de filas, true

Personalize sse precisar.

Variáveis que não podem repetir:

VariávelObjetivo
N8N_PORTPadrão 5678, mas cada serviço precisará da sua porta pois todos estão rodando juntos.

Vou usar as seguintes portas:

  • Editor: porta 5780;
  • Webhook: porta 5690;
  • Worker: porta 5500, embora ele não deva abrir porta, por algum motivo ele insiste em abrir.

4.2 – Criando serviços do N8N no Launcher

Serviço: n8n-editor – Editor e execuções do editor (execuções manuais):

  • ~/Library/LaunchAgents/com.n8n-editor.plist

~/Library/LaunchAgents/com.n8n-editor.plist

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Label</key> <string>com.n8n-editor</string> <key>ProgramArguments</key> <array> <string>/opt/homebrew/bin/node</string> <string>/opt/homebrew/n8n-app/bin/n8n</string> <string>start</string> </array> <key>WorkingDirectory</key> <string>/opt/homebrew</string> <key>RunAtLoad</key> <true/> <key>KeepAlive</key> <true/> <key>StandardOutPath</key> <string>/tmp/n8n-editor-stdout.log</string> <key>StandardErrorPath</key> <string>/tmp/n8n-editor-error.log</string> <key>EnvironmentVariables</key> <dict> <key>N8N_PORT</key> <string>5780</string> <key>N8N_PROXY_HOPS</key> <string>1</string> <key>NODE_ENV</key> <string>production</string> <key>N8N_ENDPOINT_WEBHOOK</key> <string>v1</string> <key>N8N_ENDPOINT_WEBHOOK_TEST</key> <string>test</string> <key>N8N_ENDPOINT_WEBHOOK_WAIT</key> <string>ws-wait</string> <key>N8N_ENDPOINT_MCP</key> <string>mcp</string> <key>N8N_ENDPOINT_MCP_TEST</key> <string>mcp-test</string> <key>N8N_EDITOR_BASE_URL</key> <string>http://localhost:5780</string> <key>WEBHOOK_URL</key> <string>http://localhost:5690</string> <key>N8N_BASE_URL</key> <string>http://localhost:5780</string> <key>N8N_SECURE_COOKIE</key> <string>false</string> <key>N8N_DISABLE_PRODUCTION_MAIN_PROCESS</key> <string>true</string> <key>N8N_DIAGNOSTICS_ENABLED</key> <string>false</string> <key>N8N_BLOCK_ENV_ACCESS_IN_NODE</key> <string>false</string> <key>N8N_GIT_NODE_DISABLE_BARE_REPOS</key> <string>true</string> <key>N8N_USER_FOLDER</key> <string>/opt/homebrew/n8n-data</string> <key>N8N_CUSTOM_EXTENSIONS</key><string>/opt/homebrew/n8n-nodes</string> <key>N8N_COMMUNITY_PACKAGES_ALLOW_TOOL_USAGE</key> <string>true</string> <key>N8N_COMMUNITY_PACKAGES_ENABLED</key> <string>true</string> <key>N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS</key> <string>true</string> <key>N8N_EMAIL_MODE</key> <string>smtp</string> <key>N8N_SMTP_HOST</key> <string>smtp.intranet.br</string> <key>N8N_SMTP_PORT</key> <string>587</string> <key>N8N_SMTP_USER</key> <string>username</string> <key>N8N_SMTP_PASS</key> <string>pass123x</string> <key>N8N_SMTP_SENDER</key> <string>root@intranet.br</string> <key>N8N_SMTP_SSL</key> <string>true</string> <key>EXECUTIONS_MODE</key> <string>queue</string> <key>N8N_ENCRYPTION_KEY</key> <string>tulipa</string> <key>TZ</key> <string>America/Sao_Paulo</string> <key>GENERIC_TIMEZONE</key> <string>America/Sao_Paulo</string> <key>DB_TYPE</key> <string>postgresdb</string> <key>DB_POSTGRESDB_HOST</key> <string>localhost</string> <key>DB_POSTGRESDB_PORT</key> <string>5432</string> <key>DB_POSTGRESDB_USER</key> <string>n8n_local_user</string> <key>DB_POSTGRESDB_PASSWORD</key> <string>n8nsql2025</string> <key>DB_POSTGRESDB_DATABASE</key> <string>n8n_local_db</string> <key>DB_POSTGRESDB_SCHEMA</key> <string>public</string> <key>QUEUE_BULL_REDIS_HOST</key> <string>localhost</string> <key>QUEUE_BULL_REDIS_PORT</key> <string>6379</string> <key>QUEUE_BULL_REDIS_DB</key> <string>8</string> <key>QUEUE_BULL_REDIS_DUALSTACK</key> <string>true</string> <key>QUEUE_HEALTH_CHECK_ACTIVE</key> <string>true</string> <key>EXECUTIONS_TIMEOUT</key> <string>1800</string> <key>EXECUTIONS_TIMEOUT_MAX</key> <string>1800</string> <key>EXECUTIONS_DATA_PRUNE</key> <string>true</string> <key>EXECUTIONS_DATA_MAX_AGE</key> <string>336</string> <key>EXECUTIONS_DATA_PRUNE_MAX_COUNT</key> <string>2048</string> <key>EXECUTIONS_DATA_PRUNE_HARD_DELETE_INTERVAL</key> <string>15</string> <key>EXECUTIONS_DATA_PRUNE_SOFT_DELETE_INTERVAL</key> <string>60</string> <key>EXECUTIONS_DATA_SAVE_ON_ERROR</key> <string>all</string> <key>EXECUTIONS_DATA_SAVE_ON_SUCCESS</key> <string>all</string> <key>EXECUTIONS_DATA_SAVE_ON_PROGRESS</key> <string>true</string> <key>EXECUTIONS_DATA_SAVE_MANUAL_EXECUTIONS</key> <string>true</string> <key>OFFLOAD_MANUAL_EXECUTIONS_TO_WORKERS</key> <string>true</string> </dict> </dict> </plist>

Serviço: n8n-webhook – Servidor HTTP para escuta de Webhooks (chamadas HTTP)

  • Arquivo: ~/Library/LaunchAgents/com.n8n-webhook.plist

~/Library/LaunchAgents/com.n8n-webhook.plist

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Label</key> <string>com.n8n-webhook</string> <key>ProgramArguments</key> <array> <string>/opt/homebrew/bin/node</string> <string>/opt/homebrew/n8n-app/bin/n8n</string> <string>webhook</string> </array> <key>WorkingDirectory</key> <string>/opt/homebrew</string> <key>RunAtLoad</key> <true/> <key>KeepAlive</key> <true/> <key>StandardOutPath</key> <string>/tmp/n8n-webhook-stdout.log</string> <key>StandardErrorPath</key> <string>/tmp/n8n-webhook-error.log</string> <key>EnvironmentVariables</key> <dict> <key>N8N_PORT</key> <string>5690</string> <key>N8N_PROXY_HOPS</key> <string>1</string> <key>NODE_ENV</key> <string>production</string> <key>N8N_ENDPOINT_WEBHOOK</key> <string>v1</string> <key>N8N_ENDPOINT_WEBHOOK_TEST</key> <string>test</string> <key>N8N_ENDPOINT_WEBHOOK_WAIT</key> <string>ws-wait</string> <key>N8N_ENDPOINT_MCP</key> <string>mcp</string> <key>N8N_ENDPOINT_MCP_TEST</key> <string>mcp-test</string> <key>N8N_EDITOR_BASE_URL</key> <string>http://localhost:5780</string> <key>WEBHOOK_URL</key> <string>http://localhost:5690</string> <key>N8N_BASE_URL</key> <string>http://localhost:5780</string> <key>N8N_DIAGNOSTICS_ENABLED</key> <string>false</string> <key>N8N_BLOCK_ENV_ACCESS_IN_NODE</key> <string>false</string> <key>N8N_GIT_NODE_DISABLE_BARE_REPOS</key> <string>true</string> <key>N8N_USER_FOLDER</key> <string>/opt/homebrew/n8n-data</string> <key>N8N_CUSTOM_EXTENSIONS</key><string>/opt/homebrew/n8n-nodes</string> <key>N8N_COMMUNITY_PACKAGES_ALLOW_TOOL_USAGE</key> <string>true</string> <key>N8N_COMMUNITY_PACKAGES_ENABLED</key> <string>true</string> <key>N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS</key> <string>true</string> <key>EXECUTIONS_MODE</key> <string>queue</string> <key>N8N_ENCRYPTION_KEY</key> <string>tulipa</string> <key>TZ</key> <string>America/Sao_Paulo</string> <key>GENERIC_TIMEZONE</key> <string>America/Sao_Paulo</string> <key>DB_TYPE</key> <string>postgresdb</string> <key>DB_POSTGRESDB_HOST</key> <string>localhost</string> <key>DB_POSTGRESDB_PORT</key> <string>5432</string> <key>DB_POSTGRESDB_USER</key> <string>n8n_local_user</string> <key>DB_POSTGRESDB_PASSWORD</key> <string>n8nsql2025</string> <key>DB_POSTGRESDB_DATABASE</key> <string>n8n_local_db</string> <key>DB_POSTGRESDB_SCHEMA</key> <string>public</string> <key>QUEUE_BULL_REDIS_HOST</key> <string>localhost</string> <key>QUEUE_BULL_REDIS_PORT</key> <string>6379</string> <key>QUEUE_BULL_REDIS_DB</key> <string>8</string> <key>QUEUE_BULL_REDIS_DUALSTACK</key> <string>true</string> <key>QUEUE_HEALTH_CHECK_ACTIVE</key> <string>true</string> <key>EXECUTIONS_TIMEOUT</key> <string>1800</string> <key>EXECUTIONS_TIMEOUT_MAX</key> <string>1800</string> <key>EXECUTIONS_DATA_PRUNE</key> <string>true</string> <key>EXECUTIONS_DATA_MAX_AGE</key> <string>336</string> <key>EXECUTIONS_DATA_PRUNE_MAX_COUNT</key> <string>2048</string> <key>EXECUTIONS_DATA_PRUNE_HARD_DELETE_INTERVAL</key> <string>15</string> <key>EXECUTIONS_DATA_PRUNE_SOFT_DELETE_INTERVAL</key> <string>60</string> <key>EXECUTIONS_DATA_SAVE_ON_ERROR</key> <string>all</string> <key>EXECUTIONS_DATA_SAVE_ON_SUCCESS</key> <string>all</string> <key>EXECUTIONS_DATA_SAVE_ON_PROGRESS</key> <string>true</string> <key>EXECUTIONS_DATA_SAVE_MANUAL_EXECUTIONS</key> <string>true</string> <key>OFFLOAD_MANUAL_EXECUTIONS_TO_WORKERS</key> <string>true</string> </dict> </dict> </plist>

Serviço: n8n-worker – Processo responsável pela execução dos Workflows

  • Arquivo: ~/Library/LaunchAgents/com.n8n-worker.plist

~/Library/LaunchAgents/com.n8n-worker.plist

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Label</key> <string>com.n8n-worker</string> <key>ProgramArguments</key> <array> <string>/opt/homebrew/bin/node</string> <string>/opt/homebrew/n8n-app/bin/n8n</string> <string>worker</string> <string>--concurrency=32</string> </array> <key>WorkingDirectory</key> <string>/opt/homebrew</string> <key>RunAtLoad</key> <true/> <key>KeepAlive</key> <true/> <key>StandardOutPath</key> <string>/tmp/n8n-worker-stdout.log</string> <key>StandardErrorPath</key> <string>/tmp/n8n-worker-error.log</string> <key>EnvironmentVariables</key> <dict> <key>N8N_PORT</key> <string>5500</string> <key>NODE_ENV</key> <string>production</string> <key>N8N_BASE_URL</key> <string>http://localhost:5780</string> <key>N8N_DIAGNOSTICS_ENABLED</key> <string>false</string> <key>N8N_BLOCK_ENV_ACCESS_IN_NODE</key> <string>false</string> <key>N8N_GIT_NODE_DISABLE_BARE_REPOS</key> <string>true</string> <key>N8N_USER_FOLDER</key> <string>/opt/homebrew/n8n-data</string> <key>N8N_CUSTOM_EXTENSIONS</key><string>/opt/homebrew/n8n-nodes</string> <key>N8N_COMMUNITY_PACKAGES_ALLOW_TOOL_USAGE</key> <string>true</string> <key>N8N_COMMUNITY_PACKAGES_ENABLED</key> <string>true</string> <key>N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS</key> <string>true</string> <key>EXECUTIONS_MODE</key> <string>queue</string> <key>N8N_ENCRYPTION_KEY</key> <string>tulipa</string> <key>TZ</key> <string>America/Sao_Paulo</string> <key>GENERIC_TIMEZONE</key> <string>America/Sao_Paulo</string> <key>DB_TYPE</key> <string>postgresdb</string> <key>DB_POSTGRESDB_HOST</key> <string>localhost</string> <key>DB_POSTGRESDB_PORT</key> <string>5432</string> <key>DB_POSTGRESDB_USER</key> <string>n8n_local_user</string> <key>DB_POSTGRESDB_PASSWORD</key> <string>n8nsql2025</string> <key>DB_POSTGRESDB_DATABASE</key> <string>n8n_local_db</string> <key>DB_POSTGRESDB_SCHEMA</key> <string>public</string> <key>QUEUE_BULL_REDIS_HOST</key> <string>localhost</string> <key>QUEUE_BULL_REDIS_PORT</key> <string>6379</string> <key>QUEUE_BULL_REDIS_DB</key> <string>8</string> <key>QUEUE_BULL_REDIS_DUALSTACK</key> <string>true</string> <key>QUEUE_HEALTH_CHECK_ACTIVE</key> <string>true</string> <key>EXECUTIONS_TIMEOUT</key> <string>1800</string> <key>EXECUTIONS_TIMEOUT_MAX</key> <string>1800</string> <key>EXECUTIONS_DATA_PRUNE</key> <string>true</string> <key>EXECUTIONS_DATA_MAX_AGE</key> <string>336</string> <key>EXECUTIONS_DATA_PRUNE_MAX_COUNT</key> <string>2048</string> <key>EXECUTIONS_DATA_PRUNE_HARD_DELETE_INTERVAL</key> <string>15</string> <key>EXECUTIONS_DATA_PRUNE_SOFT_DELETE_INTERVAL</key> <string>60</string> <key>EXECUTIONS_DATA_SAVE_ON_ERROR</key> <string>all</string> <key>EXECUTIONS_DATA_SAVE_ON_SUCCESS</key> <string>all</string> <key>EXECUTIONS_DATA_SAVE_ON_PROGRESS</key> <string>true</string> <key>EXECUTIONS_DATA_SAVE_MANUAL_EXECUTIONS</key> <string>true</string> <key>OFFLOAD_MANUAL_EXECUTIONS_TO_WORKERS</key> <string>true</string> </dict> </dict> </plist>

Registrar e executar serviços:

BASH (MacOS)

# Criar pasta para community-nodes: mkdir -p /opt/homebrew/n8n-nodes; # Criar pasta de arquivos do processo: mkdir -p /opt/homebrew/n8n-data; #------------------------------------------- Parar # Parar os serviços launchctl stop com.n8n-editor; launchctl stop com.n8n-webhook; launchctl stop com.n8n-worker; # Desregistrar (para atualizar) launchctl unload ~/Library/LaunchAgents/com.n8n-editor.plist 2>/dev/null; launchctl unload ~/Library/LaunchAgents/com.n8n-webhook.plist 2>/dev/null; launchctl unload ~/Library/LaunchAgents/com.n8n-worker.plist 2>/dev/null; # Limpar logs echo -n > /tmp/n8n-editor-error.log; echo -n > /tmp/n8n-editor-stdout.log; echo -n > /tmp/n8n-webhook-error.log; echo -n > /tmp/n8n-webhook-stdout.log; echo -n > /tmp/n8n-worker-error.log; echo -n > /tmp/n8n-worker-stdout.log; #------------------------------------------- Iniciar # Carregar no cadastro de serviços: launchctl load ~/Library/LaunchAgents/com.n8n-editor.plist; launchctl load ~/Library/LaunchAgents/com.n8n-webhook.plist; launchctl load ~/Library/LaunchAgents/com.n8n-worker.plist; # Iniciar os serviços launchctl start com.n8n-editor; launchctl start com.n8n-webhook; launchctl start com.n8n-worker; # Verificar status launchctl list | grep n8n; # 26377 0 com.n8n-webhook # 26080 0 com.n8n-editor # 26077 1 com.n8n-worker # Ver logs tail -n 20 /tmp/n8n*; # Acompanhar logs tail -f /tmp/n8n*;

O editor está na porta 5780 – http://localhost:5780/
O servidor HTTP de API (webhook) está na porta 5090 – http://localhost:5690/

O N8N está pronto. Use a vontade!

5 – Executar N8N com Task-Runner

Avançando rumo a perfeição, vamos compilar o Task-Runner (TR) para que ele se responsabilize pela execução de código Javascript/TypeScript e Python fora do Worker, criando no TR um ambiente Sandbox seguro para execuções de códigos de origem duvidosa (usuário, IA).

Vantagens:

  • Maior resiliência na execução de código estrangeiro
  • Segregação de execução de código estrangeiro em CPUs e servidores diferentes;

Desvantagens:

  • Mais lento, workflows que acionam node Code ficam mais lentos;
  • Latência de rede entre worker e task-runner afeta o tempo total de execução do worker;

Se você não quiser usar o Task-Runner, rode vários workers e crie rotinas que reiniciam os workers periodicamente para evitar memory-leak (acumulo de memória).

Pre-requisitos:

  • Task-Runner-Launcher;
  • Task-Runner-Javascript;

O Task-Runner-Python é opcional.

Configurar runners:

  • /etc/n8n-task-runners.json

/etc/n8n-task-runners.json

{ "task-runners": [ { "runner-type": "javascript", "workdir": "/opt/homebrew/n8n-app/runners/task-runner-javascript", "command": "/opt/homebrew/opt/node/bin/node", "args": [ "--disallow-code-generation-from-strings", "--disable-proto=delete", "/opt/homebrew/n8n-app/runners/task-runner-javascript/dist/start.js" ], "health-check-server-port": "5681", "allowed-env": [ "PATH", "GENERIC_TIMEZONE", "NODE_OPTIONS", "N8N_RUNNERS_AUTO_SHUTDOWN_TIMEOUT", "N8N_RUNNERS_TASK_TIMEOUT", "N8N_RUNNERS_MAX_CONCURRENCY", "N8N_SENTRY_DSN", "N8N_VERSION", "ENVIRONMENT", "DEPLOYMENT_NAME" ], "env-overrides": { "NODE_FUNCTION_ALLOW_BUILTIN": "crypto", "NODE_FUNCTION_ALLOW_EXTERNAL": "moment", "N8N_RUNNERS_HEALTH_CHECK_SERVER_HOST": "0.0.0.0" } } ] }

Variáveis que devem ser configuradas nas instâncias (editor, worker e webhook):

VariávelValor
N8N_RUNNERS_ENABLEDtrue
N8N_RUNNERS_MODEexternal
N8N_RUNNERS_AUTH_TOKENtulipa
N8N_RUNNERS_MAX_CONCURRENCY32
N8N_RUNNERS_TASK_TIMEOUT300
N8N_RUNNERS_HEARTBEAT_INTERVAL30
N8N_RUNNERS_INSECURE_MODEfalse
N8N_RUNNERS_TASK_REQUEST_TIMEOUT20

Variáveis que devem ser configuradas no Task-Runner-Launcher:

VariávelValor
N8N_RUNNERS_AUTH_TOKENtulipa
N8N_RUNNERS_MAX_CONCURRENCY32
N8N_RUNNERS_LAUNCHER_HEALTH_CHECK_PORT5588
N8N_RUNNERS_TASK_BROKER_URIhttp://127.0.0.1:5679
N8N_RUNNERS_LAUNCHER_LOG_LEVELinfo
N8N_RUNNERS_AUTO_SHUTDOWN_TIMEOUT15

Declare as seguintes variáveis de ambiente nos serviços editor, webhook e worker:

LaunchAgents ENVs (part)

<key>N8N_RUNNERS_ENABLED</key><string>true</string> <key>N8N_RUNNERS_PATH</key><string>/runners</string> <key>N8N_RUNNERS_MODE</key><string>external</string> <key>N8N_RUNNERS_AUTH_TOKEN</key><string>tulipa</string> <key>N8N_RUNNERS_MAX_CONCURRENCY</key><string>32</string> <key>N8N_RUNNERS_TASK_TIMEOUT</key><string>300</string> <key>N8N_RUNNERS_HEARTBEAT_INTERVAL</key><string>30</string> <key>N8N_RUNNERS_INSECURE_MODE</key><string>false</string> <key>N8N_RUNNERS_TASK_REQUEST_TIMEOUT</key><string>20</string>

É preciso adicionar a variável N8N_RUNNERS_BROKER_PORT com cuidado para não conflitar as portas na loopback:

  • Editor: N8N_RUNNERS_BROKER_PORT deve mudar da porta padrão para a porta 5501. O editor abre a porta mesmo no modo fila, mudar para não conflitar com a porta 5679 que deve ser exclusiva do worker;
  • Webhook: não abre porta broker, não precisa declarar;
  • Worker: N8N_RUNNERS_BROKER_PORT na porta 5679 oficial.

Agora é necessário criar o serviço do Task-Runner-Launcher no Launcher do MacOS:

  • ~/Library/LaunchAgents/com.task-runner-launcher.plist

~/Library/LaunchAgents/com.task-runner-launcher.plist

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Label</key> <string>com.task-runner-launcher</string> <key>ProgramArguments</key> <array> <string>/opt/homebrew/n8n-app/runners/task-runner-launcher</string> <string>javascript</string> </array> <key>WorkingDirectory</key> <string>/opt/homebrew/n8n-app/runners</string> <key>RunAtLoad</key> <true/> <key>KeepAlive</key> <true/> <key>StandardOutPath</key> <string>/tmp/task-runner-launcher-stdout.log</string> <key>StandardErrorPath</key> <string>/tmp/task-runner-launcher-error.log</string> <key>EnvironmentVariables</key> <dict> <key>N8N_RUNNERS_AUTH_TOKEN</key><string>tulipa</string> <key>N8N_RUNNERS_MAX_CONCURRENCY</key><string>32</string> <key>N8N_RUNNERS_LAUNCHER_HEALTH_CHECK_PORT</key><string>5588</string> <key>N8N_RUNNERS_TASK_BROKER_URI</key><string>http://127.0.0.1:5679</string> <key>N8N_RUNNERS_LAUNCHER_LOG_LEVEL</key><string>info</string> <key>N8N_RUNNERS_AUTO_SHUTDOWN_TIMEOUT</key><string>15</string> </dict> </dict> </plist>

Registrar e iniciar serviço TRL:

BASH (MacOS)

#------------------------------------------- Parar # Parar os serviços launchctl stop com.task-runner-launcher; # Desregistrar (para atualizar) launchctl unload ~/Library/LaunchAgents/com.task-runner-launcher.plist 2>/dev/null; # Limpar logs echo -n > /tmp/task-runner-launcher-stdout.log; echo -n > /tmp/task-runner-launcher-error.log; #------------------------------------------- Iniciar # Carregar no cadastro de serviços: launchctl load ~/Library/LaunchAgents/com.task-runner-launcher.plist; # Iniciar os serviços launchctl start com.task-runner-launcher; # Verificar status launchctl list | grep task-runner-launcher; # 26413 0 task-runner-launcher # Ver logs tail -n 20 /tmp/task-runner-launcher-*; # Acompanhar logs tail -f /tmp/task-runner-launcher-*;

Após adicionar e iniciar o task-runner-launcher, reinicie os serviços do N8N:

BASH (MacOS)

# Recarregar os serviços do N8N: # - Parar launchctl stop com.n8n-editor; launchctl stop com.n8n-webhook; launchctl stop com.n8n-worker; # - Retirar registro launchctl unload ~/Library/LaunchAgents/com.n8n-editor.plist 2>/dev/null; launchctl unload ~/Library/LaunchAgents/com.n8n-webhook.plist 2>/dev/null; launchctl unload ~/Library/LaunchAgents/com.n8n-worker.plist 2>/dev/null; # - Aguardar desligamento sleep 5; # Carregar e iniciar automaticamente launchctl load ~/Library/LaunchAgents/com.n8n-editor.plist 2>/dev/null; launchctl load ~/Library/LaunchAgents/com.n8n-webhook.plist 2>/dev/null; launchctl load ~/Library/LaunchAgents/com.n8n-worker.plist 2>/dev/null;

6 – Testes de execução e APIs internas

Testar para conferir se as APIs e serviços estão respondendo.

BASH (MacOS)

# Conferir PID nas portas abertas lsof -i tcp:5780; # editor, porta de servidor http lsof -i tcp:5690; # webhook, porta de servidor http lsof -i tcp:5588; # launcher server - health check lsof -i tcp:5678; # worker, porta padrao lsof -i tcp:5679; # worker, porta do Task Broker # Endpoints # - Editor curl http://localhost:5780/healthz; # {"status":"ok"} curl http://localhost:5780/healthz/readiness; # {"status":"ok"} # - Webhook curl http://localhost:5690/; # deve retornar 404/not-found/html # - Worker - porta padrao curl http://localhost:5678/healthz; # {"status":"ok"} curl http://localhost:5678/healthz/readiness; # {"status":"ok"} # - Worker - porta do Task Broker curl http://localhost:5679/healthz; # {"status":"ok"} # - Task-Runner Launcher curl -s -X POST \ -H "Content-Type: application/json" \ -d '{"token":"tulipa"}' \ http://localhost:5679/runners/auth; #{ # "data": # { # "token":"50dac5034e737597bd358e99e31073d049bc60d0d0422415b55df0d48260a5ed" # } #}

Paris so é Paris se você vai de vez em quando, quando você vai todo dia Paris perde o seu encanto” Autor: Ricardo Thome

Terminamos por hoje,
Patrick Brandão <patrickbrandao@gmail.com>

Ler artigo completo