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

-   [**Welley CLI** docs/index.md](https://welley.com/it/administrators/docs/cli/)
-   [**Guida rapida: installazione minima di Welley** docs/quick-start.md](https://welley.com/it/administrators/docs/quick-start/)
-   [**openai.yaml** skills/deploy-server/agents/openai.yaml](https://welley.com/it/administrators/docs/deploy-server-openai-yaml/)
-   [**Riferimento DigitalOcean** skills/deploy-server/references/digitalocean.md](https://welley.com/it/administrators/docs/deploy-server-digitalocean/)
