runner serve
Inicia o servidor de triggers para receber webhooks e/ou executar o canary scheduler.
Sintaxe
runner serve [OPTIONS]Opcoes
| Opcao | Tipo | Default | Descricao |
|---|---|---|---|
--service |
flag | false |
(v2.2.0) Service mode: le service.yml, inicia API HTTP + scheduler generico |
--mode |
string | auto |
Modo de operacao legacy: auto, webhook, cron, both |
--port |
integer | 8080 |
Porta do webhook server (legacy) |
--path |
string | /webhook |
Path do endpoint webhook |
--secret |
string | - | Secret para verificacao HMAC (ou env WEBHOOK_SECRET) |
--allow-unauthenticated |
flag | false |
(v2.161.0) Sobe o webhook sem secret, e só em 127.0.0.1. Sem esta flag, webhook sem secret não sobe |
--tick-interval |
integer | 60 |
Intervalo em segundos do canary scheduler |
Nota v2.2.0: em service mode (
--service), port/mode/secret vem doservice.ymle nao dos argumentos CLI.
Modos de Operacao
| Modo | Comportamento |
|---|---|
auto |
Inicia webhook se secret configurado, senao apenas cron |
webhook |
Apenas webhook server |
cron |
Apenas canary scheduler |
both |
Webhook e cron simultaneamente |
Exemplos
Auto-detectar Modo
runner serveSe WEBHOOK_SECRET estiver definido, inicia webhook + cron. Senao, apenas cron.
Apenas Webhook Server
runner serve --mode webhook --port 9000Apenas Canary Scheduler
runner serve --mode cron --tick-interval 30Ambos
runner serve --mode both --port 8080 --tick-interval 60Com Secret via Argumento
runner serve --secret "meu_secret_aqui"Com Secret via Variavel de Ambiente
export WEBHOOK_SECRET="meu_secret_aqui"
runner serveWebhook Server
O webhook server recebe eventos de push do GitHub (headers X-Hub-Signature-256
e X-GitHub-Event).
Estado atual: o webhook valida a assinatura e responde ao
ping, mas o push ainda não dispara deploy. O deploy continua vindo do cron (runner fetch --deploy) ou da API do service mode.
Desde a v2.161.0, com --secret o webhook escuta em todas as interfaces, para
o GitHub alcançar. Sem secret ele não sobe, salvo com --allow-unauthenticated,
que escuta só em 127.0.0.1.
Endpoints
| Endpoint | Metodo | Descricao |
|---|---|---|
/health |
GET | Health check do servidor |
/webhook |
POST | Recebe eventos webhook |
Eventos Suportados
| Evento | Acao |
|---|---|
push |
Valida a assinatura e registra (deploy pelo push: ainda não) |
ping |
Responde OK (teste de conexao) |
Headers Esperados
| Header | Descricao |
|---|---|
X-Hub-Signature-256 |
Assinatura HMAC-SHA256 (GitHub) |
X-GitHub-Event |
Tipo de evento (push, ping, etc) |
Payload GitHub
{
"ref": "refs/heads/dist",
"repository": {
"full_name": "usuario/repo",
"name": "repo"
},
"pusher": {
"name": "usuario"
},
"after": "abc123..."
}Verificacao de Assinatura
Se secret estiver configurado, o servidor verifica a assinatura HMAC-SHA256:
- Calcula HMAC-SHA256 do body com o secret
- Compara com o header
X-Hub-Signature-256 - Rejeita se nao corresponder (401 Unauthorized)
Canary Scheduler
O canary scheduler executa periodicamente (a cada tick-interval segundos) e:
- Le estado dos canary deployments ativos
- Verifica health checks
- Incrementa peso se configurado para auto-promote
- Executa rollback se condicoes de abort forem atingidas
Estado do Scheduler
O estado e persistido em /opt/runner/state/canary/:
# /opt/runner/state/canary/meu-app_production.yml
project: meu-app
instance: production
stable_version: v1.2.3
canary_version: v1.2.4
current_weight: 30
state: running
started_at: "2026-02-16T14:00:00Z"
last_step_at: "2026-02-16T14:10:00Z"
next_step_at: "2026-02-16T14:15:00Z"Logs do Scheduler
# Ver logs em tempo real
tail -f /opt/runner/logs/canary-scheduler.log
# Ou via journalctl se rodando como servico
journalctl -u runner-serve -fConfiguracao via config.yml
O comando serve le configuracoes do config.yml:
# /opt/runner/config.yml
triggers:
mode: auto
webhook:
enabled: true
port: 8080
path: /webhook
secret: "${WEBHOOK_SECRET}"
cron:
enabled: true
canary_tick_interval: 60Argumentos da CLI sobrescrevem o config.yml.
Service Mode (v2.2.0+)
A forma recomendada de rodar o serve em producao e via service mode:
runner service init --enable-api # Gera service.yml + unit; nasce DESATIVADO (v2.161.0)
runner service start # Liga: inicia e habilita no boot
runner service status # VerificaTodos os subcomandos de `service`
| Subcomando | O que faz |
|---|---|
init |
Gera service.yml e escreve a unit do systemd. Nasce desativado (v2.161.0): não habilita, não inicia, API desligada salvo --enable-api |
start |
Liga: systemctl enable --now (inicia e sobe no boot) |
stop |
systemctl stop |
restart |
systemctl restart |
status |
Estado do servico |
config |
Atualiza a configuracao do servico. Com o servico ativo, reinicia sozinho para aplicar (v2.161.0) |
expose --domain <d> [--vpn-only] |
(v2.161.0) Publica a API num dominio do Traefik, com TLS. Ver API remota |
unexpose |
(v2.161.0) Remove a rota da API e volta a escutar so em 127.0.0.1 |
uninstall |
Remove tudo: stop + disable + remove a unit + remove o service.yml |
O service mode le /opt/runner/service.yml e inicia:
- API HTTP com auth via X-API-Key (endpoints: /health, /api/v1/status, signal, deploy, apps)
- Scheduler generico com jobs configuraveis (canary, ttl_cleanup, signal_check)
- mTLS opcional (v2.3.0) com hot-reload de CA cert
Desde a v2.161.0:
- sem
service.yml, so o scheduler sobe, e a API fica desligada ate orunner service init; - API habilitada sem chave, ou com chave fora do formato
rk_…, nao sobe; - bind invalido e erro. Antes, a API subia com chave vazia aceitando um header vazio, e um bind invalido virava
127.0.0.1em silencio.
Ver service.yml reference para configuracao completa.
API Endpoints (v2.2.0)
| Endpoint | Metodo | Auth | Descricao |
|---|---|---|---|
/health |
GET | Nenhuma | Health check |
/api/v1/status |
GET | X-API-Key | Scheduler jobs + status |
/api/v1/signal/{app} |
POST | X-API-Key | Signal externo (CI/CD) |
/api/v1/deploy/{app} |
POST | X-API-Key | Dispara o deploy: 202 {deploy_id}; 409 lock_contended com quem segura o lock (v2.161.0) |
/api/v1/deploy/{id} |
GET | X-API-Key | Status do deploy disparado: rodando, sucesso ou falhou (v2.161.0) |
/api/v1/apps |
GET | X-API-Key | Listar apps |
mTLS (v2.3.0)
Quando habilitado, conexoes sem client certificate valido sao rejeitadas no TLS handshake. A CA e relida do disco a cada handshake em que o arquivo mudou (mtime), sem restart. Isso vale desde a v2.161.0; antes so valia depois de reiniciar.
Com o mTLS ligado e faltando ca.pem, server.pem ou server.key, a API
nao sobe e mostra mtls_incompleto com a lista do que falta. Antes, sem
CA, ela caia para HTTP sem avisar.
runner service config --ca-cert /path/to/ca.pemO mTLS e para conexao direta. Atras do Traefik (service expose) ele e
recusado, porque o Traefik termina o TLS.
Modo Legacy (compatibilidade)
O modo legacy (sem --service) continua funcionando como antes:
Systemd (legacy)
# /etc/systemd/system/runner-serve.service
[Unit]
Description=Runner Webhook/Cron Server
After=network.target docker.service
[Service]
Type=simple
ExecStart=/opt/runner/runner serve
WorkingDirectory=/opt/runner
Environment=WEBHOOK_SECRET=seu_secret_aqui
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.targetConfigurando GitHub Webhook
- Acesse Settings → Webhooks no repositorio
- Clique em "Add webhook"
- Configure:
- Payload URL:
https://seu.servidor.com:8080/webhook - Content type:
application/json - Secret: Mesmo valor do
WEBHOOK_SECRET - Events: Just the push event
- Payload URL:
- Clique em "Add webhook"
Testando
Health Check
curl http://localhost:8080/healthResposta esperada:
{"status": "healthy", "version": "1.2.0"}Simular Webhook
# Gerar assinatura
PAYLOAD='{"ref":"refs/heads/dist","repository":{"full_name":"user/repo"}}'
SIGNATURE=$(echo -n "$PAYLOAD" | openssl dgst -sha256 -hmac "seu_secret" | cut -d' ' -f2)
# Enviar
curl -X POST http://localhost:8080/webhook \
-H "Content-Type: application/json" \
-H "X-Hub-Signature-256: sha256=$SIGNATURE" \
-H "X-GitHub-Event: push" \
-d "$PAYLOAD"Exit Codes
| Codigo | Significado |
|---|---|
| 0 | Encerrado normalmente (Ctrl+C) |
| 1 | Erro de configuracao |
| 2 | Porta ja em uso |