Voltar para blog

Automação de provisionamento no HestiaCP via API: diagnóstico, segurança e operação em produção

02/03/2026 · 3 min · HestiaCP

Compartilhar

Automatizar criação de contas no HestiaCP é etapa obrigatória quando o painel precisa operar acoplado a billing (WHMCS), ERP interno ou pipeline de onboarding. O ganho é direto: menos intervenção manual, menor tempo de entrega e trilha operacional auditável.

Neste artigo, documento exatamente como estruturei esse fluxo: validação local de comandos, chamada remota via API, troubleshooting de autenticação/conectividade e controles de segurança para produção.

1) Arquitetura real da API do HestiaCP

A API do HestiaCP atua como wrapper dos comandos CLI (v-*). Na prática, você envia um POST para o endpoint de administração e o painel executa o comando correspondente no backend.

Endpoint padrão:

https://SEU_SERVIDOR:8083/api/

Parâmetros essenciais:

Regra operacional: a API só é previsível quando você já validou o comando equivalente no shell.

2) Pré-validação obrigatória no servidor (CLI primeiro)

Antes de integrar PHP/WHMCS, valide diretamente no host se a sintaxe e permissões do comando estão corretas.

Exemplo de criação de usuário:

v-add-user novo_usuario 'SenhaForte123!' email@cliente.com default Nome Sobrenome
echo $?

Se o retorno (exit code) não for 0, não avance para API. Corrija no nível CLI primeiro.

Checklist mínimo no host:

which v-add-user
v-list-user admin json
v-list-packages json

Isso evita perder tempo depurando aplicação quando o problema está no próprio painel/pacote/permissão.

3) Teste de API isolado com cURL

Com CLI validado, repliquei o mesmo fluxo via HTTP para eliminar variáveis do sistema chamador.

curl -k -X POST "https://seu-servidor.com:8083/api/" \
  -d "user=admin" \
  -d "password=SUA_SENHA" \
  -d "hash=SEU_HASH" \
  -d "cmd=v-add-user" \
  -d "arg1=novo_usuario" \
  -d "arg2=SenhaForte123" \
  -d "arg3=email@cliente.com" \
  -d "arg4=default" \
  -d "arg5=Nome" \
  -d "arg6=Sobrenome"

Durante debug, usei -k apenas para isolar TLS. Em produção, o correto é certificado válido + verificação habilitada.

Diagnóstico HTTP detalhado:

curl -vk -X POST "https://seu-servidor.com:8083/api/" -d "..."

Esse passo mostrou rapidamente se a falha era autenticação, payload malformado ou bloqueio de rede.

4) Implementação robusta em PHP

No integrador PHP, padronizei envio com http_build_query() para garantir encoding correto e evitar quebra de parâmetros com caracteres especiais.

<?php
$endpoint = 'https://seu-servidor.com:8083/api/';

$payload = [
  'user' => 'admin',
  'password' => 'SUA_SENHA',
  'hash' => 'SEU_HASH',
  'cmd' => 'v-add-user',
  'arg1' => 'novo_usuario',
  'arg2' => 'SenhaForte123',
  'arg3' => 'email@cliente.com',
  'arg4' => 'default',
  'arg5' => 'Nome',
  'arg6' => 'Sobrenome',
];

$ch = curl_init($endpoint);
curl_setopt_array($ch, [
  CURLOPT_POST => true,
  CURLOPT_POSTFIELDS => http_build_query($payload),
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CONNECTTIMEOUT => 10,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_SSL_VERIFYPEER => true,
  CURLOPT_SSL_VERIFYHOST => 2,
  CURLOPT_HTTPHEADER => ['Content-Type: application/x-www-form-urlencoded'],
]);

$response = curl_exec($ch);
$errno = curl_errno($ch);
$error = curl_error($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($errno) {
  throw new RuntimeException("cURL error [$errno]: $error");
}

if ($httpCode < 200 || $httpCode >= 300) {
  throw new RuntimeException("HTTP error [$httpCode] response: " . ($response ?? ''));
}

if ($response === false || trim($response) === '') {
  throw new RuntimeException('API response empty. Check auth/hash/firewall.');
}

echo $response;

Pontos que salvaram tempo de troubleshooting:

5) Falhas recorrentes que encontrei em produção

5.1 Hash inválido ou expirado

Sintoma: resposta vazia, erro de autenticação ou execução negada.

Mitigação:

5.2 Encoding quebrando args

Sintoma: nome/email com caracteres especiais gera comando corrompido.

Mitigação:

5.3 Firewall bloqueando porta 8083

Sintoma: timeout, connection refused ou handshake interrompido.

Mitigação:

# validar conectividade
nc -vz seu-servidor.com 8083

# validar regra (exemplo UFW)
ufw status

# exemplo de liberação controlada
ufw allow from IP_ORIGEM to any port 8083 proto tcp

5.4 Divergência de pacote/limite

Sintoma: API responde erro de criação por pacote inexistente ou limite.

Mitigação:

v-list-packages json
v-list-user admin json

Validar se arg4 (package) existe e se o operador tem permissão para provisionar nesse perfil.

6) Segurança operacional que implementei

  1. Segredos fora do código (env/secret manager).
  2. Mascaramento de senha/hash nos logs.
  3. TLS válido no hostname do painel (Let's Encrypt).
  4. CURLOPT_SSL_VERIFYPEER=true e CURLOPT_SSL_VERIFYHOST=2 em produção.
  5. ACL de origem na porta 8083 (somente IPs do provisionador).
  6. Auditoria de tentativas de provisionamento com correlation id por requisição.

Exemplo de log seguro:

request_id=prov-20260302-001 cmd=v-add-user user=admin target=novo_usuario package=default http=200 result=ok

7) Runbook de validação pós-implementação

Após deploy da automação, executei sequência de aceite:

  1. criar usuário via API
  2. criar domínio vinculado ao usuário
  3. validar conta no painel
  4. validar estrutura em disco
  5. validar serviço web/dns/mail conforme pacote

Comandos usados no pós-check:

v-list-user novo_usuario json
v-list-web-domains novo_usuario json
v-list-dns-domains novo_usuario json

Com isso, a automação ficou observável e previsível, sem “provisionamento fantasma”.

8) Resultado técnico

Com esse modelo, passei de criação manual para fluxo API com tempo de entrega de segundos, mantendo controle de segurança e trilha de auditoria. O principal ganho não foi só velocidade, foi consistência operacional.

Resumo prático:

CC BY-NC

Este post está licenciado sob CC BY-NC.

Comentários

Participe da discussão abaixo.