🐳 Docker Guide — OmniRoute (Português (Brasil))
Execução rápida
Seção intitulada “Execução rápida”Hospedar por conta própria com um único comando? Consulte o Guia de hospedagem própria —
docker compose -f docker-compose.selfhost.yml up -d(imagem publicada + Redis, somente loopback, sem escolha de perfil). A execução rápida abaixo é a opção de contêiner único para usuários que já executam o Redis em outro local.
docker run -d \ --name omniroute \ --restart unless-stopped \ --stop-timeout 40 \ -p 20128:20128 \ -v omniroute-data:/app/data \ diegosouzapw/omniroute:latestCom arquivo de ambiente
Seção intitulada “Com arquivo de ambiente”# Primeiro, copie e edite o arquivo .envcp .env.example .env
docker run -d \ --name omniroute \ --restart unless-stopped \ --stop-timeout 40 \ --env-file .env \ -p 20128:20128 \ -v omniroute-data:/app/data \ diegosouzapw/omniroute:latestDocker Compose
Seção intitulada “Docker Compose”# Perfil base (sem ferramentas de CLI)docker compose --profile base up -d
# Perfil de CLI (Claude Code, Codex e OpenClaw integrados)docker compose --profile cli up -d
# Perfil de host (prioriza Linux; monta os binários de CLI do host como somente leitura)docker compose --profile host up -d
# Perfil web (Chromium/Playwright para provedores de sessão web)docker compose --profile web up -d
# Combina CLI + contêiner auxiliar CLIProxyAPIdocker compose --profile cli --profile cliproxyapi up -dPerfis disponíveis
Seção intitulada “Perfis disponíveis”O OmniRoute fornece perfis do Compose para os principais tipos de implantação. Escolha aquele que corresponde ao seu ambiente.
| Perfil | Serviço | Quando usar | Comando |
|---|---|---|---|
base (padrão) |
omniroute-base |
Servidor sem interface gráfica / ambiente de execução mínimo, sem CLIs de provedores incluídas | docker compose --profile base up -d |
cli |
omniroute-cli |
Fluxos de trabalho com agentes que chamam omniroute providers/setup/doctor e CLIs incluídas (Codex, Claude Code, Droid, OpenClaw) |
docker compose --profile cli up -d |
host |
omniroute-host |
Hosts Linux que precisam de acesso semelhante a network_mode às CLIs do host montando ~/.local/bin, ~/.codex, ~/.claude etc. como somente leitura |
docker compose --profile host up -d |
cliproxyapi |
cliproxyapi |
Executa o sidecar CLIProxyAPI na porta 8317 para fazer proxy de CLIs upstream |
docker compose --profile cliproxyapi up -d |
web |
omniroute-web |
Provedores de sessão web que precisam de um navegador: gemini-web, claude-web, claude-turnstile (compila runner-web, com Chromium incluído) |
docker compose --profile web up -d |
É possível combinar vários perfis:
docker compose --profile cli --profile cliproxyapi up -d.
Configurando ferramentas de CLI do host quando o OmniRoute é executado no Docker
Seção intitulada “Configurando ferramentas de CLI do host quando o OmniRoute é executado no Docker”omniroute setup-codex, setup-claude, config set <tool> e o botão
Salvar configuração do painel gravam arquivos como ~/.codex/*.config.toml. Esses caminhos
só têm significado na máquina em que a CLI realmente é executada. Execute-os dentro
do contêiner e a gravação será feita no diretório pessoal do próprio contêiner (/home/node —
a imagem é executada com USER node), onde nenhuma CLI do host jamais fará a leitura e de onde os arquivos serão
descartados assim que o contêiner for recriado.
O OmniRoute detecta isso e recusa a gravação, fornecendo instruções em vez de
informar um sucesso que você não pode aproveitar: a CLI é encerrada com o código 2, e a API responde com 422
e containerEphemeralTarget: true.
Recomendado: execute a CLI no host e o OmniRoute no Docker
Seção intitulada “Recomendado: execute a CLI no host e o OmniRoute no Docker”O contêiner disponibiliza a API; a CLI configura as ferramentas do host.
docker compose --profile base up -d
npm install -g omnirouteomniroute connect http://localhost:20128 # aponte a CLI para o contêineromniroute setup-codex # grava o ~/.codex real no hostEssa é a escolha correta quando Codex, Claude Code, Cursor ou ferramentas semelhantes são executados no seu laptop — que é a configuração mais comum.
Alternativa: faça bind mount dos diretórios de configuração do host (perfil host)
Seção intitulada “Alternativa: faça bind mount dos diretórios de configuração do host (perfil host)”Se quiser que o próprio contêiner grave a configuração do host, monte os
diretórios e aponte CLI_CONFIG_HOME para a raiz da montagem. O perfil host
já faz isso:
environment: - CLI_CONFIG_HOME=/host-home - CLI_ALLOW_CONFIG_WRITES=truevolumes: - ~/.codex:/host-home/.codex:rw - ~/.claude:/host-home/.claude:rwUm bind mount é o que torna o caminho confiável: o OmniRoute lê
/proc/self/mountinfo e permite gravações em caminhos montados (e em diretórios
cujos filhos são montagens, que é exatamente a estrutura de /host-home acima), enquanto
continua recusando caminhos não montados.
Alternativa de escape: configure as próprias CLIs do contêiner (use com moderação)
Seção intitulada “Alternativa de escape: configure as próprias CLIs do contêiner (use com moderação)”Quando as CLIs realmente residem dentro do contêiner (o perfil cli), a gravação
é intencional. Passe --allow-container-write para qualquer comando setup-* ou defina
OMNIROUTE_ALLOW_CONTAINER_CONFIG_WRITE=true para o servidor. A gravação prossegue
com um aviso de que ela não sobreviverá ao contêiner.
Aviso de segurança — perfil
cli+ montagem dedocker.sock. O perfilclifaz bind mount de/var/run/docker.sockpara que o atualizador automático dentro do contêiner possa recriar a stack por meio do daemon do host (src/lib/system/autoUpdate.tsverifica a presença desse socket e ignora o caminho do Docker quando ele está ausente). Esse socket é um limite de confiança com acesso root ao host: qualquer coisa que consiga acessá-lo controla o daemon do Docker do host como root — podendo criar, inspecionar, interromper e remover qualquer contêiner no host. Implicações:
- Nunca exponha a porta do perfil
clià rede. Publique-a em127.0.0.1(ports: "127.0.0.1:${DASHBOARD_PORT:-20128}:...") — um perfilcliacessível pela LAN transforma qualquer RCE no nível do painel em comprometimento total do host.- Não faça bind mount de nenhum diretório adicional do host no perfil
cli. O socket do Docker, combinado com qualquer montagem adicional, concede ao contêiner acesso total de leitura/gravação ao sistema de arquivos e às configurações do host. Se precisar que uma ferramenta acesse um projeto, execute-a localmente com o binário da CLI — não o monte no contêinercli.Se não precisar da atualização automática dentro do contêiner, deixe o perfil
clidesativado (COMPOSE_PROFILES=core,redisou uma configuração mais curta). Os outros perfis não montam o socket do Docker.Consulte
docs/security/MITM-TPROXY-DECRYPT.md(git; não compilado em/docs) para ver o modelo de ameaças relacionado a MITM edocs/security/SUPPLY_CHAIN.mdpara consultar a cadeia de proveniência dos binárioscodex/claude-code/droid/openclaw.
Sidecar do Redis
Seção intitulada “Sidecar do Redis”O OmniRoute depende do Redis para dar suporte ao limitador de taxa distribuído e ao cache compartilhado. O serviço redis é sempre definido no docker-compose.yml (ele não é condicionado por nenhum perfil) e é iniciado junto com qualquer outro perfil.
| Detalhe | Valor |
|---|---|
| Imagem | redis:7-alpine |
| Nome do contêiner | omniroute-redis |
| Porta interna | 6379 |
| Porta do host (substituível) | REDIS_PORT (padrão: 6379) |
| Bind do host (substituível) | REDIS_BIND_HOST (padrão: 127.0.0.1) |
| Volume | omniroute-redis-data → /data |
| Verificação de integridade | redis-cli ping (intervalo de 10s) |
Variáveis de ambiente relacionadas:
REDIS_URL— string de conexão injetada na aplicação (redis://redis:6379por padrão).REDIS_PORT— mapeamento da porta do host para o contêiner do Redis.REDIS_BIND_HOST— interface do host na qual a porta é publicada. O padrão é127.0.0.1.
Por que usar loopback por padrão: o sidecar é executado sem
requirepass, e os contêineres da aplicação o acessam pela rede do compose (redis:6379) — a porta publicada existe apenas para ferramentas executadas no host (redis-cli, umnpm run devlocal). Publicá-la em0.0.0.0exporia um Redis sem autenticação a todos os hosts da sua LAN. Se você definirREDIS_BIND_HOST=0.0.0.0, adicione também--requirepassaocommand:do serviço.
Desabilitar o Redis não é recomendado (o limitador de taxa usará o fallback em memória, com funcionalidade reduzida). Se for necessário, remova/comente o bloco do serviço redis: no docker-compose.yml ou reduza sua escala para zero:
docker compose up -d --scale redis=0Compose de produção
Seção intitulada “Compose de produção”Para executar um snapshot isolado de produção em paralelo com o ambiente de desenvolvimento, use docker-compose.prod.yml.
| Detalhe | Valor |
|---|---|
| Arquivo | docker-compose.prod.yml |
| Porta padrão do dashboard | PROD_DASHBOARD_PORT=20130 (mapeada para a porta interna ${DASHBOARD_PORT:-20128}) |
| Porta padrão da API | PROD_API_PORT=20131 |
| Imagem | omniroute:prod (criada a partir do target runner-cli) |
| Contêiner do Redis | omniroute-redis-prod (redis:8.6.2, volume dedicado redis-prod-data) |
| Volume de dados | omniroute-prod-data (nomeado e persistente entre reconstruções) |
| Verificações de integridade | node healthcheck.mjs + redis-cli ping, com depends_on condicionado à integridade do Redis |
Como usar:
# Crie e inicie a stack de produçãodocker compose -f docker-compose.prod.yml up -d --build
# Acompanhe os logs em tempo realdocker compose -f docker-compose.prod.yml logs -f
# Encerre a stack (mantendo os volumes)docker compose -f docker-compose.prod.yml downA stack de produção é executada em paralelo com o compose de desenvolvimento (com nomes de contêineres, portas e volumes diferentes), portanto, você pode continuar trabalhando localmente enquanto a produção permanece em execução.
Estágios do Dockerfile
Seção intitulada “Estágios do Dockerfile”O repositório inclui um Dockerfile multiestágio (Dockerfile). Quatro estágios são disponibilizados; escolha o target correto para seu caso de uso.
| Estágio | Imagem base | Finalidade |
|---|---|---|
builder |
node:26-trixie-slim |
Instala as dependências (npm ci --legacy-peer-deps) e executa npm run build (Turbopack por padrão — consulte Recursos de build abaixo) |
runner-base |
node:26-trixie-slim |
Ambiente de execução de produção com a saída standalone do Next.js. Nenhuma CLI de provedor incluída. |
runner-cli |
runner-base |
Adiciona git, docker.io, docker-compose e as CLIs globais: @openai/codex, @anthropic-ai/claude-code, droid, openclaw. Escolha este estágio para fluxos de trabalho com agentes. |
runner-web |
runner-base |
Adiciona o Playwright e um navegador Chromium (--with-deps) para provedores de sessão web: gemini-web, claude-web, claude-turnstile. Escolha este estágio ao usar esses provedores — a imagem simples falha durante a solicitação sem ele (consulte a observação sobre -web em Canais de lançamento). |
Compile manualmente um target específico:
docker build --target runner-base -t omniroute:base .docker build --target runner-cli -t omniroute:cli .docker build --target runner-web -t omniroute:web .Recursos de build
Seção intitulada “Recursos de build”Três argumentos de build controlam o custo do estágio builder. Eles são usados apenas durante o build —
OMNIROUTE_MEMORY_MB (abaixo) é uma configuração separada de runtime.
| Argumento de build | Padrão | Efeito |
|---|---|---|
OMNIROUTE_USE_TURBOPACK |
1 |
0 compila usando webpack. Menor pico de memória, porém mais lento. |
OMNIROUTE_BUILD_MEMORY_MB |
6144 |
Limite de heap do V8 (--max-old-space-size) para o next build iniciado. |
OMNIROUTE_BUILD_WORKERS |
2 |
Alimenta CIRCLE_NODE_TOTAL; o Next deriva workers = N - 1 para coletar dados das páginas. |
OMNIROUTE_BUILD_WORKERS é a configuração que deve ser aumentada em um builder de grande porte e a primeira
a ser investigada quando um build com recursos limitados falha depois de ✓ Compiled successfully. Cada
worker de dados de páginas é um processo separado, assim como o próprio processo pai next build;
uma reprodução em um VPS real (issue #7518) mediu o pico de RSS de cada processo em
~4,5 GB, independentemente da opção de heap NODE_OPTIONS (o Turbopack compila usando
memória nativa/Rust fora do heap do V8). O padrão de 2 (→ 1 worker, 2
processos no total) foi dimensionado para os runners hospedados pelo GitHub com 16 GB / 4 vCPUs que o
pipeline de publicação utiliza. Com 8 (→ 7 workers), esse runner ficou sem memória e
o buildkit interrompeu a etapa com ResourceExhausted: ... cannot allocate memory;
3 (→ 2 workers) ainda não coube depois que o RSS por processo foi medido
diretamente, em vez de inferido. tests/unit/docker-build-memory-budget.test.ts
faz os cálculos com base no valor medido e falha se qualquer uma das configurações
ultrapassar a capacidade do runner.
O Turbopack compila usando memória nativa do Rust que fica fora do heap do V8, portanto
OMNIROUTE_BUILD_MEMORY_MB não a limita. Em um host com limite de memória, o
build recebe SIGKILL do OOM killer sem nenhuma mensagem de erro — ele simplesmente
para no meio de Creating an optimized production build, o que parece um travamento em vez
de falta de memória. Se o host de build tiver recursos limitados, troque o bundler:
docker build --target runner-base \ --build-arg OMNIROUTE_USE_TURBOPACK=0 \ -t omniroute:base .webpackBuildWorker está habilitado, portanto next build executa um processo pai e um processo
worker, e cada um respeita OMNIROUTE_BUILD_MEMORY_MB separadamente. Dimensione o limite
do contêiner para aproximadamente mais que o dobro desse valor, não apenas uma vez.
Medições nesta árvore (--target runner-base, OMNIROUTE_BUILD_MEMORY_MB=6144):
| Bundler | Limite do contêiner | Resultado |
|---|---|---|
| Turbopack | 8 GiB / 16 GiB | Encerrado pelo OOM em ambos, sem mensagem |
| webpack | 8 GiB | Worker de build recebeu SIGKILL |
| webpack | 12 GiB | Bem-sucedido, com pico de 11,1 GiB |
Padrões de runtime
Seção intitulada “Padrões de runtime”Valores padrão exportados por runner-base: PORT=20128, HOSTNAME=0.0.0.0, OMNIROUTE_MEMORY_MB=1024, NODE_OPTIONS=--max-old-space-size=1024, DATA_DIR=/app/data, OMNIROUTE_MIGRATIONS_DIR=/app/migrations.
Comportamento da memória no Docker:
- A imagem define
OMNIROUTE_MEMORY_MB=1024e derivaNODE_OPTIONS=--max-old-space-size=1024a partir dela. - O processo real do servidor é iniciado pelo inicializador standalone, que lê
OMNIROUTE_MEMORY_MBe acrescenta--max-old-space-size=<OMNIROUTE_MEMORY_MB>. - O Node usa o último valor repetido de
--max-old-space-size, portanto, definirOMNIROUTE_MEMORY_MBcontrola o limite efetivo de heap no Docker. - Como a imagem sempre define essa variável, o fallback do próprio inicializador, calibrado com base na RAM, nunca é aplicado no Docker. Aumente-a explicitamente de acordo com a carga de trabalho (tabela abaixo).
2048ainda é insuficiente para/v1/responsesde agentes de programação.
RAM de execução para agentes de programação
Seção intitulada “RAM de execução para agentes de programação”O padrão de 1 GiB do Docker é um mínimo para o dashboard e chats leves, não uma configuração para produção. Corpos longos de POST /v1/responses (centenas de mensagens, dezenas de ferramentas) mantêm vários grafos na memória durante a compactação. Duas solicitações sobrepostas de aproximadamente 3 MiB / 750 mil tokens fizeram o V8 abortar com um old-space de 12 GiB (FATAL ERROR: Reached heap limit) e também atingiram o OOM de um cgroup de 16 GiB. Consulte #7849.
Dimensione o --memory do cgroup acima do heap — buffers nativos, SQLite e dados intermediários de compactação ficam fora do V8.
| Carga de trabalho | OMNIROUTE_MEMORY_MB |
Contêiner / cgroup | Observações |
|---|---|---|---|
| Dashboard, um chat leve | 1024 (padrão da imagem) |
≥2 GiB | |
| Um agente de programação (Claude/Codex/Grok) | 8192 |
≥10 GiB | Uma única sessão típica de /v1/responses |
Duas /v1/responses longas simultâneas |
10240–12288 |
≥12–16 GiB | Abortamento do V8 medido com heap de aproximadamente 12 GiB |
| Três ou mais contextos longos simultâneos | não use em um único processo | serializar / mais RAM | O limite padrão de admissões pesadas é 1 em execução; aumentá-lo sem RAM reintroduz o abortamento |
Em bare metal, omniroute serve calibra aproximadamente 35% da RAM (limitado ao intervalo [512, 4096]) quando OMNIROUTE_MEMORY_MB não está definida. O Docker sempre define 1024, portanto essa calibração nunca é executada na imagem oficial.
docker run -d --name omniroute --restart unless-stopped --stop-timeout 40 \ -e OMNIROUTE_MEMORY_MB=8192 --memory=10g \ -p 127.0.0.1:20128:20128 -v omniroute-data:/app/data diegosouzapw/omniroute:latestVariáveis de Ambiente Críticas
Seção intitulada “Variáveis de Ambiente Críticas”Além dos padrões documentados em ENVIRONMENT.md, as seguintes variáveis são as mais importantes ao executar com Docker:
| Variável | Finalidade | Padrão |
|---|---|---|
OMNIROUTE_WS_BRIDGE_SECRET |
Segredo compartilhado para a ponte WebSocket. Obrigatório em produção — defina uma string aleatória forte. | não definido (deve ser fornecido) |
REDIS_URL |
String de conexão para o backend de limitação de taxa/cache | redis://redis:6379 |
REDIS_PORT |
Porta do host para o contêiner Redis incluído | 6379 |
REDIS_BIND_HOST |
Interface do host na qual a porta do Redis incluído é publicada (loopback, a menos que você adicione AUTH) | 127.0.0.1 |
AUTO_UPDATE_HOST_REPO_DIR |
Caminho do host montado no perfil cli em /workspace/omniroute para fluxos de trabalho de atualização automática |
. (diretório atual) |
OMNIROUTE_MEMORY_MB |
Limite de heap do Node em tempo de execução para o servidor autônomo do Docker; substitui o padrão da imagem indicado acima. Agentes de programação: 8192+ (consulte RAM em tempo de execução). |
1024 |
DASHBOARD_PORT / API_PORT |
Substitui as portas expostas do painel (20128) e da API (20129) | 20128 / 20129 |
APP_BIND_HOST |
Interface do host na qual o docker-compose publica as portas do painel, da API e do WS em tempo real. Com REQUIRE_API_KEY=false (o padrão), 0.0.0.0 expõe o proxy /v1 anônimo à LAN — amplie o acesso somente com REQUIRE_API_KEY=true ou um proxy reverso à frente. |
127.0.0.1 |
CLIPROXY_BIND_HOST |
Interface do host na qual o docker-compose publica o sidecar cliproxyapi — seu volume de dados armazena as credenciais dos provedores. |
127.0.0.1 |
OMNIROUTE_PLUGINS_DIR |
Diretório que o scanner de plugins do runtime lê e no qual instala. Defina-o quando os plugins forem montados por bind mount: o padrão segue HOME, que uma imagem não necessariamente exporta. |
~/.omniroute/plugins |
OMNIROUTE_BASE_PATH |
Subcaminho da URL quando o aplicativo é publicado por trás de um proxy reverso (por exemplo, /omniroute) |
(vazio = raiz) |
NEXT_PUBLIC_BASE_URL |
Origem pública do navegador incluindo o subcaminho (por exemplo, https://host/omniroute) |
não definido |
PROD_DASHBOARD_PORT |
Porta do painel no host para docker-compose.prod.yml |
20130 |
CLIPROXYAPI_PORT |
Porta do host para o sidecar cliproxyapi |
8317 |
Proxy reverso em um subcaminho (Traefik / nginx)
Seção intitulada “Proxy reverso em um subcaminho (Traefik / nginx)”O basePath do Next.js é compilado no bundle standalone. O OmniRoute registra o valor
incorporado em um arquivo sentinela na raiz do aplicativo (gravado durante npm run build;
lido por scripts/docker/ensure-docker-base-path.mjs) e o compara com
OMNIROUTE_BASE_PATH quando o contêiner é iniciado. Quando eles são diferentes e a imagem
foi criada para a raiz do domínio, o entrypoint reescreve os manifestos standalone, os
literais basePath/assetPrefix incorporados (o Next 16 renderiza URLs de assets SSR
apenas a partir de assetPrefix — o patcher replica o subcaminho nele), as URLs de assets
/_next/static incorporadas (manifestos de referência do cliente, importações de mídia,
páginas de erro pré-renderizadas) e o shim de process.env do cliente antes da execução de
node dev/run-standalone.mjs.
Build com Compose (recomendado)
Seção intitulada “Build com Compose (recomendado)”Defina ambas as variáveis em .env e, em seguida, refaça o build para que a imagem e o
ambiente de execução estejam de acordo:
OMNIROUTE_BASE_PATH=/omnirouteNEXT_PUBLIC_BASE_URL=https://myhostname.example.com/omniroutedocker compose --profile base up -d --builddocker-compose.yml encaminha OMNIROUTE_BASE_PATH como argumento de build do Docker e
como variável de ambiente em tempo de execução.
Imagem raiz pré-compilada + subcaminho em tempo de execução
Seção intitulada “Imagem raiz pré-compilada + subcaminho em tempo de execução”As imagens publicadas diegosouzapw/omniroute:* são compiladas para a raiz do domínio.
Ainda é possível definir OMNIROUTE_BASE_PATH em tempo de execução; o contêiner aplica
o patch ao bundle uma vez durante a inicialização. Use-o com a origem pública
correspondente:
services: omniroute: image: diegosouzapw/omniroute:latest environment: OMNIROUTE_BASE_PATH: /omniroute NEXT_PUBLIC_BASE_URL: https://myhostname.example.com/omnirouteConfigure o proxy reverso para encaminhar o caminho externo completo (não remova o
prefixo). O Traefik deve rotear PathPrefix(/omniroute) para o contêiner sem
StripPrefix, para que o Next.js receba /omniroute/... e forneça assets a partir de
/omniroute/_next/....
O healthcheck do Docker consulta o endpoint leve de ciclo de vida /healthz, prefixado
com o OMNIROUTE_BASE_PATH ativo. /api/monitoring/health continua disponível para
diagnósticos feitos por pessoas ou dashboards; para fazer o HEALTHCHECK do contêiner
voltar a usá-lo (por exemplo, para uma verificação aprofundada de integridade), defina
OMNIROUTE_HEALTHCHECK_PATH=/api/monitoring/health. Esse caminho executa uma verificação
aprofundada (banco de dados + resumo do monitoramento) — apropriada para o
HEALTHCHECK pouco frequente do Docker, caso você opte por reativá-la, mas não para
intervalos de livenessProbe do Kubernetes.
Para orquestradores (Kubernetes, Nomad etc.):
| Sonda | Prefira | Evite |
|---|---|---|
| Vivacidade | HTTP GET /livez ou TCP na porta principal (PORT, padrão 20128) |
/api/monitoring/health como verificação de vivacidade |
| Prontidão | HTTP GET /healthz |
Timeouts curtos que tratem um event loop ocupado como inativo |
| Aprofundada / blackbox | /api/monitoring/health |
— |
/healthz informa o ciclo de vida do processo (ok / starting / stopping). /livez
verifica apenas se o processo está ativo (200 sempre que o handler puder ser executado;
ele não aguarda a prontidão). Ambos ainda são executados no mesmo event loop do Node
usado para processar requisições, portanto, trabalhos de catálogo ou compactação que
consomem muita CPU podem atrasá-los — ocupado ≠ inativo. Prefira a verificação de
vivacidade via TCP se as sondas HTTP atingirem o timeout. Orientações completas sobre
sondas:
Guia de monitoramento — recomendações de sondas do Kubernetes.
Docker Compose com Caddy (HTTPS Auto-TLS)
Seção intitulada “Docker Compose com Caddy (HTTPS Auto-TLS)”O OmniRoute pode ser exposto com segurança usando o provisionamento automático de SSL do Caddy. Certifique-se de que o registro A de DNS do seu domínio aponte para o IP do seu servidor.
services: omniroute: image: diegosouzapw/omniroute:latest container_name: omniroute restart: unless-stopped volumes: - omniroute-data:/app/data environment: - PORT=20128 # Origem voltada ao navegador para callbacks OAuth, links do painel e URLs públicas geradas. - NEXT_PUBLIC_BASE_URL=https://your-domain.com # URL interna de servidor para servidor para tarefas agendadas / autorrequisições. - BASE_URL=http://omniroute:20128 - AUTH_COOKIE_SECURE=true
caddy: image: caddy:latest container_name: caddy restart: unless-stopped ports: - "80:80" - "443:443" command: caddy reverse-proxy --from https://your-domain.com --to http://omniroute:20128
volumes: omniroute-data:O Caddy define os cabeçalhos de encaminhamento padrão para o contêiner upstream. O OmniRoute usa
NEXT_PUBLIC_BASE_URL como a origem pública canônica para callbacks OAuth e links públicos
gerados; as gravações autenticadas do painel usam requisições da mesma origem juntamente com proteção CSRF
vinculada à sessão. Habilite OMNIROUTE_TRUST_PROXY apenas em implantações avançadas nas quais você deseja intencionalmente
que o OmniRoute derive a origem pública de cabeçalhos encaminhados confiáveis em vez de uma configuração
explícita.
Cloudflare Quick Tunnel
Seção intitulada “Cloudflare Quick Tunnel”O suporte do painel para implantações com Docker inclui um Cloudflare Quick Tunnel de um clique em Dashboard → Endpoints. Na primeira ativação, o cloudflared é baixado somente quando necessário, um túnel temporário é iniciado para o endpoint /v1 atual e a URL https://*.trycloudflare.com/v1 gerada é exibida diretamente abaixo da sua URL pública normal.
Os painéis de túneis de endpoint (Cloudflare, Tailscale, ngrok) podem ser exibidos ou ocultados em Settings → Appearance sem alterar o estado do túnel ativo.
Observações sobre túneis
Seção intitulada “Observações sobre túneis”- As URLs do Quick Tunnel são temporárias e mudam após cada reinicialização.
- Os Quick Tunnels não são restaurados automaticamente após a reinicialização do OmniRoute ou do contêiner. Reative-os no painel quando necessário.
- Atualmente, a instalação gerenciada é compatível com Linux, macOS e Windows em
x64/arm64. - Por padrão, os Quick Tunnels gerenciados usam transporte HTTP/2 para evitar avisos ruidosos sobre o buffer UDP do QUIC em ambientes de contêiner com recursos limitados. Defina
CLOUDFLARED_PROTOCOL=quicouautocaso queira usar outro transporte. - As imagens Docker incluem raízes de CA do sistema e as fornecem ao
cloudflaredgerenciado, o que evita falhas de confiança TLS quando o túnel é inicializado dentro do contêiner. - Defina
CLOUDFLARED_BIN=/absolute/path/to/cloudflaredcaso queira que o OmniRoute use um binário existente em vez de baixar um.
Tags de imagem
Seção intitulada “Tags de imagem”| Imagem | Tag | Tamanho | Descrição |
|---|---|---|---|
diegosouzapw/omniroute |
latest |
~250MB | Maior SemVer estável publicada (não o main do git) |
diegosouzapw/omniroute |
3.8.0 |
~250MB | Fixe essa classe de tag para GitOps |
Manifesto multiplataforma: linux/amd64 + linux/arm64 nativos (Apple Silicon, AWS Graviton, Raspberry Pi). O Docker seleciona automaticamente a arquitetura correspondente; use --platform linux/amd64 caso precise forçar a emulação de AMD64 em hosts ARM.
Canais de lançamento
Seção intitulada “Canais de lançamento”O OmniRoute publica canais Docker separados para versões estáveis, testes da branch de lançamento ativa e builds de desenvolvimento.
| Canal | Origem | Mutabilidade | Uso recomendado |
|---|---|---|---|
:<version> / :<version>-web |
Versão assinada/versionada | Imutável | Implantações em produção que fixam uma versão exata |
:latest / :latest-web |
Maior SemVer estável publicada | Ponteiro estável mutável | Acompanha versões estáveis após um job de publicação SemVer — não acompanha main nem commits não lançados de release/v* |
:next / :next-web |
Branch release/v* padrão atual |
Ponteiro de pré-lançamento mutável | Testes de correções que chegaram à branch de lançamento ativa, mas que ainda não estão em uma versão estável |
:main / :main-web |
Branch main |
Ponteiro de desenvolvimento mutável | Apenas para testes de desenvolvimento e integração |
Provedores de sessão web: as imagens -web
Seção intitulada “Provedores de sessão web: as imagens -web”Cada canal acima também está disponível como uma tag -web (:latest-web, :<version>-web, :next-web, :main-web), criada a partir do estágio runner-web — a mesma imagem, acrescida do Playwright e de um navegador Chromium. A imagem comum é fornecida sem o Chromium; gemini-web, claude-web e claude-turnstile precisam dele.
A falha é adiada, não ocorre na inicialização: esses provedores listam seus modelos e aparecem como conectados no painel, e somente a primeira solicitação falha com
[500]: Failed to load external module playwright: Error: Cannot find module'/app/node_modules/playwright/node_modules/playwright-core/browsers.json'Se você usa esses provedores, baixe a tag -web do canal que já está usando — nada mais muda. Em uma instalação via npm/CLI (sem imagem Docker), o componente equivalente ausente é o binário do navegador: execute npx playwright install chromium no host.
Como usar o canal de pré-lançamento
Seção intitulada “Como usar o canal de pré-lançamento”O canal next é recriado a cada push para a branch release/v* padrão atual e é publicado tanto para AMD64 quanto para ARM64. Branches de manutenção mais antigas não podem sobrescrevê-lo. O canal fornece uma imagem que pode ser baixada contendo correções que foram mescladas à branch de lançamento ativa antes da criação da próxima tag estável.
docker pull diegosouzapw/omniroute:nextdocker pull diegosouzapw/omniroute:next-webPara o Docker Compose, substitua a tag da imagem usada pelo perfil selecionado e, em seguida, baixe e recrie o serviço:
services: omniroute: image: diegosouzapw/omniroute:nextdocker compose pulldocker compose up -dSegurança e reversão
Seção intitulada “Segurança e reversão”next é um canal de pré-lançamento flutuante. Ele pode mudar a cada push para a branch de lançamento ativa e não tem suporte para uso em produção. Fixe o digest da imagem ao avaliar um build específico:
docker pull diegosouzapw/omniroute:nextdocker image inspect diegosouzapw/omniroute:next --format '{{index .RepoDigests 0}}'Antes de testar, faça backup do volume de dados do OmniRoute ou do diretório de dados montado via bind. Para reverter, restaure a versão estável ou o digest usado anteriormente e recrie o contêiner:
docker pull diegosouzapw/omniroute:<stable-version>docker compose up -dUm build da branch de lançamento nunca pode mover latest; apenas uma versão semântica estável elegível pode promover o ponteiro estável. As imagens next mantêm a inspeção da imagem de lançamento e o bloqueio por vulnerabilidades CRITICAL.
latest não garante que o conteúdo esteja atualizado em relação ao git. Correções mescladas em main ou na branch release/v* ativa não estarão em :latest até que uma imagem SemVer estável seja publicada e o job de publicação promova :latest (com o mesmo digest dessa SemVer). Se latest parecer congelada enquanto o GitHub já mostra a correção, baixe :next para testar a branch de lançamento ou aguarde a tag SemVer.
| O que você quer | Use |
|---|---|
| GitOps / produção que não pode sofrer alterações | Fixe :X.Y.Z (ou o digest da imagem) |
| Acompanhar versões estáveis publicadas e aceitar uma recriação a cada versão | :latest |
Testar commits não lançados de release/v* |
:next (não para produção) |
Testar main |
:main (não para produção) |
Disponibilidade: o SQLite padrão tem uma única réplica
Seção intitulada “Disponibilidade: o SQLite padrão tem uma única réplica”A implantação padrão do OmniRoute em Docker / Kubernetes consiste em um processo Node + um gravador SQLite. Alta disponibilidade não é suportada nessa topologia.
| Restrição | Consequência |
|---|---|
| Gravador único | Não execute várias réplicas usando o mesmo arquivo SQLite. Isso corrompe o banco de dados. |
| Recriação / reinicialização / encerramento pelo HEALTHCHECK | Indisponibilidade total de conexões SSE em andamento, sessões do painel e estado em memória. Todos os clientes conectados são desconectados. Novas solicitações durante o período sem endpoints recebem do proxy reverso 502 Bad Gateway: Unknown error, e não um JSON do OmniRoute — os clientes não conseguem diferenciar isso de uma falha do provedor (#11015). |
Mesmo loop de eventos que /healthz |
Um ciclo intenso de catálogo ou compactação pode atrasar as sondagens; um timeout curto reinicia então a única réplica. |
Matriz de sondagens (consulte também recomendações de sondagens do Kubernetes):
| Sondagem | Destino | Não use |
|---|---|---|
| Atividade | TCP em PORT (padrão 20128) ou HTTP flexível em /healthz |
/api/monitoring/health |
| Prontidão | HTTP GET /healthz |
Timeouts curtos que tratam um loop de eventos ocupado como inativo |
| Profunda / humanos | /api/monitoring/health |
Sondagem de atividade automatizada do kubelet |
Atualizações: espere que todas as sessões sejam desconectadas. Drene os clientes se puder; não há atualização contínua com o SQLite padrão. O restart: unless-stopped do Compose combinado com o HEALTHCHECK do Docker também substituirá o único processo quando o contêiner estiver não saudável — com o mesmo raio de impacto.
Trecho do Kubernetes para uma única réplica (Recreate é obrigatório; não aumente replicas usando um único arquivo SQLite):
spec: replicas: 1 strategy: type: Recreate template: spec: terminationGracePeriodSeconds: 90 containers: - name: omniroute lifecycle: preStop: exec: command: ["/bin/sleep", "15"] readinessProbe: httpGet: path: /healthz port: 20128 periodSeconds: 5 livenessProbe: tcpSocket: port: 20128 periodSeconds: 20A espera de preStop permite que o kube remova os endpoints do Service antes do SIGTERM, para que o tráfego novo deixe de atingir o processo que está sendo encerrado. O SSE de /v1/responses em andamento é drenado por até SHUTDOWN_TIMEOUT_MS (30s por padrão) por meio de leases de admissão de alto custo (#11015). Novas solicitações que ainda chegam ao processo recebem 503 + Retry-After: 5. O intervalo do Recreate sem endpoints até que a substituição esteja pronta continua sendo uma indisponibilidade total — isso é consequência da topologia SQLite, não de uma configuração incorreta das sondagens.
Postgres externo / HA com vários gravadores não é um caminho padrão documentado. Se você precisar de HA, mantenha uma única réplica ou execute uma topologia que o projeto tenha testado e documentado separadamente. O trabalho relacionado a Postgres/MySQL está em #8075. Até que isso seja disponibilizado, a única maneira suportada de multiplicar a capacidade de /v1/responses grandes é usar N processos independentes (próxima seção), e não replicas > 1 em um único volume.
Escala horizontal: N processos independentes
Seção intitulada “Escala horizontal: N processos independentes”Um processo Node corresponde a um heap V8. Duas solicitações simultâneas de agente de codificação POST /v1/responses (RTK + Caveman), cada uma com ~3 MiB / ~750 mil tokens, fazem esse heap abortar em ~12 Gi (FATAL ERROR: Reached heap limit) e podem causar OOM em um cgroup de 16 Gi. Consulte #7849. Essa medição é um alerta de orçamento de memória, não um limite máximo do produto de duas solicitações longas /v1/responses simultâneas. A admissão de chats pesados é controlada por um orçamento de bytes de entrada derivado automaticamente (OMNIROUTE_CHAT_MAX_INFLIGHT_BYTES, src/shared/middleware/admissionBudget.ts), dimensionado a partir desse mesmo limite do V8/cgroup — aumentá-lo manualmente (ou definir o limite legado por contagem de solicitações OMNIROUTE_CHAT_MAX_HEAVY_IN_FLIGHT) em um processo já dimensionado reintroduz o aborto. Chats pequenos, /healthz, /v1/models e MCP não estão incluídos nesse limite.
Um processo: mais de duas solicitações longas /v1/responses
Seção intitulada “Um processo: mais de duas solicitações longas /v1/responses”Um processo saudável (heap abaixo de OMNIROUTE_CHAT_ADMISSION_HEAP_SHED_RATIO, padrão 0.75) pode executar mais de duas solicitações longas POST /v1/responses simultâneas quando ainda houver espaço no orçamento de bytes em trânsito de todo o processo (OMNIROUTE_CHAT_MAX_INFLIGHT_BYTES / #10110). Corpos com tamanho igual ou superior a OMNIROUTE_CHAT_LARGE_BODY_BYTES (padrão de 256 KiB) adquirem a mesma concessão de recursos pesados que solicitações com estruturas complexas e usam o mesmo escape tryAcquireHealthyHeadroom de #10437 (OMNIROUTE_CHAT_ADMISSION_HEALTHY_HEADROOM). Dezenas de clientes SSE longos simultâneos (os operadores frequentemente precisam de 40–50) são uma questão de orçamento de memória — dimensione o heap + slots primários/de margem saudável + OMNIROUTE_CHAT_MAX_INFLIGHT_BYTES — e não um limite rígido do produto de “no máximo 2”. Um heap sob pressão ainda rejeita solicitações com um erro 503 que permite nova tentativa, evitando a recorrência de #7849.
Para multiplicar os heaps (old-spaces V8 independentes) hoje:
| Faça | Não faça |
|---|---|
Execute N contêineres/pods, cada um com seu próprio DATA_DIR / volume |
Defina replicas > 1 apontando para um único arquivo SQLite |
| Dimensione as solicitações pesadas em trânsito + a margem saudável com base no heap / orçamento de bytes em trânsito; 1–2 é o padrão conservador de #7849, não um limite rígido do produto | Forneça 8× mais RAM a um processo e um limite de contagem irrestrito |
Opcional: QUOTA_STORE_DRIVER=redis + QUOTA_STORE_REDIS_URL para contadores de cota compartilhados |
Trate o Redis como SQLite compartilhado — ele não é isso |
| Duplique os segredos dos provedores em cada instância (ou aceite painéis particionados) | Espere um único painel / registro de chamadas entre as instâncias |
| Use qualquer balanceador de carga na frente; afinidade por chave de API ou sessão é suficiente | Exija um middleware específico de fornecedor sensível ao tamanho |
Hardware: as solicitações longas /v1/responses simultâneas por instância são uma questão de orçamento de memória (heap + bytes em trânsito / #10110). N DATA_DIRs independentes ainda multiplicam os heaps: a RAM do host deve comportar N × cgroup, e não “um pod de 16 Gi com N=8”. Nunca use replicas > 1 com um único arquivo SQLite.
Exemplo de Compose (dois heaps, dois volumes — não deploy.replicas: 2):
services: omniroute-a: image: diegosouzapw/omniroute:3.8.49 environment: DATA_DIR: /app/data OMNIROUTE_MEMORY_MB: "12288" QUOTA_STORE_DRIVER: redis QUOTA_STORE_REDIS_URL: redis://redis:6379 volumes: [omniroute-a-data:/app/data] ports: ["20128:20128"] omniroute-b: image: diegosouzapw/omniroute:3.8.49 environment: DATA_DIR: /app/data OMNIROUTE_MEMORY_MB: "12288" QUOTA_STORE_DRIVER: redis QUOTA_STORE_REDIS_URL: redis://redis:6379 volumes: [omniroute-b-data:/app/data] ports: ["20138:20128"]volumes: omniroute-a-data: omniroute-b-data:A densidade dentro do processo (compressão fora do isolate HTTP) está em #11023. Um cluster lógico em estado durável compartilhado está em #8075.
Observações Importantes
Seção intitulada “Observações Importantes”- Modo WAL do SQLite: Deve-se permitir que
docker stopseja concluído para que o OmniRoute possa realizar o checkpoint das alterações mais recentes de volta parastorage.sqlite. Os arquivos do Compose incluídos já definem um período de tolerância de 40s para a parada. Se você executar a imagem diretamente, mantenha--stop-timeout 40. DISABLE_SQLITE_AUTO_BACKUP: Defina comotruese os backups rotineiros/antes de gravações forem gerenciados externamente. As migrações de bancos de dados existentes ainda exigem um snapshot de segurança durável próprio e uma proteção contra migrações em massa.- Persistência de Dados: Sempre monte um volume em
/app/datapara manter seu banco de dados, suas chaves e configurações entre reinicializações do contêiner. - Configuração de Porta: Sobrescreva a variável de ambiente
PORTpara alterar a porta padrão20128.
Veja Também
Seção intitulada “Veja Também”- Guia de Implantação em VM — Configuração de VM + nginx + Cloudflare
- Guia de Implantação no Fly.io — Implante no Fly.io
- Configuração de Ambiente — Referência completa do
.env
HagiCode
HagiCode é um ambiente de programação com agentes, fluxos estruturados, execução multiagente e visualizações Hero Dungeon.
Transforme ideias em software útil com um fluxo de trabalho com agentes mais inteligente, rápido e agradável.

- SmartFluxos estruturados transformam intenções em um caminho executável da ideia à entrega.
- EfficientFluxos multiagente mantêm pesquisa, implementação e revisão em andamento simultaneamente.
- FunO Hero Dungeon torna longas sessões de programação mais visuais e colaborativas.