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.
```

# Palvelimen käyttöönotto

## Yleiskuva

Tämä skill luo yhden instanssin Welley-pinon DigitalOceanissa ja osaa ajaa päivitykset SSH:n kautta. Se ohjaa agenttia keräämään puuttuvat tiedot, hakemaan saatavilla olevat instanssimallit määritellystä lähteestä, luomaan virtuaalikoneen, määrittämään isännän, ottamaan Welleyn käyttöön komennolla `wlycli deployment create` ja tarkistamaan lopputuloksen.

Komentojen nimien on vastattava CLI:tä:

-   `wlycli deployment create`
-   `wlycli deployment update`
-   `wlycli deployment delete`

## Oletukset (DigitalOcean)

-   Alue: `nyc3`
-   Levykuva: `latest LTS available via API` (haetaan osoitteesta `images?type=distribution`)
-   Dropletin nimi: arvotaan muodossa `wlsly-<adjective>-<surname>` (esim. `wlsly-bright-hopper`). Käytä nimigeneraattorin koodia tiedostosta `references/digitalocean.md`. Jos hallinnoitu tietokanta luodaan, käytä sille samaa nimeä.
-   Tilaustyyppi: Basic / Regular (Shared CPU)
-   Koko: 2 vCPU / 4 GB RAM / 80 GB SSD / 4 TB siirtoa (noin 24 $/kk)

## Oletusten muuttamisen sääntö

Jos käyttäjä määrittää jonkin oletuksen toisin (alue, levykuva, dropletin nimi, projekti, koko), agentin on:

1.  Toistettava muutos käyttäjälle sanatarkasti.
2.  Pyydettävä vahvistus ennen jatkamista.

## Vuorovaikutteisten kysymysten malli

Kysy vain se, mikä puuttuu. Käytä näitä täsmällisiä kysymyksiä, jotta väärinymmärryksiä syntyy vähemmän. Kysy vaiheittain. Kierros 1: enintään 2 kysymystä kerrallaan. Kierroksella 2 voi tarjota yhteisen vaihtoehdon ”hyväksy kaikki oletukset”. Jos ajoympäristö tukee valintoja, tarjoa jokaiseen kysymykseen 2 tai 3 vaihtoehtoa (A/B/C). Vältä vapaamuotoisia vastauksia, ellei se ole tarpeen.

Kierroksen 1 kysymykset (tunnistetiedot ja pääsy):

1.  ”Onko sinulla DigitalOcean API -tunnus käytettäväksi, vai odotanko, että annat sellaisen?”
2.  ”Mitä verkkotunnusta tämän palvelimen pitäisi käyttää (esim. `super-puper.example.com`)? Hallitsetko sen DNS-asetuksia?”
3.  ”Onko sinulla jo julkinen SSH-avain käytettäväksi, vai luonko ja lataanko sellaisen?”
4.  ”Haluatko liittää tämän dropletin olemassa olevaan DigitalOcean-projektiin? Jos haluat, kerro projektin nimi tai tunnus.”
5.  ”DNS-vaatimus: sinun täytyy luoda A/AAAA-tietueet osoitteille `<domain>` ja `storage.<domain>` (jos CDN:ää ei ole). Pystytkö tekemään sen ennen kuin certbot ajetaan?”
6.  ”Sähköpostin DNS-vaatimus: `--smtp-from`\-verkkotunnukselle tarvitaan SPF-, DMARC- ja DKIM-tietueet, muuten kutsu- ja vahvistussähköpostit uusille vastaanottajille voivat hävitä huomaamatta. Ovatko ne kunnossa, vai listaanko tietueet, joita SMTP-palveluntarjoajasi tarvitsee?”
7.  Jos käyttäjä kysyy, mistä DO-tunnuksen saa, anna tämä linkki:

```
https://cloud.digitalocean.com/account/api/tokens
```

Kierroksen 2 kysymykset (koko, sijainti ja käyttöönoton asetukset):

1.  ”Haluatko oletusalueen `nyc3` vai jonkin muun alueen?”
2.  ”Haluatko oletuskoon (2 vCPU / 2 GB) vai jonkin muun CPU- ja RAM-tavoitteen?”
3.  ”Käytänkö uusinta APIn kautta saatavilla olevaa Ubuntu LTS -versiota vai tiettyä Ubuntu-versiota?”
4.  ”Mitä SSH-käyttäjää käytetään alustuksen jälkeen (oletus: `wlsly`)? Voit pitää oletuksen.”
5.  ”Haluatko hallinnoidun Postgres-tietokannan vai paketin mukana tulevan Postgres-kontin?”
6.  Jos hallinnoitu Postgres valitaan: ”Mitä tietokannan aluetta ja kokoa käytän? Oletuksena voin käyttää aluetta `nyc3` ja kokoa 1 vCPU / 2 GB.”
7.  Jos hallinnoitu Postgres valitaan: ”Saanko jatkaa luomiseen palveluntarjoajan ilmoittamalla kuukausihinnalla?”
8.  ”Anna tarvittavat SMTP-asetukset (host, user, password, from). OTEL on valinnainen: anna se vain, jos tarvitset sitä.”
9.  ”Ylläpitäjän sähköpostiosoite vaaditaan luomiseen. Anna se nyt (lippu: `--email` / `-e`). Jos et anna sitä, pyydän sinua kirjoittamaan sen kahdesti varmistukseksi.”

Tarjoa kierroksella 2 vaihtoehtoa ”hyväksy kaikki oletukset”, jotta tietojen kerääminen sujuu nopeammin.

Jos jokin vastaus puuttuu, esitä tarkentava jatkokysymys (yksi tai kaksi kysymystä).

## Työnkulku (DigitalOcean, yksi instanssi)

1.  **Kerää tarvittavat tiedot (kysy, jos puuttuvat).**

-   DigitalOcean API -tunnus
-   Projektin nimi tai tunnus (valinnainen; jos puuttuu tai ei löydy, käytä oletusprojektia)
-   Alue
-   Instanssin kokotavoite (esim. 4 vCPU / 16 GB RAM)
-   Verkkotunnus
-   Julkinen SSH-avain (tai vahvistus siitä, että avain luodaan ja rekisteröidään)
-   Ylläpitäjän sähköpostiosoite ensimmäistä kirjautumista ja salasanan palautusta varten (vaaditaan luomiseen; `--email` / `-e`). Jos puuttuu, pyydä se kahdesti ja varmista, että ne täsmäävät.
-   Valinnainen: omat TLS-varmenteet vai certbot
-   Vahvistus DNS-pääsystä (A/AAAA-tietueiden luominen osoitteille `<domain>` ja tarvittaessa `storage.<domain>` täytyy onnistua)

1.  **Hae instanssityypit ja valitse koko.**

-   Käytä koodia tiedostosta `references/digitalocean.md`, jolla listaat koot ja suodatat ne CPU:n ja RAMin mukaan.
-   Jos vaihtoehtoja on useita, vahvista valinta käyttäjältä.

2b. **Selvitä Ubuntu-levykuvan slug.**

-   Kutsu `GET /v2/images?type=distribution&per_page=200` ja suodata Ubuntu-kuvat.
-   Jos käyttäjä pyysi tiettyä versiota, tarkista että sen slug on olemassa, ja vahvista valinta.
-   Muussa tapauksessa valitse listan uusin LTS-slug ja vahvista valinta käyttäjältä ennen luomista.

1.  **Luo droplet.**

-   Käytä DigitalOceanin APIa suoraan (doctl on valinnainen).
-   Levykuva: käytä ensisijaisesti käyttäjän määrittämää, muuten valitse APIn listan uusin LTS.
-   Liitä SSH-avaimen sormenjälki tai luo ja lataa avain.
-   Ota seuranta käyttöön.
-   Jos projektin nimi tai tunnus annettiin mutta sitä ei löytynyt, luo droplet ilman projektia (oletusprojektiin).
-   Huomio: hallinnoidun tietokannan voi luoda samaan aikaan dropletin kanssa.

## Töiden rinnakkaistaminen

Agentin pitäisi ajaa toisistaan riippumattomia tehtäviä limittäin, jotta kokonaisaika lyhenee:

-   Kun keräät tietoja käyttäjältä (kierros 2), aloita dropletin luominen, jos tunnus, alue, koko, levykuva ja SSH-avain on jo vahvistettu.
-   Kun droplet on luomisvaiheessa, aloita hallinnoidun Postgresin luominen (jos sitä pyydettiin).
-   Kun droplet käynnistyy, jatka jäljellä olevien tietojen keräämistä (SMTP, OTEL, ylläpitäjän sähköposti).
-   Jos jostakin vaiheesta puuttuu kriittinen tieto, keskeytä se vaihe ja jatka muita rinnakkain tehtäviä.
-   Jos DNS on DigitalOceanissa, luo tai päivitä A/AAAA-tietueet heti, kun dropletin IP-osoite on saatavilla (älä odota koko käyttöönottovaiheen valmistumista).

1.  **DNS ja verkkotunnus.**

-   Kysy, luodaanko tai päivitetäänkö DNS DigitalOceanissa vai jätetäänkö ulkopuolinen DNS ennalleen.
-   Jos käytät DigitalOceanin DNS:ää, luo A/AAAA-tietueet dropletin IP-osoitteeseen.

1.  **Määritä isäntä SSH:n kautta.**

-   Luo käyttäjä ilman root-oikeuksia (esim. `wlsly`), anna sille sudo-oikeudet ja kopioi SSH:n authorized keys -tiedot.
-   **Poistu rootista ja kirjaudu uudelleen sisään tavallisena käyttäjänä** ennen kuin jatkat.
-   Asenna Docker ja docker compose.
-   Hae Welley CLI -ohjelma AppStoresta ja tee siitä suoritettava:
    -   Perusosoite: `https://appstore.allroads.social/v1/social.wellesley.wlycli/latest?develop=stable&platform=<os>/<arch>`
    -   Valitse oikea `platform`\-arvo käyttöjärjestelmän ja arkkitehtuurin mukaan:
        -   Linux x86\_64: `linux/amd64`
        -   Linux arm64: `linux/arm64`
        -   macOS x86\_64: `darwin/amd64`
        -   macOS arm64: `darwin/arm64`
        -   Windows x86\_64: `windows/amd64`
    -   Esimerkki (Linux x86\_64):
        
        ```
        curl -fL 'https://appstore.allroads.social/v1/social.wellesley.wlycli/latest?develop=stable&platform=linux/amd64' -o wlycli
        chmod +x wlycli
        ```
        
    -   Odotettujen vastausotsikoiden joukossa on:
        -   `x-artifact-display-name: Welley CLI`
        -   `x-artifact-full-name: social.wellesley.wlycli`
        -   `x-artifact-kind: cli`
        -   `x-artifact-platform: <os>/<arch>`, esimerkiksi `linux/amd64`
        -   `x-artifact-sha256: <sha256>`
        -   `x-artifact-version: <version>`
        -   `x-channel: develop`
    -   Ennen asennusta tarkista otsikot mieluiten HEAD-pyynnöllä ja varmista, että artefaktin nimi, tyyppi, alusta ja kanava vastaavat pyydettyä ohjelmaa.
-   Tarkista CLI-ohjelma: aja `wlycli -v` ja `wlycli deployment --help` varmistaaksesi, että koontitiedot ovat odotetut.

1.  **Ota Welley käyttöön.**

-   Aja `wlycli deployment create` tarvittavilla asetuksilla.
-   Käytä yhden instanssin oletuksia (ei ulkoista Postgresia, ellei käyttäjä pyydä sitä).
-   Jos hallinnoitua Postgresia pyydetään, luo se ensin (DigitalOceanin tietokanta) ja käytä sitten palautettuja host-, port-, db-, user- ja password-arvoja `--postgres-*`\-lipuissa.
-   Jos tietokantakäyttäjän salasanaa ei palauteta APIsta tai käyttöliittymästä, nollaa tietokantakäyttäjän tunnistautuminen saadaksesi uudet tunnukset ennen kuin ajat `wlycli`\-komennon.
-   Ei-vuorovaikutteisissa ajoissa täytyy antaa `--email` / `-e`, muuten komento epäonnistuu.
-   `--base-dir` osoittaa ylähakemistoon. CLI luo projektin alihakemiston automaattisesti.
-   CLI ei suostu ajamaan, jos projektihakemisto tai kontit ovat jo olemassa. Ne on siivottava ennen uutta yritystä.

1.  **Varmenteet (pakollinen).**

-   Oletus: käytä Certbotin standalone-tilaa (ei-vuorovaikutteinen).
-   **Käyttäjän täytyy ohjata verkkotunnuksen (ja tarvittaessa `storage.<domain>`) A/AAAA-tietueet dropletin IP-osoitteeseen ennen kuin certbot ajetaan.**
-   CLI tukee lippuja `--public-ip` (ohittaa havaitun IP-osoitteen) ja `--skip-dns-preflight`, jos tarkistus on pakko ohittaa.
-   **Älä koskaan oleta, että DNS on määritetty. Kysy ja odota selkeää vahvistusta.**
-   **Älä koskaan käytä lippua `--skip-dns-preflight`, ellei käyttäjä erikseen pyydä sitä.**
-   Jos CDN:ää ei ole määritetty, certbotin varmennepyyntöön on sisällytettävä `storage.<domain>`.
-   Käytä itse allekirjoitettuja varmenteita vain, jos käyttäjä erikseen pyytää, ja anna silloin `--self-signed-certs` (luo itse allekirjoitetut varmenteet Go:lla).
-   Anna käyttäjälle DNS-asetusten ohjeet ja odota vahvistusta:
-   ”Luo A/AAAA-tietueet niin, että `<domain>` osoittaa dropletin IP-osoitteeseen.”
-   ”Jos käytät osoitetta `storage.<domain>`, luo sille myös A/AAAA-tietue.”
-   ”Kun DNS-muutokset ovat levinneet, kerro minulle, niin jatkan. En näe leviämistä, ellet pyydä minua tarkistamaan nimenselvitystä.”
-   Agentti voi tarkistaa DNS:n leviämisen itse komennolla `ping -c 1 <domain>` ja vertaamalla IP-osoitetta dropletin osoitteeseen. Jos ne täsmäävät, jatka.

7b. **Sähköpostin DNS (SPF / DMARC / DKIM).**

-   Jos verkkotunnuksella ei ole SPF- ja DMARC-tietueita, Gmail ja Outlook pudottavat sen viestit usein, kun vastaanottaja saa niitä ensimmäistä kertaa, vaikka SMTP-palveluntarjoaja ilmoittaa viestin toimitetuksi.
-   `deployment create` tulostaa `Warning:`\-varoituksen, kun `--smtp-from`\-verkkotunnuksella ei ole SPF-tietuetta tai kohdassa `_dmarc.<domain>` tai ylätason verkkotunnuksella ei ole DMARC-tietuetta. Varoitus ei estä käyttöönottoa. Älä koskaan ohita varoitusta: näytä se käyttäjälle ja anna lisättävät tietueet:
    -   `<mail-domain>` TXT `v=spf1 include:<provider> ~all` (tarkka include-arvo tulee SMTP-palveluntarjoajalta; yhdistä se olemassa olevaan SPF-tietueeseen, älä koskaan lisää toista)
    -   `_dmarc.<mail-domain>` TXT `v=DMARC1; p=none; rua=mailto:dmarc@<mail-domain>`
    -   DKIM: `<selector>._domainkey.<mail-domain>`\-tietueet, jotka SMTP-palveluntarjoaja luo, kun verkkotunnus vahvistetaan
-   Tarkista komennoilla `dig +short TXT <mail-domain>` ja `dig +short TXT _dmarc.<mail-domain>`.
-   CLI ei voi tarkistaa DKIM:ää (selector riippuu palveluntarjoajasta). Pyydä aina käyttäjää vahvistamaan, että DKIM on vahvistettu SMTP-palveluntarjoajalla, vaikka `create` ei olisi tulostanut varoitusta. Amazon SES:n ja vastaavien palveluntarjoajien kanssa SPF tarkistetaan palveluntarjoajan oman envelope-verkkotunnuksen osalta, joten vain DKIM voi saada DMARC-tarkistuksen läpi. SES:ssä kohdan _Verified identities_ alla olevan `<mail-domain>`\-tunnisteen DKIM-tilan on oltava _Successful_.

1.  **Tarkista ja raportoi.**

-   Tarkista `docker ps` ja palveluiden terveystarkistuspisteet.
-   Anna lopulliset yhteystiedot ja seuraavat vaiheet.

## Päivitys SSH:n kautta

Kun käyttäjä pyytää ”päivitä palvelin”:

1.  Kysy kohdeisäntä tai IP-osoite sekä SSH-käyttäjä ja avain.
2.  Aja `wlycli deployment update --domain <domain> [--force-restart]`.
3.  Tarkista konttien ja Nginxin tila.

## Lähteet

-   DigitalOcean API -koodiesimerkit: `references/digitalocean.md`.

## Salaiset tiedot ja liput

Käytä salaisille tiedoille näitä lippujen nimiä:

-   SMTP host: `--smtp-host`
-   SMTP user: `--smtp-user`
-   SMTP password: `--smtp-password`
-   SMTP from: `--smtp-from`
-   OTEL endpoint: `--otel-endpoint`
-   OTEL headers: `--otel-headers`

## Pienin mahdollinen create-komento

Pakolliset liput:

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

Pienin esimerkki:

```
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
```

## Hallinnoidun Postgresin oletukset (DigitalOcean ja CLI)

Kun käytät DigitalOceanin hallinnoitua Postgresia, älä luota CLI:n oletuksiin. Aseta kaikki `--postgres-*`\-liput erikseen:

-   DO:n tyypilliset oletukset:
    -   Portti: `25060`
    -   Tietokanta: `defaultdb`
    -   Käyttäjä: `doadmin`
-   CLI:n oletukset (jos jätät liput pois):
    -   Portti: `5432`
    -   Tietokanta: `wlsly`
    -   Käyttäjä: `wlsly`

## CLI:n käyttöohjeita

-   Version tarkistus: `wlycli -v` tai `wlycli --version` (lippu). `version`\-alikomentoa ei ole.
-   Käytä `--base-dir`\-lippua vain, jos haluat muun kuin oletussijainnin (oletus on `~/.welley`). CLI luo hakemiston, jos sillä on siihen oikeus.
-   Ei-vuorovaikutteisissa SSH-ajoissa tulee antaa `--email` ja kaikki tarvittavat liput, jotta kysymyksiltä vältytään.
-   Jos käyttäjä on tuonut CLI-ohjelman palvelimelle (esim. `~/wcli`), käytä sitä suoraan. Älä siirrä sitä muualle, ellei sitä pyydetä.
-   **Kopioi koodinpätkät sellaisenaan** tiedostosta `references/digitalocean.md` kaikkiin DO API -kutsuihin. Älä kirjoita Python-jäsennystä uudelleen, muokkaa sitä tai improvisoi sitä: pienetkin muutokset (esim. escapointi, lainausmerkit) voivat rikkoa sen eri shelleissä.
-   **SSH-etäskriptit:** Käytä aina muotoa `ssh host 'bash -s' << 'EOF'` (lainausmerkeillä suojattu heredoc). Älä koskaan käytä muotoa `ssh host "..."` kaksoislainausmerkeillä: zsh laajentaa `$(...)` ja `[...]` paikallisesti ennen kuin komento lähetetään etäisännälle.

## Virheistä toipuminen

Jos `deployment create` epäonnistuu ja sinun täytyy yrittää uudelleen:

-   Siivoa komennolla `wlycli deployment delete --domain <domain> --yes-please-delete-all-the-data`.
-   Delete-komento yrittää siivota rootin omistamat tiedostot konttien avulla. Jos se epäonnistuu silti, poista projektihakemisto kohdasta `--base-dir` korotetuilla oikeuksilla ja aja komento uudelleen.

## Portin 80 esitarkistus (valinnainen)

Jos certbot epäonnistuu, testaa portin 80 tavoitettavuus ennen uutta ajoa:

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

## Muut asiakirjat

-   [**Welley CLI** docs/index.md](https://welley.com/fi/administrators/docs/cli/)
-   [**Pikaopas: Welleyn minimiasennus** docs/quick-start.md](https://welley.com/fi/administrators/docs/quick-start/)
-   [**openai.yaml** skills/deploy-server/agents/openai.yaml](https://welley.com/fi/administrators/docs/deploy-server-openai-yaml/)
-   [**DigitalOcean-ohjeet** skills/deploy-server/references/digitalocean.md](https://welley.com/fi/administrators/docs/deploy-server-digitalocean/)
