Inicio Rapido

Este guia mostra como instalar e configurar o Runner em seu servidor de producao.

Requisitos

Antes de comecar, certifique-se de ter:

  • Linux (Ubuntu 22.04+ ou Debian 12+)
  • Docker 24.0+ instalado e rodando
  • Traefik 3.0+ configurado com dynamic config
  • Acesso SSH ao servidor de producao
  • GitHub CLI (gh) instalado (opcional, para staging de PRs)

Instalacao

1. Instalar o Runner

curl -sL https://runner.ccs.systems/init.sh | sudo bash

Para instalar uma release candidate:

curl -sL https://runner.ccs.systems/init.sh | sudo bash -s -- --rc

O instalador:

  • Detecta a arquitetura (x86_64 ou aarch64)
  • Baixa o binario static musl (zero dependencias)
  • Instala em /opt/runner/runner
  • Cria symlink /usr/local/bin/runner
  • Gera /opt/runner/config.yml automaticamente
  • Cria diretorios: state/, logs/, .keys/

2. Verificar Instalacao

runner version

Para output JSON (integracao com CCS Client):

runner version --json

3. Configurar config.yml

Edite /opt/runner/config.yml:

# Caminhos
apps_path: /data/apps
traefik_dynamic_path: /etc/traefik/dynamic
state_path: /opt/runner/state
logs_path: /opt/runner/logs

# Docker
registry: registry.local
keep_versions: 3

# Traefik
traefik:
  entrypoints:
    - websecure
  cert_resolver: myresolver

# GitHub
github:
  default_user: seu-usuario-github

# Notificacoes (opcional)
notify:
  telegram_bot_token: ""
  telegram_chat_id: ""
  verbose_errors: true

# Staging (opcional)
staging:
  enabled: true
  base_path: /opt/runner/staging
  network: public
  default_ttl_hours: 48
  max_total_instances: 20

Ou use o CLI para gerenciar configuracoes:

runner settings show                          # ver config atual
runner settings get github.default_user       # ler valor
runner settings set github.default_user user  # setar valor
runner settings show --json                   # output JSON

4. Registrar Aplicacao

runner add --repo usuario/meu-app --branch main --token ghp_xxx --ckey "minha-chave-secreta"

Este comando:

  • Clona o repositorio em /data/apps/meu-app/
  • Registra a app no estado do Runner
  • Faz checkout da branch indicada em --branch
  • Se --ckey fornecida e secrets.enc existe no repo, restaura .env/.secrets
  • Se nao tem .env e o .deploy.yml define environment:/secrets:, roda o Env Wizard

`--repo` aceita URLs (v2.12.0+)

Todos esses formatos sao normalizados pra usuario/meu-app:

runner add --repo usuario/meu-app --branch main             # canonical
runner add --repo https://github.com/usuario/meu-app --branch main
runner add --repo https://github.com/usuario/meu-app.git --branch main
runner add --repo git@github.com:usuario/meu-app.git --branch main
runner add --repo ssh://git@github.com/usuario/meu-app.git --branch main
runner add --repo https://gitlab.com/grupo/sub/repo --branch main   # pega 2 segmentos finais

`--branch` e OBRIGATORIO (v2.12.0+, BREAKING)

Removido o default "dist". Sempre especifique --branch:

runner add --repo usuario/repo                  # ERRO: branch_required
runner add --repo usuario/repo --branch main    # OK
runner add --repo usuario/repo --branch dist    # OK
runner add --repo usuario/repo --branch dev     # OK

Justificativa: evita publicar branch errada por equivoco. Cada chamada de runner add agora declara explicitamente qual branch sera deployada.

`--branch` propaga pra `instances.X.source.branch` (v2.18.0+)

Antes da v2.18.0, runner add --branch dev clonava de dev mas o instances.{instance}.source.branch ficava com o valor do .deploy.yml (geralmente main). Resultado: runner fetch posterior puxava da branch errada.

Agora a flag propaga automaticamente:

  • Com --instance X: aplica a instances.X.source.branch
  • Sem --instance: aplica a toda instance cujo source.branch esteja vazio ou em valores genericos (main/master)

Configs explicitas (ex: staging.source.branch: dev + production.source.branch: main) sao preservadas.

`--deploy` realmente deploya (v2.18.0+)

Antes da v2.18.0, runner add ... --deploy apenas registrava a app e logava Auto-deploy requested but disabled — operador acreditava que rolou e nao subia container.

Agora invoca o pipeline de deploy na sequencia. Se o deploy falhar, a app continua registrada (basta rerun de runner deploy <app> para tentar de novo).

runner add --repo user/app --branch dev --token-from outra-app --ckey --instance production --deploy
# [ADD] middleware-241/api registered
# [--deploy] launching deploy for /data/apps/middleware-241 (instance: production)
# [BUILD] image built: middleware-241:abc1234
# [DEPLOY] container healthy after 42s

`--ckey-show` para exibir plaintext (v2.18.0+)

Por default, runner add --ckey (sem valor) gera ckey random e mostra apenas o fingerprint (ck_xxxx…xxxx) — a ckey fica encriptada em state/<app>.yml. Para retrieve-la, use runner ckeys export <app>.

Para forcar exibicao plaintext (em terminal privado, sem audit log):

runner add --repo user/app --branch main --ckey --ckey-show
# Generated random ckey (32 chars). Save it now: shown only here.
#   ckey: <32-char-alfanum-aleatoria>     # exemplo: XEpjzTTA…JRLx (seu valor sera diferente)
#   fingerprint: ck_XEpj…JRLx

Mudanca pra evitar leak por screen-share, log de CI, paste em chat.

Repos sem `.deploy.yml` (v2.16.0+)

Se o repo nao tem .deploy.yml, o runner detecta o perfil do repo e gera o manifesto proporcionalmente:

Perfil Sinais O que acontece
A tem .deploy.yml usa direto
B Dockerfile + envs gera completo
C Dockerfile so gera parcial + warning instrutivo
D docker-compose.yml so gera baseado no service app
E nada de Docker falha com instrucao clara
# repo com Dockerfile + .env.example
runner add --repo user/app --branch main
# [generator] Profile B detected. Generating .deploy.yml from inputs: Dockerfile, .env.example

Veja Generator de .deploy.yml pra detalhes dos perfis e heuristicas.

Wizard interativo automatico (v2.17.0+)

Existem 3 ferramentas pra ajudar com .deploy.yml e .secrets.enc (CLI + 2 browser). Se nao tem certeza qual usar, comece pela visao geral comparativa.

Em modo TTY interativo (sem --json, stdin/stderr conectados a um terminal), quando o repo cai no perfil E (cru — sem Docker e sem .deploy.yml), o runner add pergunta:

⚠ Repositorio sem perfil de deploy detectado.
? Executar wizard interativo agora? [Y/n]

Aceite e o wizard guia voce pergunta-a-pergunta para construir o .deploy.yml do zero — incluindo deteccao de variaveis de ambiente, classificacao automatica de secrets, geracao de .runner/secrets.enc encriptado, e instrucoes finais para commitar e completar o registro.

Tambem pode ser invocado standalone:

runner wizard --path /tmp/meu-repo            # wizard num repo local
runner wizard --repo user/app --branch main   # clone shallow + wizard
runner wizard --path . --accept-defaults --json --dry-run   # CI/automacao

Detalhes completos: `runner wizard`.

Estrutura do app dir (v2.15.0+)

A partir da v2.15.0, runner add cria o app dir minimalista — sem clone do repo na raiz. O codigo so aparece em src/{instance}/{version}/ apos o primeiro deploy.

/data/apps/meu-app/
├── .deploy.yml            # so o config (copiado do shallow clone)
├── .runner/
│   ├── REGISTERED_BY_RUNNER
│   └── secrets.enc        # se houver no repo
├── data/                  # vazio (uso runtime)
├── logs/                  # vazio (uso runtime)
├── pull/                  # criado pelo primeiro fetch
└── src/{instance}/{version}/   # criado pelo deploy

Apps registradas em versoes anteriores tinham o codigo do repo na raiz (duplicado com src/). Pra migrar:

runner cleanup --reset-root --project meu-app --dry-run    # preview
runner cleanup --reset-root --project meu-app              # executa (snapshot automatico)

Veja runner cleanup pra detalhes.

`--token-from ` (v2.13.0+)

Reusa token de outra app ja registrada. Util quando varias apps usam o mesmo token:

runner add --repo devborlot/app2 --branch main --token-from app1
# Reusing token from 'app1' (fingerprint: tk_a1b2…c3d4)

Veja runner tokens para listagem e validacao de tokens registrados.

`--ckey` (v2.12.0+: aceita random)

runner add --repo X --branch main --ckey                  # gera 32 chars random (mostrado uma vez)
runner add --repo X --branch main --ckey "minha-chave"    # usa literal
runner add --repo X --branch main                         # sem ckey (secrets em plaintext)

A flag --ckey e opcional mas recomendada. Permite recuperacao automatica dos secrets em caso de perda do servidor. Guarde a ckey em um password manager (especialmente quando random — o runner mostra o valor uma unica vez).

Para backup da master key (encripta todas as ckeys):

runner mkey

Env Wizard (primeiro deploy)

Quando o .deploy.yml define variaveis de ambiente com sintaxe especial, o Runner gera .env e .secrets automaticamente no primeiro registro:

# No .deploy.yml do projeto
environment:
  FLASK_ENV: production                          # valor fixo
  BASE_DOMAIN: "{{::Domain?projeto.com.br}}"     # pergunta com default
  DB_NAME: "{{::Database name}}"                 # pergunta sem default
  REDIS_DB: "{{::Redis DB?0}}"                   # pergunta com default

secrets:
  DB_PASSWORD: "{RANDOM}"                        # gera automaticamente
  JWT_SECRET: "${GENERATE:hex:64}"               # gera hex 64 chars
  SMTP_PASSWORD: "{{::SMTP Password}}"           # pergunta ao operador

No modo interativo, o Runner pergunta cada valor:

Configuring environment for meu-app (sys):

  Domain [projeto.com.br]:
  Database name: meu_app_prod
  Redis DB [0]:

Generated .env (4 vars), .secrets (3 vars, 2 random)

Para deploy remoto (sem interacao), passe valores via --env:

runner add --repo usuario/meu-app --branch main --token ghp_xxx \
  --env BASE_DOMAIN=app.cliente.com \
  --env DB_NAME=cliente_prod \
  --env SMTP_PASSWORD=segredo123

Consulte o guia Secrets e Encriptacao para detalhes.

5. Configurar Cron

Adicione ao crontab (crontab -e):

# Fetch e deploy a cada 5 minutos
*/5 * * * * runner fetch --deploy --json >> /var/log/runner-fetch.json 2>&1

# Cleanup de staging a cada hora (opcional)
0 * * * * runner stage cleanup --json >> /var/log/runner-staging-cleanup.json 2>&1

# Cleanup de versoes antigas diario
0 3 * * * runner cleanup >> /var/log/runner-cleanup.log 2>&1

# Cleanup de imagens Docker + build cache semanal
0 5 * * 0 runner cleanup --images --build-cache 72h >> /var/log/runner-images.log 2>&1

Preparar Repositorio

1. Criar Branch dist

No seu repositorio local:

git checkout -b dist
git push -u origin dist

2. Criar .deploy.yml

Crie o arquivo .deploy.yml na raiz do projeto:

project: meu-app
port: 8000
networks:
  - public

environment:
  FLASK_ENV: production
  BASE_DOMAIN: "{{::Domain?meusite.com.br}}"
  DB_NAME: "{{::Database name}}"

secrets:
  DB_PASSWORD: "{RANDOM}"
  JWT_SECRET: "${GENERATE:hex:64}"

healthcheck:
  path: /health            # HTTP (servicos)
  # mode: exit             # CLI tools/scanners (sem container permanente)

instances:
  production:
    domain: app.meusite.com.br
    source:
      type: dist
    keep_versions: 3

Para gerar um template completo com todas as opcoes:

runner generate-config

3. Fazer Build e Push

# Build do projeto
npm run build  # ou seu comando de build

# Mudar para dist
git checkout dist

# Copiar artefatos
rm -rf dist/
cp -r ../build/dist ./dist/

# Commit e push
git add .
git commit -m "deploy: v1.0.0"
git push origin dist

Verificar Deploy

Status completo de uma app

runner status meu-app/front
runner status meu-app/front --json

Mostra: instancias, container state, health, versoes, contadores (fetches, deploys, errors).

Listar todas as apps

runner list
runner list --detailed --json

Ver instancias e versoes

runner instances meu-app
runner versions meu-app -i production

Verificar health

runner health meu-app/front

Mostra: domain, endpoint, container status, HTTP status code, response time.

Ver manifest (.deploy.yml)

runner manifest meu-app/front --json

Ver logs de deploy

runner logs tail meu-app/front
runner logs history meu-app/front

Gerenciar Apps

Desregistrar uma app

runner unregister print                        # para tudo e limpa (pede confirmacao)
runner unregister print --force                # sem confirmacao
runner unregister print --keep-running         # desregistra mas mantém container
runner unregister print --keep-traefik         # para container mas mantém rota
runner unregister print --force --json         # output JSON

Reset de deploy

runner reset print                             # reset instancia default
runner reset print --instance staging          # reset instancia especifica
runner reset print --hard                      # wipe .env/.secrets tambem
runner reset print --hard --env DB_NAME=new    # regenera via wizard

Atualizacoes

runner self-update            # atualizar para ultima versao
runner self-update --rc       # testar release candidate
runner self-update --check    # verificar se ha atualizacao

Configurar Notificacoes (Opcional)

Telegram

  1. Crie um bot com @BotFather
  2. Obtenha o chat ID enviando uma mensagem para o bot
  3. Configure:
runner settings set notify.telegram_bot_token "123456789:ABCdefGHIjklMNOpqrsTUVwxyz"
runner settings set notify.telegram_chat_id "-1001234567890"

Discord

  1. Crie um webhook no canal desejado
  2. Configure:
runner settings set notify.discord_webhook "https://discord.com/api/webhooks/..."

Integrar com Claude Code (Opcional)

O Runner inclui um servidor MCP para integracao com Claude Code.

runner mcp install   # instalar configuracao
runner mcp status    # verificar status

Apos instalar, reinicie o Claude Code. O Runner estara disponivel como ferramenta.

Proximos Passos

Comandos Uteis

runner --help                          # ajuda geral
runner list                            # listar apps
runner status meu-app/front            # status detalhado
runner deploy meu-app/front            # deploy manual
runner rollback meu-app/front          # rollback
runner versions meu-app -i production  # ver versoes
runner health meu-app/front            # health check
runner manifest meu-app/front --json   # ver .deploy.yml
runner secrets meu-app/front --json    # ver secrets descriptografados
runner settings show --json            # ver config runner
runner mkey --json                     # backup master key
runner unregister meu-app --force      # remover app
runner reset meu-app --hard            # reset completo
By Borlot.com.br on 20/04/2026