Pular para o conteúdo
OmniRoute source

🐳 Docker Guide — OmniRoute (Português (Brasil))

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.

Janela do terminal
docker run -d \
--name omniroute \
--restart unless-stopped \
--stop-timeout 40 \
-p 20128:20128 \
-v omniroute-data:/app/data \
diegosouzapw/omniroute:latest
Janela do terminal
# Primeiro, copie e edite o arquivo .env
cp .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:latest
Janela do terminal
# 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 CLIProxyAPI
docker compose --profile cli --profile cliproxyapi up -d

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.

Janela do terminal
docker compose --profile base up -d
npm install -g omniroute
omniroute connect http://localhost:20128 # aponte a CLI para o contêiner
omniroute setup-codex # grava o ~/.codex real no host

Essa é 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=true
volumes:
- ~/.codex:/host-home/.codex:rw
- ~/.claude:/host-home/.claude:rw

Um 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 de docker.sock. O perfil cli faz bind mount de /var/run/docker.sock para que o atualizador automático dentro do contêiner possa recriar a stack por meio do daemon do host (src/lib/system/autoUpdate.ts verifica 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:

  1. Nunca exponha a porta do perfil cli à rede. Publique-a em 127.0.0.1 (ports: "127.0.0.1:${DASHBOARD_PORT:-20128}:...") — um perfil cli acessível pela LAN transforma qualquer RCE no nível do painel em comprometimento total do host.
  2. 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êiner cli.

Se não precisar da atualização automática dentro do contêiner, deixe o perfil cli desativado (COMPOSE_PROFILES=core,redis ou 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 e docs/security/SUPPLY_CHAIN.md para consultar a cadeia de proveniência dos binários codex/claude-code/droid/openclaw.

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:6379 por 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, um npm run dev local). Publicá-la em 0.0.0.0 exporia um Redis sem autenticação a todos os hosts da sua LAN. Se você definir REDIS_BIND_HOST=0.0.0.0, adicione também --requirepass ao command: 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:

Janela do terminal
docker compose up -d --scale redis=0

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:

Janela do terminal
# Crie e inicie a stack de produção
docker compose -f docker-compose.prod.yml up -d --build
# Acompanhe os logs em tempo real
docker compose -f docker-compose.prod.yml logs -f
# Encerre a stack (mantendo os volumes)
docker compose -f docker-compose.prod.yml down

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

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:

Janela do terminal
docker build --target runner-base -t omniroute:base .
docker build --target runner-cli -t omniroute:cli .
docker build --target runner-web -t omniroute:web .

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:

Janela do terminal
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

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=1024 e deriva NODE_OPTIONS=--max-old-space-size=1024 a partir dela.
  • O processo real do servidor é iniciado pelo inicializador standalone, que lê OMNIROUTE_MEMORY_MB e acrescenta --max-old-space-size=<OMNIROUTE_MEMORY_MB>.
  • O Node usa o último valor repetido de --max-old-space-size, portanto, definir OMNIROUTE_MEMORY_MB controla 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). 2048 ainda é insuficiente para /v1/responses de 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.

Janela do terminal
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:latest

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

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.

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:

.env
OMNIROUTE_BASE_PATH=/omniroute
NEXT_PUBLIC_BASE_URL=https://myhostname.example.com/omniroute
Janela do terminal
docker compose --profile base up -d --build

docker-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/omniroute

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

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.

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.

  • 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=quic ou auto caso queira usar outro transporte.
  • As imagens Docker incluem raízes de CA do sistema e as fornecem ao cloudflared gerenciado, o que evita falhas de confiança TLS quando o túnel é inicializado dentro do contêiner.
  • Defina CLOUDFLARED_BIN=/absolute/path/to/cloudflared caso queira que o OmniRoute use um binário existente em vez de baixar um.
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.

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
:&lt;version&gt; / :&lt;version&gt;-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

Cada canal acima também está disponível como uma tag -web (:latest-web, :&lt;version&gt;-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.

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.

Janela do terminal
docker pull diegosouzapw/omniroute:next
docker pull diegosouzapw/omniroute:next-web

Para 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:next
Janela do terminal
docker compose pull
docker compose up -d

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:

Janela do terminal
docker pull diegosouzapw/omniroute:next
docker 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:

Janela do terminal
docker pull diegosouzapw/omniroute:&lt;stable-version&gt;
docker compose up -d

Um 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: 20

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

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.

  • Modo WAL do SQLite: Deve-se permitir que docker stop seja concluído para que o OmniRoute possa realizar o checkpoint das alterações mais recentes de volta para storage.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 como true se 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/data para 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 PORT para alterar a porta padrão 20128.

Código-fonte do OmniRoute (a58000c7685f)

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.

Interface principal do HagiCode no tema claro
  • 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.
Acessar HagiCode