`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 productionNo 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
v2explicitamente 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 anteriorQuando 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 listmostra todas - Quer trocar a config da app existente →
runner unregister+ re-add OUrunner 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:
- Clona o repo
- Parseia o compose pra descobrir services
- Separa em
WizardizableApp(apps) vsInfrastructure(redis, postgres — silenciosamente puladas) - Exige cada wizardizable service ter manifest em
<service>/.deploy.yml(gere antes comrunner wizard --from-compose) - 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 v1mantêm a simétrica compartilhada. Em ambos os casos é uma unidade de custódia:runner ckeys export <qualquer-app>recupera o bundle todo - Loop
runner addpor service com--force-duplicateimplí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.ymlResultado 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-webConfirme o ckey shared:
$ runner ckeys list
ck_xxxx…yyyy | meu-api | ... | shared_with: meu-web
ck_xxxx…yyyy | meu-web | ... | shared_with: meu-apiErros úteis do `--from-compose`
compose_not_found— path do compose não existe no repomissing_service_manifests: api— service no compose sem<service>/.deploy.yml. Roderunner wizard --from-composeprimeirono_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 anteriorQuando 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 listmostra todas - Quer trocar a config da app existente →
runner unregister+ re-add OUrunner 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-checkVeja Também
- `runner wizard` — gera
.deploy.yml(incluindo bulk pra--from-compose) - `runner unregister` — remove app registrada
- `runner tokens` — gerencia tokens GitHub
- `runner edit` — altera branch/instance da app
- `runner list` — lista apps registradas
- `runner logs registros` — tentativas de registro, inclusive as recusadas