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.

Deploy del server

Panoramica

Questa skill crea uno stack Welley a istanza singola su DigitalOcean e può eseguire aggiornamenti via SSH. Guida l'agente a raccogliere gli input mancanti, recuperare le specifiche delle istanze disponibili da una fonte definita, creare la VM, configurare l'host, fare il deploy con wlycli deployment create e validare il risultato.

I nomi dei comandi devono corrispondere a quelli della CLI:

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

Valori predefiniti (DigitalOcean)

  • Regione: nyc3
  • Immagine: latest LTS available via API (risolvila con images?type=distribution)
  • Nome del droplet: generato a caso come wlsly-<adjective>-<surname> (es. wlsly-bright-hopper). Usa lo snippet del generatore di nomi in references/digitalocean.md. Se viene creato un database gestito, usa lo stesso nome anche per quello.
  • Piano di riferimento: Basic / Regular (Shared CPU)
  • Dimensione di riferimento: 2 vCPU / 4 GB RAM / 80 GB SSD / 4 TB di trasferimento (~$24/mese)

Regola per modificare i valori predefiniti

Se l'utente specifica uno qualsiasi dei valori predefiniti (regione, immagine, nome del droplet, progetto, dimensione), l'agente deve:

  1. Ripetere all'utente la modifica parola per parola.
  2. Chiedere conferma prima di procedere.

Modello per raccogliere gli input

Chiedi solo ciò che manca. Usa esattamente queste domande, per ridurre le ambiguità. Procedi a round successivi. Round 1: massimo 2 domande per turno. Il round 2 può proporre un'unica opzione “accetta tutti i valori predefiniti”. Se l'ambiente supporta le scelte, proponi 2 o 3 opzioni per domanda (A/B/C). Evita le risposte libere se non sono necessarie.

Domande del round 1 (credenziali e accesso):

  1. “Hai un token API di DigitalOcean da usare, o devo aspettare che tu me ne fornisca uno?”
  2. “Quale dominio deve usare questo server (es. super-puper.example.com)? Gestisci tu il suo DNS?”
  3. “Hai già una chiave pubblica SSH da usare, o devo crearne e caricarne una io?”
  4. “Vuoi assegnare questo droplet a un progetto DigitalOcean esistente? Se sì, indicami il nome o l'ID del progetto.”
  5. “Requisito DNS: devi creare record A/AAAA per <domain> e storage.<domain> (se non c'è una CDN). Puoi farlo prima che parta certbot?”
  6. “Requisito DNS per le email: il dominio di --smtp-from ha bisogno di record SPF, DMARC e DKIM, altrimenti le email di invito e di conferma ai nuovi destinatari potrebbero essere scartate senza alcun avviso. Sono già a posto, o vuoi che ti elenchi i record che servono al tuo provider SMTP?”
  7. Se l'utente chiede dove ottenere un token DO, fornisci questo link:
https://cloud.digitalocean.com/account/api/tokens

Domande del round 2 (dimensione, posizione e opzioni di deploy):

  1. “Vuoi la regione predefinita nyc3 o un'altra regione?”
  2. “Vuoi la dimensione predefinita (2 vCPU / 2 GB) o un altro obiettivo di CPU/RAM?”
  3. “Uso l'ultima Ubuntu LTS disponibile nell'API o una versione specifica di Ubuntu?”
  4. “Quale utente SSH dobbiamo usare dopo il bootstrap (predefinito: wlsly)? Puoi tenere quello predefinito.”
  5. “Vuoi un database Postgres gestito, o preferisci usare il container Postgres incluso?”
  6. Se è stato scelto il Postgres gestito: “Quale regione e quale dimensione devo usare per il database? Posso usare nyc3 e 1 vCPU / 2 GB come valori predefiniti.”
  7. Se è stato scelto il Postgres gestito: “Vuoi che proceda con la creazione al prezzo mensile indicato dal provider?”
  8. “Indicami le impostazioni SMTP obbligatorie (host, utente, password, mittente). OTEL è facoltativo: indicalo solo se serve.”
  9. “L'email dell'amministratore è obbligatoria per la creazione. Indicala ora (flag: --email / -e). Se non me la dai, te la chiederò due volte per conferma.”

Offri un'opzione “accetta tutti i valori predefiniti” nel round 2 per velocizzare la raccolta degli input.

Se manca qualche risposta, fai una domanda di approfondimento mirata (una o due domande).

Flusso di lavoro (DigitalOcean, istanza singola)

  1. Raccogli gli input necessari (chiedi se mancano).
  • Token API di DigitalOcean
  • Nome o ID del progetto (facoltativo; se manca o non viene trovato, usa il progetto predefinito)
  • Regione
  • Dimensione dell'istanza (es. 4 vCPU / 16 GB RAM)
  • Nome di dominio
  • Chiave pubblica SSH (o conferma per crearne e registrarne una)
  • Email dell'amministratore per il primo accesso e il recupero della password (obbligatoria per create; --email / -e). Se manca, chiedila due volte e verifica che coincidano.
  • Facoltativo: certificati TLS personalizzati invece di certbot
  • Conferma dell'accesso al DNS (deve essere possibile creare record A/AAAA per <domain> e, se usato, per storage.<domain>)
  1. Recupera i tipi di istanza e scegli una dimensione.
  • Usa lo snippet delle dimensioni in references/digitalocean.md per elencare le istanze e filtrarle per CPU/RAM.
  • Se ci sono più corrispondenze, chiedi conferma all'utente.

2b. Individua lo slug dell'immagine Ubuntu.

  • Chiama GET /v2/images?type=distribution&per_page=200 e filtra per Ubuntu.
  • Se l'utente ha chiesto una versione specifica, verifica che il suo slug esista e chiedi conferma.
  • Altrimenti scegli dall'elenco lo slug dell'ultima LTS e chiedi conferma all'utente prima della creazione.
  1. Crea il droplet.
  • Usa direttamente l'API di DigitalOcean (doctl è facoltativo).
  • Immagine: preferisci quella indicata dall'utente, altrimenti scegli l'ultima LTS dall'elenco dell'API.
  • Collega l'impronta della chiave SSH oppure crea e carica una chiave.
  • Attiva il monitoraggio.
  • Se sono stati forniti il nome o l'ID del progetto ma il progetto non è stato trovato, crea il droplet senza progetto (progetto predefinito).
  • Nota: la creazione del database gestito può avvenire in parallelo a quella del droplet.

Indicazioni sulla parallelizzazione

L'agente deve sovrapporre i task indipendenti per ridurre i tempi complessivi:

  • Mentre raccogli gli input dell'utente (round 2), avvia la creazione del droplet se token, regione, dimensione, immagine e chiave SSH sono già confermati.
  • Mentre il droplet è in fase di provisioning, avvia la creazione del Postgres gestito (se richiesto).
  • Mentre il droplet si avvia, continua a raccogliere gli input rimanenti (SMTP, OTEL, email dell'amministratore).
  • Se per un passaggio manca un input critico, metti in pausa quel passaggio e prosegui con gli altri task che si possono fare in parallelo.
  • Se il DNS è gestito su DigitalOcean, crea o aggiorna i record A/AAAA appena l'IP del droplet è disponibile (non aspettare il passaggio di deploy completo).
  1. DNS / dominio.
  • Chiedi se creare o aggiornare il DNS su DigitalOcean oppure lasciare il DNS esterno.
  • Se usi il DNS di DigitalOcean, crea record A/AAAA che puntano all'IP del droplet.
  1. Configura l'host via SSH.
  • Crea un utente non root (es. wlsly), concedigli sudo e copia le chiavi SSH autorizzate.
  • Esci da root e rientra come utente non root prima di continuare.
  • Installa Docker + docker compose.
  • Scarica da AppStore il binario della CLI di Welley e rendilo eseguibile:
    • URL di base: https://appstore.allroads.social/v1/social.wellesley.wlycli/latest?develop=stable&platform=<os>/<arch>
    • Scegli il valore corretto di platform in base a sistema operativo e architettura:
      • Linux x86_64: linux/amd64
      • Linux arm64: linux/arm64
      • macOS x86_64: darwin/amd64
      • macOS arm64: darwin/arm64
      • Windows x86_64: windows/amd64
    • Esempio (Linux x86_64):
      curl -fL 'https://appstore.allroads.social/v1/social.wellesley.wlycli/latest?develop=stable&platform=linux/amd64' -o wlycli
      chmod +x wlycli
      
    • Le intestazioni di risposta attese includono:
      • x-artifact-display-name: Welley CLI
      • x-artifact-full-name: social.wellesley.wlycli
      • x-artifact-kind: cli
      • x-artifact-platform: <os>/<arch>, ad esempio linux/amd64
      • x-artifact-sha256: <sha256>
      • x-artifact-version: <version>
      • x-channel: develop
    • Prima di installare, è meglio controllare le intestazioni con una richiesta HEAD e verificare che nome dell'artefatto, tipo, piattaforma e canale corrispondano al binario richiesto.
  • Verifica il binario della CLI: esegui wlycli -v e wlycli deployment --help per confermare le informazioni di build attese.
  1. Fai il deploy di Welley.
  • Esegui wlycli deployment create con le opzioni necessarie.
  • Usa i valori predefiniti per l'istanza singola (nessun Postgres esterno, a meno che l'utente lo chieda).
  • Se è richiesto un Postgres gestito, crealo prima (database DigitalOcean) e poi usa host/porta/db/utente/password restituiti nei flag --postgres-*.
  • Se la password dell'utente del database non viene restituita dall'API o dall'interfaccia, reimposta l'autenticazione dell'utente del database per ottenere credenziali nuove prima di eseguire wlycli.
  • Le esecuzioni non interattive devono passare --email / -e, altrimenti il comando fallisce.
  • --base-dir indica la directory padre; la CLI crea da sola la sottodirectory del progetto.
  • La CLI si rifiuta di partire se la directory del progetto o i container esistono già: prima di riprovare serve una pulizia.
  1. Certificati (obbligatori).
  • Impostazione predefinita: usa Certbot in modalità standalone (non interattiva).
  • L'utente deve far puntare all'IP del droplet i record DNS A/AAAA del dominio (e di storage.<domain>, se usato) prima che parta certbot.
  • La CLI supporta --public-ip (sostituisce l'IP rilevato) e --skip-dns-preflight se devi saltare il controllo.
  • Non dare mai per scontato che il DNS sia configurato. Chiedi e aspetta una conferma esplicita.
  • Non usare mai --skip-dns-preflight, a meno che l'utente lo chieda esplicitamente.
  • Se la CDN non è configurata, certbot deve includere storage.<domain> nella richiesta del certificato.
  • Usa certificati autofirmati solo se l'utente lo chiede esplicitamente, e passa --self-signed-certs (genera certificati autofirmati in Go).
  • Dai all'utente le istruzioni per configurare il DNS e aspetta la conferma:
  • “Crea record A/AAAA in modo che <domain> punti all'IP del droplet.”
  • “Se usi storage.<domain>, crea un record A/AAAA anche per quello.”
  • “Quando il DNS si è propagato, scrivimelo e io continuo. Non posso vedere la propagazione, a meno che tu non mi chieda di verificare la risoluzione.”
  • L'agente può verificare da solo la propagazione del DNS con ping -c 1 <domain>, confrontando l'IP con quello del droplet. Se coincide, procede.

7b. DNS per le email (SPF / DMARC / DKIM).

  • Le email inviate da un dominio senza SPF e DMARC vengono spesso scartate da Gmail e Outlook quando il destinatario le riceve per la prima volta, anche se il provider SMTP le segnala come consegnate.
  • deployment create stampa un Warning: quando il dominio di --smtp-from non ha un record SPF, oppure non ha un record DMARC in _dmarc.<domain> o in un dominio padre. Non blocca il deploy. Non ignorare mai l'avviso: mostralo all'utente e dagli i record da aggiungere:
    • <mail-domain> TXT v=spf1 include:<provider> ~all (l'include esatto dipende dal provider SMTP; unisci il valore a un record SPF già esistente e non aggiungerne mai un secondo)
    • _dmarc.<mail-domain> TXT v=DMARC1; p=none; rua=mailto:dmarc@<mail-domain>
    • DKIM: i record <selector>._domainkey.<mail-domain> che il provider SMTP genera quando il dominio viene verificato
  • Controlla con dig +short TXT <mail-domain> e dig +short TXT _dmarc.<mail-domain>.
  • La CLI non può controllare DKIM (il selector dipende dal provider). Chiedi sempre all'utente di confermare che DKIM sia verificato presso il provider SMTP, anche quando create non ha stampato nessun avviso. Con Amazon SES e provider simili, SPF viene controllato sul dominio envelope del provider stesso, quindi solo DKIM può far passare DMARC. In SES, apri Verified identities e poi <mail-domain>: la voce DKIM deve risultare Successful.
  1. Verifica e riepiloga.
  • Controlla docker ps e gli endpoint di stato dei servizi.
  • Fornisci i dettagli finali di connessione e i passi successivi.

Aggiornamento via SSH

Quando l'utente chiede “aggiorna il server”:

  1. Chiedi host/IP di destinazione e utente/chiave SSH.
  2. Esegui wlycli deployment update --domain <domain> [--force-restart].
  3. Verifica lo stato dei container e di Nginx.

Risorse

  • Snippet ed esempi dell'API di DigitalOcean: references/digitalocean.md.

Flag per i segreti

Usa questi nomi di flag per i segreti:

  • Host SMTP: --smtp-host
  • Utente SMTP: --smtp-user
  • Password SMTP: --smtp-password
  • Mittente SMTP: --smtp-from
  • Endpoint OTEL: --otel-endpoint
  • Header OTEL: --otel-headers

Comando create minimo

Flag obbligatori:

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

Esempio minimo:

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

Valori predefiniti del Postgres gestito (DigitalOcean e CLI)

Quando usi il Postgres gestito di DigitalOcean, non fare affidamento sui valori predefiniti della CLI. Imposta esplicitamente tutti i flag --postgres-*:

  • Valori predefiniti tipici di DO:
    • Porta: 25060
    • Database: defaultdb
    • Utente: doadmin
  • Valori predefiniti della CLI (se ometti i flag):
    • Porta: 5432
    • Database: wlsly
    • Utente: wlsly

Note sull'uso della CLI

  • Controllo della versione: wlycli -v oppure wlycli --version (flag). Non esiste un sottocomando version.
  • Usa --base-dir solo se vuoi una posizione diversa da quella predefinita (il valore predefinito è ~/.welley). La CLI crea la directory se ha i permessi.
  • Le esecuzioni SSH non interattive devono includere --email e tutti i flag necessari, per evitare le richieste.
  • Se l'utente fornisce un binario della CLI sul server (es. ~/wcli), usalo direttamente. Non spostarlo, a meno che ti venga chiesto.
  • Copia gli snippet alla lettera da references/digitalocean.md per tutte le chiamate all'API di DO. Non riscrivere, adattare o improvvisare il parsing Python: anche piccole modifiche (es. escaping o virgolette) possono smettere di funzionare su shell diverse.
  • Script remoti via SSH: usa sempre ssh host 'bash -s' << 'EOF' (heredoc tra apici). Non usare mai ssh host "..." con le virgolette doppie: zsh espande $(...) e [...] in locale prima di inviarli all'host remoto.

Recupero dopo un errore

Se deployment create fallisce e devi riprovare:

  • Usa wlycli deployment delete --domain <domain> --yes-please-delete-all-the-data per fare pulizia.
  • Delete prova a pulire tramite container i file che appartengono a root. Se fallisce ancora, rimuovi la directory del progetto sotto --base-dir con permessi elevati e riesegui il comando.

Test preliminare della porta 80 (facoltativo)

Se certbot fallisce, prima di riprovare verifica che la porta 80 sia raggiungibile:

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

Altri documenti