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.

Розгортання сервера

Огляд

Ця навичка розгортає на DigitalOcean стек Welley з одним інстансом і може запускати оновлення через SSH. Вона підказує агенту, як зібрати відсутні дані, отримати доступні характеристики інстансів із визначеного джерела, створити віртуальну машину, налаштувати хост, розгорнути Welley командою wlycli deployment create і перевірити результат.

Назви команд мають збігатися з CLI:

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

Типові значення (DigitalOcean)

  • Регіон: nyc3
  • Образ: latest LTS available via API (визначається через images?type=distribution)
  • Назва дроплета: випадково згенерована у форматі wlsly-<adjective>-<surname> (наприклад, wlsly-bright-hopper). Скористайтеся фрагментом генератора назв із references/digitalocean.md. Якщо створюється керована база даних, використайте ту саму назву.
  • Цільовий тариф: Basic / Regular (Shared CPU)
  • Цільовий розмір: 2 vCPU / 4 GB RAM / 80 GB SSD / 4 TB трафіку (~$24/міс)

Правило зміни типових значень

Якщо користувач указує будь-яке з типових значень (регіон, образ, назва дроплета, проєкт, розмір), агент повинен:

  1. Дослівно повторити змінене значення.
  2. Попросити підтвердження, перш ніж продовжувати.

Шаблон інтерактивного введення

Запитуйте лише про те, чого бракує. Використовуйте саме ці формулювання, щоб уникнути двозначності. Запитуйте по колах. Коло 1: не більше 2 запитань за раз. У колі 2 можна запропонувати єдиний варіант «прийняти всі типові значення». Якщо середовище виконання підтримує вибір, пропонуйте 2 або 3 варіанти на запитання (A/B/C). Уникайте вільної форми, якщо вона не потрібна.

Запитання кола 1 (акаунт і доступ):

  1. «Чи є у вас токен DigitalOcean API, або мені зачекати, поки ви його надасте?»
  2. «Який домен має використовувати цей сервер (наприклад, super-puper.example.com)? Чи керуєте ви його DNS?»
  3. «Чи є у вас публічний SSH-ключ, який можна використати, або мені створити й завантажити новий?»
  4. «Чи хочете ви додати цей дроплет до наявного проєкту DigitalOcean? Якщо так, вкажіть назву або ID проєкту.»
  5. «Вимога до DNS: потрібно створити записи A/AAAA для <domain> і storage.<domain> (якщо немає CDN). Чи можете ви зробити це до запуску certbot?»
  6. «Вимога до DNS для пошти: для домену з --smtp-from потрібні записи SPF, DMARC і DKIM, інакше листи із запрошеннями та підтвердженнями для нових одержувачів можуть мовчки відкидатися. Вони вже налаштовані, чи показати вам записи, які потрібні вашому SMTP-провайдеру?»
  7. Якщо користувач питає, де взяти токен DO, дайте це посилання:
https://cloud.digitalocean.com/account/api/tokens

Запитання кола 2 (розмір, розташування та параметри розгортання):

  1. «Вам підійде типовий регіон nyc3 чи потрібен інший?»
  2. «Вам підійде типовий розмір (2 vCPU / 2 GB) чи потрібні інші параметри CPU/RAM?»
  3. «Використати останню LTS-версію Ubuntu, доступну в API, чи якусь конкретну версію Ubuntu?»
  4. «Якого користувача SSH використовувати після початкового налаштування (типово: wlsly)? Можна залишити типового.»
  5. «Вам потрібна керована база Postgres чи використати Postgres із комплектного контейнера?»
  6. Якщо обрано керований Postgres: «Який регіон і розмір бази використати? Можу типово взяти nyc3 і 1 vCPU / 2 GB.»
  7. Якщо обрано керований Postgres: «Чи продовжувати створення за місячною ціною, яку вказує провайдер?»
  8. «Вкажіть обов'язкові налаштування SMTP (host, user, password, from). OTEL необов'язковий, указуйте його лише за потреби.»
  9. «Для створення потрібна електронна адреса адміністратора. Вкажіть її зараз (прапорець: --email / -e). Якщо ви її не вкажете, я попрошу ввести її двічі для підтвердження.»

Запропонуйте в колі 2 варіант «прийняти всі типові значення», щоб пришвидшити збір даних.

Якщо якоїсь відповіді бракує, поставте цільове уточнювальне запитання (одне або два).

Порядок дій (DigitalOcean, один інстанс)

  1. Зберіть потрібні дані (запитайте, якщо чогось бракує).
  • Токен DigitalOcean API
  • Назва або ID проєкту (необов'язково; якщо не вказано або не знайдено, використайте типовий проєкт)
  • Регіон
  • Цільовий розмір інстансу (наприклад, 4 vCPU / 16 GB RAM)
  • Доменне ім'я
  • Публічний SSH-ключ (або згода створити й зареєструвати його)
  • Електронна адреса адміністратора для першого входу та відновлення пароля (обов'язкова для створення; --email / -e). Якщо її немає, попросіть ввести двічі й переконайтеся, що вони збігаються.
  • Необов'язково: власні TLS-сертифікати чи certbot
  • Підтвердження доступу до DNS (потрібно мати змогу створити записи A/AAAA для <domain> і, якщо використовується, для storage.<domain>)
  1. Отримайте типи інстансів і виберіть розмір.
  • Використайте фрагмент для розмірів із references/digitalocean.md, щоб отримати список і відфільтрувати його за CPU/RAM.
  • Якщо збігів кілька, уточніть у користувача.

2b. Визначте slug образу Ubuntu.

  • Викличте GET /v2/images?type=distribution&per_page=200 і відфільтруйте Ubuntu.
  • Якщо користувач просив конкретну версію, переконайтеся, що її slug існує, і підтвердіть вибір.
  • Інакше виберіть зі списку slug останньої LTS-версії та підтвердьте його з користувачем перед створенням.
  1. Створіть дроплет.
  • Використовуйте DigitalOcean API напряму (doctl необов'язковий).
  • Образ: віддавайте перевагу вказаному користувачем; інакше виберіть останню LTS зі списку API.
  • Додайте відбиток SSH-ключа або створіть і завантажте ключ.
  • Увімкніть моніторинг.
  • Якщо назву або ID проєкту вказано, але не знайдено, створіть дроплет без проєкту (у типовому проєкті).
  • Примітка: керовану базу даних можна створювати паралельно зі створенням дроплета.

Паралельне виконання

Агент має поєднувати незалежні завдання, щоб скоротити загальний час виконання:

  • Поки збираєте дані від користувача (коло 2), починайте створювати дроплет, якщо токен, регіон, розмір, образ і SSH-ключ уже підтверджені.
  • Поки дроплет розгортається, починайте створювати керований Postgres (якщо його просили).
  • Поки дроплет запускається, продовжуйте збирати решту даних (SMTP, OTEL, електронна адреса адміністратора).
  • Якщо для кроку бракує важливих даних, призупиніть цей крок і продовжуйте інші завдання, які можна виконувати паралельно.
  • Якщо DNS керується в DigitalOcean, створіть або оновіть записи A/AAAA, щойно стане відома IP-адреса дроплета (не чекайте кроку повного розгортання).
  1. DNS і домен.
  • Запитайте, чи створювати або оновлювати DNS у DigitalOcean, чи залишити зовнішній DNS.
  • Якщо використовується DNS DigitalOcean, створіть записи A/AAAA з IP-адресою дроплета.
  1. Налаштуйте хост через SSH.
  • Створіть користувача без прав root (наприклад, wlsly), надайте йому sudo і скопіюйте авторизовані SSH-ключі.
  • Вийдіть із root і знову увійдіть як цей користувач, перш ніж продовжувати.
  • Встановіть Docker і docker compose.
  • Завантажте бінарний файл Welley CLI з AppStore і зробіть його виконуваним:
    • Базова URL-адреса: https://appstore.allroads.social/v1/social.wellesley.wlycli/latest?develop=stable&platform=<os>/<arch>
    • Виберіть правильне значення platform за ОС і архітектурою:
      • Linux x86_64: linux/amd64
      • Linux arm64: linux/arm64
      • macOS x86_64: darwin/amd64
      • macOS arm64: darwin/arm64
      • Windows x86_64: windows/amd64
    • Приклад (Linux x86_64):
      curl -fL 'https://appstore.allroads.social/v1/social.wellesley.wlycli/latest?develop=stable&platform=linux/amd64' -o wlycli
      chmod +x wlycli
      
    • Очікувані заголовки відповіді містять:
      • x-artifact-display-name: Welley CLI
      • x-artifact-full-name: social.wellesley.wlycli
      • x-artifact-kind: cli
      • x-artifact-platform: <os>/<arch>, наприклад linux/amd64
      • x-artifact-sha256: <sha256>
      • x-artifact-version: <version>
      • x-channel: develop
    • Перш ніж встановлювати, краще перевірити заголовки запитом HEAD і переконатися, що назва артефакту, тип, платформа та канал збігаються із запитаним бінарним файлом.
  • Перевірте бінарний файл CLI: виконайте wlycli -v і wlycli deployment --help, щоб переконатися, що збірка очікувана.
  1. Розгорніть Welley.
  • Виконайте wlycli deployment create з потрібними параметрами.
  • Використовуйте типові налаштування для одного інстансу (без зовнішнього Postgres, якщо користувач не просить).
  • Якщо потрібен керований Postgres, спершу створіть його (база DigitalOcean), а потім використайте повернені host/port/db/user/password у прапорцях --postgres-*.
  • Якщо API чи інтерфейс не повертає пароль користувача бази, скиньте автентифікацію користувача бази, щоб отримати нові облікові дані, перш ніж запускати wlycli.
  • Неінтерактивні запуски мають передавати --email / -e, інакше команда завершиться помилкою.
  • --base-dir указує на батьківський каталог; CLI сам створює підкаталог проєкту.
  • CLI відмовляється працювати, якщо каталог проєкту або контейнери вже існують; перед повторною спробою потрібне очищення.
  1. Сертифікати (обов'язково).
  • Типово: використовуйте Certbot у режимі standalone (неінтерактивно).
  • Користувач має спрямувати записи DNS A/AAAA для домену (і для storage.<domain>, якщо він використовується) на IP дроплета до запуску certbot.
  • CLI підтримує --public-ip (перевизначити виявлену IP-адресу) і --skip-dns-preflight, якщо потрібно обійти перевірку.
  • Ніколи не вважайте, що DNS налаштовано. Запитайте й дочекайтеся явного підтвердження.
  • Ніколи не використовуйте --skip-dns-preflight, якщо користувач прямо цього не просить.
  • Якщо CDN не налаштовано, запит сертифіката certbot має містити storage.<domain>.
  • Використовуйте самопідписані сертифікати, лише якщо користувач прямо про це просить, і передайте --self-signed-certs (генерує самопідписані сертифікати на Go).
  • Надайте користувачу інструкції з налаштування DNS і дочекайтеся підтвердження:
  • «Створіть записи A/AAAA, щоб <domain> вказував на IP дроплета.»
  • «Якщо використовується storage.<domain>, створіть запис A/AAAA і для нього.»
  • «Коли DNS оновиться, повідомте мені, і я продовжу. Я не бачу, чи поширився DNS, поки ви не попросите мене перевірити розв'язання імені.»
  • Агент може сам перевірити поширення DNS командою ping -c 1 <domain> і порівняти IP з IP дроплета. Якщо вони збігаються, продовжуйте.

7b. DNS для пошти (SPF / DMARC / DKIM).

  • Лист із домену без SPF і DMARC часто відкидають Gmail та Outlook для нових одержувачів, навіть якщо SMTP-провайдер повідомляє, що його доставлено.
  • deployment create виводить Warning:, якщо для домену з --smtp-from немає запису SPF або немає запису DMARC у _dmarc.<domain> чи в батьківському домені. Це не блокує розгортання. Ніколи не ігноруйте попередження: покажіть його користувачу й дайте записи, які треба додати:
    • <mail-domain> TXT v=spf1 include:<provider> ~all (точне значення include надає SMTP-провайдер; додайте його до наявного запису SPF, ніколи не створюйте другий)
    • _dmarc.<mail-domain> TXT v=DMARC1; p=none; rua=mailto:dmarc@<mail-domain>
    • DKIM: записи <selector>._domainkey.<mail-domain>, які SMTP-провайдер генерує під час перевірки домену
  • Перевірте командами dig +short TXT <mail-domain> і dig +short TXT _dmarc.<mail-domain>.
  • CLI не може перевірити DKIM (селектор залежить від провайдера). Завжди просіть користувача підтвердити, що DKIM перевірено в SMTP-провайдера, навіть якщо create не вивів попередження. В Amazon SES та подібних провайдерів SPF перевіряється для власного домену конверта провайдера, тож пройти DMARC допоможе лише DKIM. В SES: розділ Verified identities, далі <mail-domain>, далі DKIM. Там має бути статус Successful.
  1. Перевірте й повідомте про результат.
  • Перевірте docker ps і кінцеві точки стану сервісів.
  • Надайте остаточні дані для підключення та наступні кроки.

Оновлення через SSH

Коли користувач просить «оновити сервер»:

  1. Запитайте адресу чи IP цільового хоста, а також користувача й ключ SSH.
  2. Виконайте wlycli deployment update --domain <domain> [--force-restart].
  3. Перевірте стан контейнерів і Nginx.

Ресурси

  • Фрагменти та приклади DigitalOcean API: references/digitalocean.md.

Секрети й прапорці

Використовуйте ці назви прапорців для секретів:

  • Хост SMTP: --smtp-host
  • Користувач SMTP: --smtp-user
  • Пароль SMTP: --smtp-password
  • Адреса відправника SMTP: --smtp-from
  • Кінцева точка OTEL: --otel-endpoint
  • Заголовки OTEL: --otel-headers

Мінімальна команда створення

Обов'язкові прапорці:

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

Мінімальний приклад:

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

Типові значення керованого Postgres (DigitalOcean і CLI)

Якщо ви використовуєте керований Postgres від DigitalOcean, не покладайтеся на типові значення CLI. Явно задайте всі прапорці --postgres-*:

  • Типові значення DO:
    • Порт: 25060
    • База даних: defaultdb
    • Користувач: doadmin
  • Типові значення CLI (якщо пропустити прапорці):
    • Порт: 5432
    • База даних: wlsly
    • Користувач: wlsly

Нотатки щодо використання CLI

  • Перевірка версії: wlycli -v або wlycli --version (прапорець). Підкоманди version немає.
  • Використовуйте --base-dir лише якщо потрібне нетипове розташування (типово ~/.welley). CLI створить каталог, якщо матиме дозвіл.
  • Неінтерактивні запуски через SSH мають містити --email і всі потрібні прапорці, щоб уникнути запитів.
  • Якщо користувач надає бінарний файл CLI на сервері (наприклад, ~/wcli), використовуйте його напряму. Не переміщуйте його, якщо не просять.
  • Копіюйте фрагменти дослівно із references/digitalocean.md для всіх викликів DO API. Не переписуйте, не адаптуйте й не імпровізуйте розбір у Python: навіть невеликі зміни (наприклад, екранування чи лапки) можуть ламатися в різних оболонках.
  • Віддалені скрипти SSH: завжди використовуйте ssh host 'bash -s' << 'EOF' (heredoc у лапках). Ніколи не використовуйте ssh host "..." з подвійними лапками: zsh розкриває $(...) і [...] локально, до надсилання на віддалений хост.

Відновлення після збою

Якщо deployment create завершується помилкою і потрібна повторна спроба:

  • Скористайтеся wlycli deployment delete --domain <domain> --yes-please-delete-all-the-data, щоб очистити залишки.
  • Команда delete спробує очистити файли, що належать root, через контейнер. Якщо це все одно не вдасться, видаліть каталог проєкту в --base-dir з підвищеними правами й запустіть команду знову.

Попередня перевірка порту 80 (необов'язково)

Якщо certbot завершується помилкою, перед повторним запуском перевірте доступність порту 80:

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

Інші документи