Referencia config.yml (Global)

O arquivo /opt/runner/config.yml define a configuracao global do Runner no servidor.

Estrutura Completa

# ============================================
# CAMINHOS
# ============================================
apps_path: /data/apps                      # Diretorio raiz das apps
traefik_dynamic_path: /etc/traefik/dynamic # Configs dinamicas Traefik
state_path: /opt/runner/state              # Estado do Runner
logs_path: /opt/runner/logs                # Logs do Runner

# ============================================
# DOCKER
# ============================================
registry: registry.local                   # Registry Docker (opcional)
keep_versions: 3                           # Versoes a manter por padrao
max_deploy_retries: 3                      # Max tentativas para mesmo commit (0 = ilimitado)

# ============================================
# TRAEFIK
# ============================================
traefik:
  mode: external                           # local | external | none (v2.20.0+)
  entrypoints:
    - websecure                            # Entrypoint HTTPS
  cert_resolver: myresolver                # Resolver de certificados
  external:                                # v2.21.0+ sub-block (só usado quando mode=external)
    write_snippet_to: "/opt/traefik-snippets/{app}.yml"   # opcional, salva em arquivo
    print_snippet: true                    # default true, emite snippet em stderr

# ============================================
# GITHUB
# ============================================
github:
  default_user: devborlot                  # Usuario GitHub padrao

# ============================================
# NOTIFICACOES (v1.4.0+)
# ============================================
notify:
  channel: telegram                        # telegram | discord | both
  telegram_bot_token: "123456:ABC-DEF..."  # Token do bot (@BotFather)
  telegram_chat_id: "-1001234567890"       # ID do chat/grupo/canal
  discord_webhook: ""                      # URL do webhook Discord
  verbose_errors: true                     # Segunda mensagem com erro completo (v2.0.7)

# ============================================
# PR AUTO-CLEANUP (v2.0.0)
# ============================================
auto_cleanup_prs: true                     # Remove PRs expirados (TTL) no fetch

# ============================================
# LOGS ESTRUTURADOS v1.2.0
# ============================================
logs:
  deploy_events:
    type: structured_log
    path: /opt/runner/logs/deploy-events.jsonl
    format: json_lines

# ============================================
# TRIGGERS v1.2.0
# ============================================
triggers:
  mode: auto                               # auto | webhook | cron | both

  webhook:
    enabled: true
    port: 8080
    path: /webhook
    secret: "${WEBHOOK_SECRET}"            # Para verificacao HMAC

  cron:
    enabled: true
    canary_tick_interval: 60               # Segundos entre ticks do scheduler

# ============================================
# STAGING
# ============================================
staging:
  enabled: true                            # Habilitar staging de PRs
  base_path: /opt/runner/staging           # Diretorio base
  network: public                          # Network Docker
  default_ttl_hours: 48                    # TTL padrao
  max_total_instances: 20                  # Max stagings total

# ============================================
# NETWORK / PORT ALLOCATION (v2.19.0)
# ============================================
network:
  vpc_ip: 10.108.0.5                       # opcional. Sem isso → bind 127.0.0.1 (loopback)
  publish_strategy: random                 # random | sequential | explicit | none
  port_range: [8000, 8999]                 # range pra alocacao automatica
  port_blocklist: [8080, 9000]             # opcional — portas a ignorar

Campos Detalhados

Caminhos

Campo Tipo Default Descricao
apps_path string /data/apps Diretorio raiz das aplicacoes
traefik_dynamic_path string /etc/traefik/dynamic Configs dinamicas do Traefik
state_path string /opt/runner/state Diretorio de estado
logs_path string /opt/runner/logs Diretorio de logs

Docker

Campo Tipo Default Descricao
registry string - URL do registry Docker privado
keep_versions integer 3 Quantas versoes manter por padrao
max_deploy_retries integer 3 Max tentativas de deploy para o mesmo commit que falhou. 0 = ilimitado (v1.4.1+)
docker.auto_prune_dangling boolean true v2.23.20+. Apos deploy build:, roda docker image prune -f (so untagged sem container). Safe.
docker.auto_prune_build_cache string "72h" v2.23.20+. Apos deploy build:, prune do buildkit cache mais velho que isso. Aceita 72h, 7d, all, ou "" (desabilita).

Traefik

Campo Tipo Default Descricao
traefik.mode string local Modo de roteamento. Detalhe abaixo.
traefik.entrypoints array [websecure] Entrypoints a usar
traefik.cert_resolver string myresolver Resolver de certificados
traefik.external.write_snippet_to string - Path opcional pra salvar snippet (Ansible sync). {app} placeholder expande pro project slug (v2.21.0+)
traefik.external.print_snippet boolean true Imprime snippet em stderr depois do deploy (v2.21.0+)

`traefik.mode` — quatro modos

Valor Quando usar Como funciona
local (default) Traefik na mesma docker network dos containers (bridge public ou similar) Runner escreve <traefik_dynamic_dir>/<app>.yml com url: http://<container_name>:port. Traefik resolve via Docker DNS interno.
docker_labels (v2.23.11+) Traefik em network_mode: host OU quando você quer routing reativo a start/stop Runner emite labels Traefik no container. Traefik com provider docker (socket mount) descobre o container e seu bridge IP automaticamente. Requer Traefik configurado com providers.docker.endpoint: unix:///var/run/docker.sock e os containers conectados à network indicada em traefik.network. Limitação: canary não suportado (weighted service não cabe em labels per-container).
external (v2.20.0+) Traefik em outro host (sync via Ansible/scp) Skipa write local + emite snippet copy-pasteable em stderr (e/ou em external.write_snippet_to).
none (v2.20.0+) App interna sem HTTP público Nenhuma config Traefik gerada. Container sobe mas não tem rota.

Erro comum: Traefik em network_mode: host + traefik.mode: local → dynamic file escrito com container name → Traefik no host não resolve via Docker DNS → dial tcp: lookup <container> on 127.0.0.53:53: server misbehaving → service marked DOWN → 503 pro cliente. Switch pra docker_labels resolve.

Output em mode=external (v2.21.0+):

✅ DEPLOY CONCLUÍDO
   Endpoint: http://10.0.0.5:8473

📋 SNIPPET TRAEFIK (cole no <traefik-server>:/etc/traefik/dynamic/<file>.yml):

http:
  routers:
    meu-app-production:
      rule: "Host(`app.example.com`)"
      entryPoints: ["websecure"]
      tls: { certResolver: myresolver }
      service: meu-app-production
  services:
    meu-app-production:
      loadBalancer:
        servers:
          - url: "http://127.0.0.1:8473"

ℹ️  Snippet salvo em /opt/traefik-snippets/meu-app.yml

Com print_snippet: true (default), o snippet vai em stderr depois do deploy. Com write_snippet_to: configurado, também salva em arquivo (Ansible sync). Os dois podem coexistir.

GitHub

Campo Tipo Default Descricao
github.default_user string - Usuario GitHub padrao

Notificacoes (v1.4.0+)

Campo Tipo Default Descricao
notify.channel string telegram Canal: telegram, discord ou both
notify.telegram_bot_token string - Token do bot Telegram (@BotFather)
notify.telegram_chat_id string - ID do chat/grupo/canal (negativo para grupos)
notify.discord_webhook string - URL completa do webhook Discord
notify.verbose_errors boolean true Envia segunda mensagem com erro completo quando deploy falha (v2.0.7)

PR Auto-Cleanup (v2.0.0)

Campo Tipo Default Descricao
auto_cleanup_prs boolean true Remove automaticamente PRs expirados (TTL) durante o fetch. PRs com branch deletada sao marcados como stale

Setup automatico:

runner notify setup --channel telegram   # Setup interativo Telegram
runner notify setup --channel discord    # Setup interativo Discord
runner notify setup --channel both       # Setup ambos
runner notify test                       # Testar envio
runner notify status                     # Ver status dos canais

O setup Telegram auto-detecta o chat_id de DMs, grupos e canais. Para canais, o bot precisa ser admin.

Canais ativados: O NotifyManager v2 ativa canais automaticamente com base nos campos preenchidos. Alem disso, um StructuredLogChannel grava todos os eventos em deploy-events.jsonl no diretorio de logs.

Logs (v1.2.0)

Configuracao de logs estruturados.

logs:
  deploy_events:
    type: structured_log
    path: /opt/runner/logs/deploy-events.jsonl
    format: json_lines

Formatos:

  • json_lines - Um JSON por linha (JSONL)
  • ndjson - Newline Delimited JSON (equivalente)

Exemplo de saida:

{"timestamp":"2026-02-16T14:30:00Z","event":"deploy_success","project":"meu-app","version":"v1.2.0","instance":"production","duration_ms":45000}
{"timestamp":"2026-02-16T14:35:00Z","event":"canary_weight_changed","project":"meu-app","version":"v1.2.1","instance":"production","weight":30}

Triggers (v1.2.0)

Configuracao de triggers automaticos.

triggers:
  mode: auto
  webhook:
    enabled: true
    port: 8080
    path: /webhook
    secret: "${WEBHOOK_SECRET}"
  cron:
    enabled: true
    canary_tick_interval: 60

Modos:

Modo Comportamento
auto Webhook se secret configurado, senao cron
webhook Apenas webhook server
cron Apenas cron scheduler
both Webhook e cron simultaneamente

Webhook:

Campo Tipo Default Descricao
enabled boolean true Habilitar webhook server
port integer 8080 Porta do servidor
path string /webhook Path do endpoint
secret string - Secret para verificacao HMAC

Cron:

Campo Tipo Default Descricao
enabled boolean true Habilitar cron scheduler
canary_tick_interval integer 60 Segundos entre ticks do canary scheduler

Staging

Campo Tipo Default Descricao
staging.enabled boolean false Habilitar staging de PRs
staging.base_path string /opt/runner/staging Diretorio base
staging.network string public Network Docker
staging.default_ttl_hours integer 48 TTL padrao em horas
staging.max_total_instances integer 20 Max stagings global

Network / Port Allocation (v2.19.0)

Bloco opcional. Sem ele, o runner usa publish_strategy=Explicit por default — comportamento idêntico à v2.18.x (lê ports: do .deploy.yml).

network:
  vpc_ip: 10.108.0.5
  publish_strategy: random
  port_range: [8000, 8999]
  port_blocklist: [8080]
Campo Tipo Default Descricao
network.vpc_ip string (IPv4) - IP da interface VPC. Sem isso, bind cai pra 127.0.0.1 (Traefik no mesmo host alcança via loopback)
network.publish_strategy string explicit Ver tabela abaixo
network.port_range [int, int] [8000, 8999] Range fechado pra alocação automática
network.port_blocklist array de int [] Portas a ignorar mesmo dentro do range

Strategies disponíveis:

Strategy Comportamento
random Sorteia porta livre na primeira deploy. Persiste sticky em state.network.published_port — re-deploys reusam.
sequential Pega primeira porta livre no range (em ordem crescente). Sticky igual random.
explicit (default) ports: do .deploy.yml (comportamento v2.18.x). Ignora port_range.
none Container roda sem -p no host (só na rede docker). Útil pra workers/sidecars.

Sticky lifecycle:

  1. Primeira deploy: aloca porta → persiste em state/<app>.yml::network.published_port
  2. Re-deploys (commit novo, runner fetch --deploy): reusa a mesma porta — Traefik externo permanece válido
  3. runner unregister X: libera porta de volta ao pool
  4. runner reset --hard X: libera state → próximo deploy realoca
  5. runner ports realloc X: força nova alocação (operador atualiza Traefik externo)

Backwards compat:

  • Sem bloco network: no config → publish_strategy = Explicit → comportamento idêntico v2.18.x
  • Apps registradas em v2.18.x continuam rodando sem precisar migrar
  • State files antigos sem bloco network migram silenciosamente — porta re-alocada na próxima deploy quando strategy != Explicit

Setup interativo:

runner init
# → "Esse server fica em uma VPC interna? [s/N]"
# → "IP detectado: 10.108.0.5 (interface eth1). Confirma? [Y/n]"
# → "Strategy [random/sequential/explicit] (default: random)"

Em modo não-TTY (CI, piped) skipa silenciosamente — backcompat 100%.

Veja também:

Auto-pause (v2.23.19)

Apps que falham git ls-remote (ou similar) repetidas vezes consecutivas viram paused automaticamente e o cron para de tentar.

max_consecutive_fetch_errors: 10   # default; 0 = desabilita
Campo Tipo Default Descricao
max_consecutive_fetch_errors integer 10 Quantos erros consecutivos no fetch antes de marcar a app como paused. 0 desabilita o auto-pause.

Quando vira paused:

  • state.consecutive_fetch_errors >= max_consecutive_fetch_errors
  • state.status muda pra paused
  • Cron skipa a app silenciosamente no proximo tick
  • Resultado: para de poluir o log (caso print com repo deletado)

Como reativar:

runner unpause <app>          # clear de paused + reset do counter
runner unpause <app> --json

runner reset <app> tambem reativa (clear total do state). Para casos onde a unica coisa errada eh o paused, prefira unpause.

Env Sync (v2.23.18)

Controla se .env/.secrets sao regenerados a partir do secrets.enc remoto quando o hash muda durante deploy.

env_sync_default: remote   # default — remoto soberano
env_sync_default: skip     # local soberano (staging servers)
Campo Tipo Default Descricao
env_sync_default string remote Default global para env_sync. Apps sem env_sync: explicito no .deploy.yml herdam este valor.

Valores:

Valor Comportamento
remote Se secrets.enc do repo mudou (hash diferente), decripta e sobrescreve .env/.secrets locais
skip .env/.secrets locais nunca sao sobrescritos por mudancas no secrets.enc remoto

Caso de uso principal: servidores de staging/teste onde o operador ajusta .env manualmente e nao quer que um deploy sobrescreva com valores de outro servidor.

Precedencia:

  1. Per-app env_sync: no .deploy.yml (se skip, sempre vence)
  2. Global env_sync_default no config.yml
  3. Se ambos omitidos: remote (retrocompativel)

Nota: .deploy.yml sempre sincroniza do remoto independente do env_sync — ele controla o contrato do deploy.

Exemplo Minimo

apps_path: /data/apps
traefik_dynamic_path: /data/assets/traefik/dynamic
state_path: /opt/runner/state
logs_path: /opt/runner/logs

traefik:
  entrypoints:
    - websecure
  cert_resolver: myresolver

github:
  default_user: meu-usuario

Exemplo Completo (v2.4.1)

apps_path: /data/apps
traefik_dynamic_path: /data/assets/traefik/dynamic
state_path: /opt/runner/state
logs_path: /opt/runner/logs

registry: registry.meuservidor.com.br
keep_versions: 5
max_deploy_retries: 3

traefik:
  entrypoints:
    - websecure
    - web
  cert_resolver: myresolver

github:
  default_user: devborlot

# Notificacoes v1.4.0
notify:
  channel: both
  telegram_bot_token: "123456789:ABCdefGHI..."
  telegram_chat_id: "-1001234567890"
  discord_webhook: "https://discord.com/api/webhooks/123456/abcdef..."

# Triggers
triggers:
  mode: auto
  webhook:
    enabled: true
    port: 8080
    path: /webhook
    secret: "${GITHUB_WEBHOOK_SECRET}"
  cron:
    enabled: true
    canary_tick_interval: 60

# Staging
staging:
  enabled: true
  base_path: /opt/runner/staging
  network: public
  default_ttl_hours: 72
  max_total_instances: 30

Inicializacao

O arquivo e criado automaticamente com:

runner init

Para ver o template sem criar:

runner init --show-template

Para sobrescrever existente:

runner init --force

Diretorios Criados

Apos runner init, os seguintes diretorios sao criados:

/opt/runner/
├── runner              # Binario
├── config.yml          # Este arquivo
├── state/              # Estado das apps
│   ├── {app}.yml       # Estado por app
│   └── canary/         # Estado do canary scheduler
│       └── {project}_{instance}.yml
└── logs/               # Logs
    ├── fetch-audit.json    # Log de fetches
    └── deploy-events.jsonl # Eventos de deploy (v1.2.0)

/data/apps/             # Raiz das aplicacoes
└── {projeto}_{instance}/   # Cada app/instancia

Permissoes

# Permissoes recomendadas
chown -R root:docker /opt/runner/
chmod 750 /opt/runner/
chmod 640 /opt/runner/config.yml
chmod 750 /opt/runner/state/
chmod 750 /opt/runner/logs/

Variaveis de Ambiente

O config.yml suporta interpolacao de variaveis de ambiente:

integrations:
  telegram:
    url: "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage"

As variaveis sao resolvidas em tempo de execucao.

Variaveis recomendadas:

  • TELEGRAM_BOT_TOKEN - Token do bot Telegram
  • DISCORD_WEBHOOK_URL - URL completa do webhook Discord
  • FLARE_API_TOKEN - Token da API Flare
  • SLACK_WEBHOOK_URL - URL do webhook Slack
  • GITHUB_WEBHOOK_SECRET - Secret para webhooks GitHub
  • CCS_CLIENT_ID / CCS_CLIENT_SECRET - Credenciais OAuth2 CCS
By Borlot.com.br on 12/03/2026