`runner add`

Registra uma nova app no runner. Faz clone shallow do repo, lê .deploy.yml (ou gera via wizard), encripta secrets/ckey/token no state file, e opcionalmente deploya.

Sintaxe

runner add --repo <USER>/<repo> [flags]

Flags

Flag Tipo Descrição
--repo string Repo GitHub no formato user/repo. Dispensável com --image, ou com --manifest-file em app de source de arquivo
--image string (v2.173.0+) App sem repositório que implanta imagem de registry: o repositório da imagem, sem tag (ex.: ghcr.io/org/api), igual ao image: do manifesto. Exige --manifest-file ou --manifest-stdin e dispensa --repo/--branch. Ver Deploy por imagem de registry
--branch string Branch do source. Com --repo, é obrigatório: sem ela o runner sai com branch_required (desde a v2.173.0; antes era erro do clap, exit 2)
--token string GitHub token (ghp_*); se omitido, usa fallback ou interativo
--token-from <app> string Reusa token encriptado de outro app já registrado. Desde a v2.152.0, token com escopo amplo herdado assim não é barrado: o token já está neste servidor. Os escopos sensíveis são listados e a herança fica no audit log (--token-from:token-amplo-herdado). --token com token novo de escopo amplo continua exigindo --allow-broad-token
--ckey string Content key (encripta secrets). Sem valor = default v2 (assimétrica, desde a v2.124.0); a/asym/assimetric/2 (ou v2) = o mesmo explícito; s/sym/symetric/1 (ou c, v1) = simétrica gerada; qualquer outro texto = ckey literal simétrica. Ver escolha do esquema
--ckey-show flag Imprime ckey plaintext no add (default: só fingerprint)
--trigger <origem> string (v2.188.0+) Origem gravada na tentativa de registro: cli (default), api… O CCS passa api
--actor <nome> string (v2.188.0+) Ator humano gravado na tentativa de registro
--discard-remote-bundle flag (2.142.0+) O repo já tem um bundle desta instância cifrado com outra ckey (registro anterior): regrava-o com a ckey deste registro (ou o remove, se a app não tem envs; o primeiro deploy grava o novo). Sem a flag o registro é recusado com bundle_de_outra_ckey e nada fica registrado — passe a ckey original para recuperar os secrets. Os valores do bundle antigo só voltam com a ckey antiga. O adopt faz o descarte sempre

Qual ckey usar

Prefira a assimétrica:

runner add --repo usuario/meu-app --branch main --ckey v2 --instance production

No modo assimétrico a chave privada fica no servidor e a pública vai no repo. Consequência prática: escrever um secret deixa de dar o poder de ler os outros — uma automação ou o front adicionam valores tendo só o recipient público. E como o bundle guarda os nomes legíveis com os valores selados um a um, dá para revisar num diff de PR o que entrou ou saiu sem expor conteúdo.

Forma Esquema
--ckey v2 Assimétrica (par X25519)
--ckey v1 Simétrica, valor gerado
--ckey sem valor Default — v2 (assimétrica) desde a v2.124.0; antes era v1
--ckey "minha-chave" Simétrica, ckey literal

O default sem valor ainda é o simétrico, e isso muda numa versão futura. Peça v2 explicitamente em vez de contar com o default.

Fique na simétrica só quando precisar fixar uma chave para uso externo — um processo fora do Runner abre o bundle, ou várias apps compartilham a mesma ckey. No modo assimétrico a privada é do servidor por construção e não sai dele.

Já registrou como simétrica? `runner secrets migrate` faz a transição, sempre explícita, com backup e validação antes de publicar. | --instance | string | Instância que o registro deploya. Grava state.instance — a fonte de prioridade 1 na resolução de instância de deploy/deploy --all/fetch --deploy (v2.55.1+). Sem ela, o deploy cai no default do manifesto. Ver Qual instância é deployada | | --deploy | flag | Deploya imediatamente após add | | --force-duplicate | flag | (v2.21.0+) Permite registrar segunda app pro mesmo repo | | --manifest-path <path> | string | (v2.23.13+) Path do .deploy.yml em subdir (monorepo) | | --from-compose <path> | string | (v2.32.0+) Bulk-registra N apps de um docker-compose.yml. Conflita com --manifest-path/--pr | | --skip-dns-check | flag | (v2.32.0+) Pula o advisory de DNS no add (CI / quando DNS ainda está sendo configurado) | | --skip-health | flag | (v2.54.0+) Com --deploy: pula a validação de saúde só no primeiro deploy (equivale a healthcheck: mode: skip_check sem tocar no manifesto). Use quando o container sobe mas ainda não há Traefik/healthcheck válido no server; redeploy futuro revalida sem reinstalar. Veja `runner deploy` | | --insecure | flag | Bypass de pre-flight checks (não recomendado) |

Detecção de duplicate (v2.21.0+)

Desde v2.21.0, runner detecta quando você tenta registrar um repo que já está em uso por outra app:

$ runner add --repo usuario/meu-app --branch main --ckey "..." --instance production
ERROR duplicate_repo: Repo usuario/meu-app já está registrado como `meu-app-old`
       (branch: dev, status: registered).

       Opções:
         --force-duplicate            permite criar SEGUNDA app pro mesmo repo
         runner unregister meu-app-old --force    remove a anterior

Quando usar --force-duplicate:

  • Testes A/B com versões paralelas do mesmo repo
  • Multi-instance experimental (raro)
  • Deploys de branches diferentes do mesmo repo como apps separadas

Quando NÃO usar:

  • Você esqueceu o nome da app antiga → runner list mostra todas
  • Quer trocar a config da app existente → runner unregister + re-add OU runner edit

Bulk add com `--from-compose` (v2.32.0+)

Para monorepos com docker-compose.yml que descrevem várias apps, registre todas num único comando. O runner:

  1. Clona o repo
  2. Parseia o compose pra descobrir services
  3. Separa em WizardizableApp (apps) vs Infrastructure (redis, postgres — silenciosamente puladas)
  4. Exige cada wizardizable service ter manifest em <service>/.deploy.yml (gere antes com runner wizard --from-compose)
  5. Esquema v2 (assimétrica) com UMA identity para o bundle inteiro (v2.130.0+; antes: ckey simétrica gerada e compartilhada). --ckey <literal> ou --ckey v1 mantêm a simétrica compartilhada. Em ambos os casos é uma unidade de custódia: runner ckeys export <qualquer-app> recupera o bundle todo
  6. Loop runner add por service com --force-duplicate implícito a partir do segundo
# 1. Gera os manifests
runner wizard --from-compose docker-compose.yml \
  --repo usuario/meu-monorepo --branch main

# 2. Commita e empurra
cd meu-monorepo && git add . && git commit -m "add manifests" && git push

# 3. Bulk registra
runner add --repo usuario/meu-monorepo --branch main \
  --from-compose docker-compose.yml

Resultado típico:

INFO [from-compose] docker-compose.yml → registering 2 app(s): api, web
INFO [from-compose] skipped infrastructure services: redis
[from-compose] generated shared ckey for 2 services (fingerprint: ck_xxxx…yyyy)
[ADD] meu-api/api registered at /data/apps/meu-api
[ADD] meu-web/web registered at /data/apps/meu-web

Confirme o ckey shared:

$ runner ckeys list
ck_xxxx…yyyy | meu-api | ... | shared_with: meu-web
ck_xxxx…yyyy | meu-web | ... | shared_with: meu-api

Erros úteis do `--from-compose`

  • compose_not_found — path do compose não existe no repo
  • missing_service_manifests: api — service no compose sem <service>/.deploy.yml. Rode runner wizard --from-compose primeiro
  • no_wizardizable_services — compose só tem infrastructure (redis/postgres etc.). Nada a registrar

Advisories não-fatais (v2.32.0+)

Após semantic_validate_or_fail, antes de tocar /data/apps/, o runner emite WARN não-fatal pra duas categorias:

DNS check

Resolve cada instance.domain declarado. Detecta IP público do servidor via ipify/ifconfig.me (timeout 2s). Comportamento:

Estado Output
Resolve para o IP do servidor silent
Resolve para outro IP WARN: "resolves to X but this server's public IP is Y"
Não resolve (NXDOMAIN) WARN: "not resolved yet. Propagação 5-15min"
Test domain (.invalid, .test, .local, IP literal, wildcard) silent

Bypass: --skip-dns-check (CI / quando DNS está sendo configurado em paralelo).

Monorepo build.context

Se o repo tem marker no root (pnpm-workspace.yaml, turbo.json, lerna.json, nx.json, rush.json) E build.context canonicalizado != root → WARN apontando pro fix:

WARN Monorepo detected (pnpm-workspace.yaml at repo root), but
build.context resolves to /tmp/.../apps/api. Your Dockerfile likely
depends on root-level files (pnpm-lock.yaml, packages/*, etc.) and
`docker build` may fail with COPY errors. Consider setting
`build.context: ../..` when the manifest is at apps/<svc>/.deploy.yml.

Sem bypass — é advisory. Operadores com single-package em monorepo podem ignorar.

Detecção de duplicate (v2.21.0+)

Desde v2.21.0, runner detecta quando você tenta registrar um repo que já está em uso por outra app:

$ runner add --repo usuario/meu-app --branch main --ckey "..." --instance production
ERROR duplicate_repo: Repo usuario/meu-app já está registrado como `meu-app-old`
       (branch: dev, status: registered).

       Opções:
         --manifest-path <path>       registra segunda app do mesmo repo apontando pra outro .deploy.yml (monorepo)
         --force-duplicate            permite duplicação sem manifest-path (A/B testing, multi-instance experimental)
         runner unregister meu-app-old --force    remove a anterior

Quando usar --manifest-path:

  • Monorepo com <service>/.deploy.yml (caso comum em v2.32.0+)

Quando usar --force-duplicate:

  • Testes A/B com versões paralelas do mesmo repo
  • Multi-instance experimental (raro)

Quando NÃO usar:

  • Você esqueceu o nome da app antiga → runner list mostra todas
  • Quer trocar a config da app existente → runner unregister + re-add OU runner edit

Exemplos

# Add básico
runner add --repo usuario/meu-app --branch main --ckey --instance production

# Add com deploy automático
runner add --repo usuario/meu-app --branch main --ckey --instance production --deploy

# Reusa token de app já registrada
runner add --repo usuario/outro-app --branch main --token-from meu-app --ckey

# Monorepo (manifest em subdir)
runner add --repo usuario/meu-monorepo --branch main \
  --manifest-path apps/api/.deploy.yml --ckey

# Bulk de monorepo (v2.32.0+)
runner add --repo usuario/meu-monorepo --branch main \
  --from-compose docker-compose.yml

# Multi-instance experimental
runner add --repo usuario/meu-app --branch main-experimental --ckey \
  --instance staging --force-duplicate

# CI / DNS ainda sendo configurado
runner add --repo usuario/meu-app --branch main --ckey \
  --skip-dns-check

Veja Também

By Borlot.com.br on 03/06/2026