skills/deploy-server/SKILL.md

name: deploy-server
description: Use this skill to provision or update a Welley server on a supported cloud (currently DigitalOcean) when the user asks to deploy a new instance or run a server update. Covers single-instance deployments and SSH-based updates, including interactive collection of missing credentials, SSH keys, domain, region, and sizing.

Implantar servidor

Visão geral

Esta skill cria uma stack Welley de instância única na DigitalOcean e pode executar atualizações por SSH. Ela orienta o agente a reunir os dados que faltam, buscar as especificações de instância disponíveis em uma fonte definida, criar a VM, configurar o host, implantar com wlycli deployment create e validar o resultado.

Os nomes dos comandos devem ser iguais aos da CLI:

  • wlycli deployment create
  • wlycli deployment update
  • wlycli deployment delete

Padrões (DigitalOcean)

  • Região: nyc3
  • Imagem: latest LTS available via API (resolva com images?type=distribution)
  • Nome do droplet: gerado aleatoriamente no formato wlsly-<adjective>-<surname> (por exemplo, wlsly-bright-hopper). Use o trecho gerador de nomes de references/digitalocean.md. Use o mesmo nome para o banco gerenciado, se ele for criado.
  • Plano desejado: Basic / Regular (CPU compartilhada)
  • Tamanho desejado: 2 vCPU / 4 GB de RAM / 80 GB de SSD / 4 TB de transferência (~US$ 24/mês)

Regra para substituir os padrões

Se o usuário definir qualquer um dos padrões (região, imagem, nome do droplet, projeto, tamanho), o agente deve:

  1. Repetir a alteração exatamente como o usuário informou.
  2. Pedir confirmação antes de continuar.

Modelo de perguntas interativas

Pergunte só o que estiver faltando. Use exatamente estas perguntas para evitar ambiguidade. Faça as perguntas em rodadas. Rodada 1: no máximo 2 perguntas por vez. A rodada 2 pode apresentar uma opção agrupada de “aceitar todos os padrões”. Se o ambiente aceitar opções, apresente 2 a 3 alternativas por pergunta (A/B/C). Evite respostas livres, a menos que seja necessário.

Perguntas da rodada 1 (identidade e acesso):

  1. “Você tem um token de API da DigitalOcean para usar, ou devo esperar você enviar um?”
  2. “Qual domínio este servidor deve usar (por exemplo, super-puper.example.com)? Você controla o DNS dele?”
  3. “Você já tem uma chave pública SSH para usar, ou devo criar e enviar uma?”
  4. “Você quer colocar este droplet em um projeto existente da DigitalOcean? Se sim, informe o nome ou o ID do projeto.”
  5. “Requisito de DNS: você precisa criar registros A/AAAA para <domain> e storage.<domain> (se não houver CDN). Você consegue fazer isso antes de o certbot rodar?”
  6. “Requisito de DNS para e-mail: o domínio de --smtp-from precisa de registros SPF, DMARC e DKIM, senão e-mails de convite e de confirmação para novos destinatários podem ser descartados sem aviso. Eles já estão configurados, ou devo listar os registros que o seu provedor de SMTP exige?”
  7. Se o usuário perguntar onde conseguir um token da DO, envie este link:
https://cloud.digitalocean.com/account/api/tokens

Perguntas da rodada 2 (tamanho, localização e opções de implantação):

  1. “Você quer a região padrão nyc3 ou outra região?”
  2. “Você quer o tamanho padrão (2 vCPU / 2 GB) ou outra meta de CPU/RAM?”
  3. “Devo usar o Ubuntu LTS mais recente disponível na API ou uma versão específica do Ubuntu?”
  4. “Qual usuário SSH devemos usar depois do bootstrap (padrão: wlsly)? Você pode manter o padrão.”
  5. “Você quer um banco Postgres gerenciado ou prefere usar o contêiner de Postgres incluído?”
  6. Se o Postgres gerenciado for escolhido: “Qual região e qual tamanho devo usar para o banco? Posso usar como padrão nyc3 e 1 vCPU / 2 GB.”
  7. Se o Postgres gerenciado for escolhido: “Posso criar o banco pelo preço mensal listado pelo provedor?”
  8. “Envie as configurações de SMTP necessárias (host, usuário, senha, remetente). OTEL é opcional: envie só se precisar.”
  9. “O e-mail do administrador é obrigatório para criar. Envie agora (flag: --email / -e). Se você não enviar, vou pedir duas vezes para confirmar.”

Ofereça uma opção de “aceitar todos os padrões” na rodada 2 para agilizar a coleta de dados.

Se faltar alguma resposta, faça uma pergunta complementar objetiva (no máximo uma ou duas).

Fluxo de trabalho (DigitalOcean, instância única)

  1. Reúna os dados necessários (pergunte se faltar algum).
  • Token de API da DigitalOcean
  • Nome ou ID do projeto (opcional; se não for informado ou não for encontrado, use o projeto padrão)
  • Região
  • Tamanho desejado da instância (por exemplo, 4 vCPU / 16 GB de RAM)
  • Nome do domínio
  • Chave pública SSH (ou confirmação para criar e registrar uma)
  • E-mail do administrador para o primeiro login e a recuperação de senha (obrigatório para criar; --email / -e). Se faltar, peça duas vezes e confirme que são iguais.
  • Opcional: certificados TLS próprios ou certbot
  • Confirmação de acesso ao DNS (é preciso conseguir criar registros A/AAAA para <domain> e para storage.<domain>, se for usado)
  1. Busque os tipos de instância e escolha um tamanho.
  • Use o trecho de tamanhos de references/digitalocean.md para listar e filtrar por CPU/RAM.
  • Confirme com o usuário se houver mais de uma opção compatível.

2b. Descubra o slug da imagem do Ubuntu.

  • Chame GET /v2/images?type=distribution&per_page=200 e filtre pelo Ubuntu.
  • Se o usuário pediu uma versão específica, verifique se o slug dela existe e confirme.
  • Caso contrário, escolha o slug do LTS mais recente da lista e confirme com o usuário antes de criar.
  1. Crie o droplet.
  • Use a API da DigitalOcean diretamente (o doctl é opcional).
  • Imagem: prefira a que o usuário indicou; se não houver, escolha o LTS mais recente da lista da API.
  • Anexe o fingerprint da chave SSH ou crie e envie uma chave.
  • Ative o monitoramento.
  • Se o nome/ID do projeto foi informado, mas não foi encontrado, crie o droplet sem projeto (projeto padrão).
  • Observação: a criação do banco gerenciado pode rodar em paralelo com a criação do droplet.

Orientação de paralelização

O agente deve sobrepor tarefas independentes para reduzir o tempo total:

  • Enquanto reúne os dados do usuário (rodada 2), comece a criar o droplet se o token, a região, o tamanho, a imagem e a chave SSH já estiverem confirmados.
  • Enquanto o droplet está sendo criado, comece a criar o Postgres gerenciado (se foi pedido).
  • Enquanto o droplet está iniciando, continue coletando os dados restantes (SMTP, OTEL, e-mail do administrador).
  • Se faltar algum dado essencial para uma etapa, pause essa etapa e continue com as outras tarefas que podem rodar em paralelo.
  • Se o DNS for gerenciado na DigitalOcean, crie ou atualize os registros A/AAAA assim que o IP do droplet estiver disponível (não espere a etapa completa de implantação).
  1. DNS e domínio.
  • Pergunte se o DNS deve ser criado ou atualizado na DigitalOcean ou se ele fica em um DNS externo.
  • Se usar o DNS da DigitalOcean, crie registros A/AAAA apontando para o IP do droplet.
  1. Configure o host por SSH.
  • Crie um usuário sem privilégios de root (por exemplo, wlsly), dê a ele acesso ao sudo e copie as chaves SSH autorizadas.
  • Saia do root e entre de novo como o usuário sem privilégios de root antes de continuar.
  • Instale o Docker e o docker compose.
  • Baixe o binário da CLI do Welley pela AppStore e torne-o executável:
    • URL base: https://appstore.allroads.social/v1/social.wellesley.wlycli/latest?develop=stable&platform=<os>/<arch>
    • Escolha o valor correto de platform conforme o sistema e a arquitetura:
      • Linux x86_64: linux/amd64
      • Linux arm64: linux/arm64
      • macOS x86_64: darwin/amd64
      • macOS arm64: darwin/arm64
      • Windows x86_64: windows/amd64
    • Exemplo (Linux x86_64):
      curl -fL 'https://appstore.allroads.social/v1/social.wellesley.wlycli/latest?develop=stable&platform=linux/amd64' -o wlycli
      chmod +x wlycli
      
    • Os cabeçalhos de resposta esperados incluem:
      • x-artifact-display-name: Welley CLI
      • x-artifact-full-name: social.wellesley.wlycli
      • x-artifact-kind: cli
      • x-artifact-platform: <os>/<arch>, como linux/amd64
      • x-artifact-sha256: <sha256>
      • x-artifact-version: <version>
      • x-channel: develop
    • Antes de instalar, prefira conferir os cabeçalhos com uma requisição HEAD e verificar se o nome do artefato, o tipo, a plataforma e o canal correspondem ao binário pedido.
  • Verifique o binário da CLI: rode wlycli -v e wlycli deployment --help para confirmar as informações de build esperadas.
  1. Implante o Welley.
  • Rode wlycli deployment create com as opções necessárias.
  • Use os padrões de instância única (sem Postgres externo, a menos que o usuário peça).
  • Se o Postgres gerenciado for pedido, crie-o primeiro (banco da DigitalOcean) e depois use o host, a porta, o banco, o usuário e a senha retornados nas flags --postgres-*.
  • Se a senha do usuário do banco não for retornada pela API ou pela interface, redefina a autenticação do usuário do banco para obter credenciais novas antes de rodar o wlycli.
  • Execuções não interativas devem passar --email / -e, senão o comando falha.
  • --base-dir aponta para o diretório pai; a CLI cria o subdiretório do projeto automaticamente.
  • A CLI se recusa a rodar se o diretório do projeto ou os contêineres já existirem; é preciso limpar tudo antes de tentar de novo.
  1. Certificados (obrigatório).
  • Padrão: use o Certbot em modo standalone (não interativo).
  • O usuário deve apontar os registros A/AAAA do domínio (e de storage.<domain>, se for usado) para o IP do droplet antes de o certbot rodar.
  • A CLI aceita --public-ip (substitui o IP detectado) e --skip-dns-preflight, caso você precise ignorar a verificação.
  • Nunca presuma que o DNS está configurado. Pergunte e espere uma confirmação explícita.
  • Nunca use --skip-dns-preflight, a menos que o usuário peça explicitamente.
  • Se a CDN não estiver configurada, o certbot deve incluir storage.<domain> no pedido do certificado.
  • Use certificados autoassinados só se o usuário pedir explicitamente, e passe --self-signed-certs (gera certificados autoassinados em Go).
  • Dê ao usuário as instruções de configuração do DNS e espere a confirmação:
  • “Crie registros A/AAAA para que <domain> aponte para o IP do droplet.”
  • “Se storage.<domain> for usado, crie também um registro A/AAAA para ele.”
  • “Quando o DNS propagar, me avise e eu continuo. Não consigo ver a propagação, a menos que você peça para eu verificar a resolução.”
  • O agente pode verificar a propagação do DNS por conta própria usando ping -c 1 <domain> e comparando o IP com o do droplet. Se forem iguais, siga em frente.

7b. DNS de e-mail (SPF / DMARC / DKIM).

  • E-mails enviados de um domínio sem SPF e DMARC costumam ser descartados pelo Gmail e pelo Outlook quando o destinatário é novo, mesmo que o provedor de SMTP informe que foram entregues.
  • deployment create mostra um Warning: quando o domínio de --smtp-from não tem registro SPF, ou não tem registro DMARC em _dmarc.<domain> nem em um domínio pai. Isso não bloqueia a implantação. Nunca ignore o aviso: mostre-o ao usuário e passe os registros que ele deve adicionar:
    • <mail-domain> TXT v=spf1 include:<provider> ~all (o include exato vem do provedor de SMTP; junte ao registro SPF existente e nunca adicione um segundo)
    • _dmarc.<mail-domain> TXT v=DMARC1; p=none; rua=mailto:dmarc@<mail-domain>
    • DKIM: os registros <selector>._domainkey.<mail-domain> que o provedor de SMTP gera quando o domínio é verificado
  • Confira com dig +short TXT <mail-domain> e dig +short TXT _dmarc.<mail-domain>.
  • A CLI não consegue verificar o DKIM (o seletor depende do provedor). Sempre peça ao usuário que confirme que o DKIM está verificado no provedor de SMTP, mesmo quando o create não mostrou nenhum aviso. Com o Amazon SES e provedores parecidos, o SPF é verificado para o domínio de envelope do próprio provedor, então só o DKIM faz o DMARC passar. No SES: em Verified identities, abra <mail-domain> e veja a seção DKIM, que deve indicar Successful.
  1. Valide e informe o resultado.
  • Confira docker ps e os endpoints de saúde dos serviços.
  • Passe os dados finais de conexão e os próximos passos.

Fluxo de atualização por SSH

Quando o usuário pedir “atualizar o servidor”:

  1. Pergunte o host/IP de destino e o usuário/chave SSH.
  2. Rode wlycli deployment update --domain <domain> [--force-restart].
  3. Verifique o estado dos contêineres e do Nginx.

Recursos

  • Trechos e exemplos da API da DigitalOcean: references/digitalocean.md.

Segredos e flags

Use estes nomes de flag para os segredos:

  • Host do SMTP: --smtp-host
  • Usuário do SMTP: --smtp-user
  • Senha do SMTP: --smtp-password
  • Remetente do SMTP: --smtp-from
  • Endpoint do OTEL: --otel-endpoint
  • Cabeçalhos do OTEL: --otel-headers

Comando mínimo de criação

Flags obrigatórias:

  • --domain
  • --email
  • --smtp-host
  • --smtp-user
  • --smtp-password
  • --smtp-from

Exemplo mínimo:

wlycli deployment create \
  --domain example.com \
  --email admin@example.com \
  --smtp-host smtp.example.com \
  --smtp-user user \
  --smtp-password pass \
  --smtp-from noreply@example.com

Padrões do Postgres gerenciado (DigitalOcean e CLI)

Ao usar o Postgres gerenciado da DigitalOcean, não dependa dos padrões da CLI. Defina todas as flags --postgres-* explicitamente:

  • Padrões típicos da DO:
    • Porta: 25060
    • Banco: defaultdb
    • Usuário: doadmin
  • Padrões da CLI (se você omitir as flags):
    • Porta: 5432
    • Banco: wlsly
    • Usuário: wlsly

Notas de uso da CLI

  • Verificação de versão: wlycli -v ou wlycli --version (flag). Não existe um subcomando version.
  • Use --base-dir só se quiser um local diferente do padrão (o padrão é ~/.welley). A CLI cria o diretório se tiver permissão.
  • Execuções SSH não interativas devem incluir --email e as outras flags obrigatórias para evitar perguntas.
  • Se o usuário já tiver um binário da CLI no servidor (por exemplo, ~/wcli), use-o diretamente. Não mude o binário de lugar, a menos que peçam.
  • Copie os trechos exatamente como estão em references/digitalocean.md para todas as chamadas à API da DO. Não reescreva, não adapte e não improvise o parsing em Python: até pequenas mudanças (por exemplo, de escape ou de aspas) podem quebrar de um shell para outro.
  • Scripts remotos por SSH: use sempre ssh host 'bash -s' << 'EOF' (heredoc entre aspas). Nunca use ssh host "..." com aspas duplas, porque o zsh expande $(...) e [...] localmente antes de enviar ao host remoto.

Recuperação de falhas

Se deployment create falhar e você precisar tentar de novo:

  • Use wlycli deployment delete --domain <domain> --yes-please-delete-all-the-data para limpar.
  • O delete tenta limpar por meio de contêiner os arquivos que pertencem ao root. Se ainda assim falhar, remova o diretório do projeto dentro de --base-dir com permissões elevadas e rode de novo.

Teste prévio da porta 80 (opcional)

Se o certbot falhar, teste se a porta 80 está acessível antes de rodar de novo:

docker run --rm -d -p 80:80 --name test-http nginx:alpine
curl -s http://<domain>:80
docker rm -f test-http

Outros documentos