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.
部署服务器
概览
这个 skill 会在 DigitalOcean 上创建单实例的 Welley 服务,也可以通过 SSH 执行更新。它会引导 agent 收集缺少的输入信息,从指定来源获取可用的实例规格,创建虚拟机,配置主机,用 wlycli deployment create 完成部署,最后进行验证。
命令名称必须与 CLI 一致:
wlycli deployment createwlycli deployment updatewlycli deployment delete
默认值(DigitalOcean)
- 区域:
nyc3 - 镜像:
latest LTS available via API(通过images?type=distribution获取) - Droplet 名称:随机生成,格式为
wlsly-<adjective>-<surname>(例如wlsly-bright-hopper)。请使用references/digitalocean.md中的名称生成代码片段。如果创建托管数据库,数据库也使用同一个名称。 - 方案目标:Basic / Regular(共享 CPU)
- 规格目标:2 vCPU / 4 GB 内存 / 80 GB SSD / 4 TB 流量(约 $24/月)
覆盖默认值的规则
如果用户指定了任何默认值(区域、镜像、Droplet 名称、项目、规格),agent 必须:
- 把用户的修改内容原样复述一遍。
- 先请用户确认,再继续往下做。
交互式输入模板
只问缺少的信息。请使用下面这些原话提问,以减少歧义。 分几轮逐步提问。第 1 轮:每次最多问 2 个问题。第 2 轮可以给出一个打包的“全部使用默认值”选项。 如果运行环境支持选项,每个问题给出 2 到 3 个选项(A/B/C)。除非必要,避免开放式提问。
第 1 轮问题(身份与访问):
- “你有可以使用的 DigitalOcean API token 吗?还是我先等你提供?”
- “这台服务器要使用哪个域名(例如
super-puper.example.com)?这个域名的 DNS 由你管理吗?” - “你已经有可用的 SSH 公钥了吗?还是由我来创建并上传一个?”
- “要把这台 Droplet 放进已有的 DigitalOcean 项目吗?如果要,请提供项目名称或 ID。”
- “DNS 要求:你需要为
<domain>和storage.<domain>(没有 CDN 时)创建 A/AAAA 记录。你能在运行 certbot 之前完成吗?” - “邮件 DNS 要求:
--smtp-from的域名需要配置 SPF、DMARC 和 DKIM 记录,否则发给新收件人的邀请邮件和确认邮件可能会被悄悄丢弃。这些记录已经配好了吗?还是需要我列出你的 SMTP 服务商要求的记录?” - 如果用户问到在哪里获取 DO token,请提供这个链接:
https://cloud.digitalocean.com/account/api/tokens
第 2 轮问题(规格、位置和部署选项):
- “区域使用默认的
nyc3,还是换一个区域?” - “规格使用默认的 2 vCPU / 2 GB,还是换一个 CPU/内存目标?”
- “我使用 API 中最新的 Ubuntu LTS,还是你指定某个 Ubuntu 版本?”
- “引导完成后使用哪个 SSH 用户(默认:
wlsly)?可以保持默认。” - “你想用托管的 Postgres 数据库,还是用自带的 Postgres 容器?”
- 如果选择托管 Postgres:“数据库使用哪个区域和规格?我可以默认用
nyc3和 1 vCPU / 2 GB。” - 如果选择托管 Postgres:“要我按服务商列出的月费价格继续创建吗?”
- “请提供必需的 SMTP 设置(host、user、password、from)。OTEL 是可选的,需要时再提供。”
- “创建时必须提供管理员邮箱。请现在提供(参数:
--email/-e)。如果没有提供,我会让你输入两次来确认。”
在第 2 轮提供“全部使用默认值”的选项,加快收集输入的速度。
如果有任何回答缺失,就针对性地追问(一到两个问题)。
流程(DigitalOcean,单实例)
- 收集必需的输入信息(缺少就问)。
- DigitalOcean API token
- 项目名称或 ID(可选;缺少或找不到时使用默认项目)
- 区域
- 实例规格目标(例如 4 vCPU / 16 GB 内存)
- 域名
- SSH 公钥(或确认由我们创建并注册一个)
- 用于首次登录和找回密码的管理员邮箱(创建时必填;
--email/-e)。如果缺少,请让用户输入两次并确认一致。 - 可选:自定义 TLS 证书,或使用 certbot
- 确认有 DNS 操作权限(必须能为
<domain>创建 A/AAAA 记录,如果用到storage.<domain>,也要为它创建)
- 获取实例类型并选择规格。
- 使用
references/digitalocean.md中的规格代码片段,列出实例类型并按 CPU/内存筛选。 - 如果有多个匹配项,请向用户确认。
2b. 确定 Ubuntu 镜像 slug。
- 调用
GET /v2/images?type=distribution&per_page=200,筛选出 Ubuntu。 - 如果用户指定了版本,先确认这个 slug 存在,再向用户确认。
- 否则从列表中选最新的 LTS slug,创建之前先向用户确认。
- 创建 Droplet。
- 直接使用 DigitalOcean API(doctl 是可选的)。
- 镜像:优先使用用户指定的;否则从 API 列表中选最新的 LTS。
- 附上 SSH 密钥指纹,或者创建并上传一个密钥。
- 启用监控。
- 如果提供了项目名称/ID 但找不到,就不指定项目来创建 Droplet(使用默认项目)。
- 注意:托管数据库的创建可以和 Droplet 的创建同时进行。
并行处理指引
agent 应该让互不依赖的任务同时进行,以缩短总耗时:
- 在收集用户输入(第 2 轮)的同时,如果 token、区域、规格、镜像和 SSH 密钥都已确认,就可以开始创建 Droplet。
- Droplet 创建期间,开始创建托管 Postgres(如果用户需要)。
- Droplet 启动期间,继续收集剩下的输入(SMTP、OTEL、管理员邮箱)。
- 如果某一步缺少关键输入,就先暂停这一步,继续做其他可以并行的任务。
- 如果 DNS 在 DigitalOcean 上管理,一拿到 Droplet 的 IP 就创建/更新 A/AAAA 记录(不用等到完整的部署步骤)。
- DNS / 域名。
- 询问是在 DigitalOcean 创建或更新 DNS,还是继续使用外部 DNS。
- 如果使用 DigitalOcean DNS,创建指向 Droplet IP 的 A/AAAA 记录。
- 通过 SSH 配置主机。
- 创建一个非 root 用户(例如
wlsly),授予 sudo 权限,并复制 SSH authorized keys。 - 退出 root,用这个非 root 用户重新登录,然后再继续。
- 安装 Docker 和 docker compose。
- 从 AppStore 下载 Welley CLI 二进制文件,并设为可执行:
- 基础 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:
- 示例(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 CLIx-artifact-full-name: social.wellesley.wlyclix-artifact-kind: clix-artifact-platform: <os>/<arch>,例如linux/amd64x-artifact-sha256: <sha256>x-artifact-version: <version>x-channel: develop
- 安装之前,最好先用 HEAD 请求检查响应头,确认文件名称、类型、平台和渠道与要下载的二进制文件一致。
- 基础 URL:
- 验证 CLI 二进制文件:运行
wlycli -v和wlycli deployment --help,确认构建信息符合预期。
- 部署 Welley。
- 带上必需的选项运行
wlycli deployment create。 - 使用单实例的默认设置(除非用户要求,否则不使用外部 Postgres)。
- 如果用户要求托管 Postgres,先创建它(DigitalOcean 数据库),再把返回的 host/port/db/user/password 填入
--postgres-*参数。 - 如果 API/界面没有返回数据库用户的密码,请在运行
wlycli之前重置该数据库用户的认证信息,获取新的凭据。 - 非交互式运行必须传入
--email/-e,否则命令会失败。 --base-dir指向上级目录,CLI 会自动创建项目子目录。- 如果项目目录或容器已经存在,CLI 会拒绝运行;重试之前必须先清理。
- 证书(必需)。
- 默认:使用 Certbot 的 standalone 模式(非交互式)。
- 在运行 certbot 之前,用户必须把域名(如果用到
storage.<domain>,也包括它)的 DNS A/AAAA 记录指向 Droplet 的 IP。 - CLI 支持
--public-ip(覆盖检测到的 IP),如果必须绕过检查,还有--skip-dns-preflight。 - 不要假设 DNS 已经配置好。请询问用户,并等待明确的确认。
- 除非用户明确要求,否则不要使用
--skip-dns-preflight。 - 如果没有配置 CDN,certbot 的证书申请必须包含
storage.<domain>。 - 只有在用户明确要求时才使用自签名证书,并传入
--self-signed-certs(用 Go 生成自签名证书)。 - 向用户提供 DNS 设置说明,并等待确认:
- “请创建 A/AAAA 记录,让
<domain>解析到 Droplet 的 IP。” - “如果用到
storage.<domain>,也请为它创建 A/AAAA 记录。” - “DNS 生效后告诉我,我再继续。除非你让我验证解析结果,否则我看不到 DNS 是否已经生效。”
- agent 也可以自己验证 DNS 是否生效:运行
ping -c 1 <domain>,并把得到的 IP 与 Droplet 的 IP 比对。如果一致,就继续。
7b. 邮件 DNS(SPF / DMARC / DKIM)。
- 来自没有配置 SPF 和 DMARC 的域名的邮件,发给首次收件人时常常会被 Gmail 和 Outlook 丢弃,即使 SMTP 服务商显示已送达。
- 当
--smtp-from的域名没有 SPF 记录,或者在_dmarc.<domain>或上级域名下没有 DMARC 记录时,deployment create会打印一条Warning:。它不会阻止部署。不要忽略这条警告:要把它展示给用户,并告诉用户需要添加哪些记录:<mail-domain>TXTv=spf1 include:<provider> ~all(具体的 include 由 SMTP 服务商提供;如果已有 SPF 记录,就合并进去,不要再添加第二条)_dmarc.<mail-domain>TXTv=DMARC1; p=none; rua=mailto:dmarc@<mail-domain>- DKIM:域名验证时由 SMTP 服务商生成的
<selector>._domainkey.<mail-domain>记录
- 用
dig +short TXT <mail-domain>和dig +short TXT _dmarc.<mail-domain>检查。 - CLI 无法检查 DKIM(selector 因服务商而异)。即使
create没有打印警告,也一定要请用户确认 DKIM 已在 SMTP 服务商处验证通过。对于 Amazon SES 和类似的服务商,SPF 检查的是服务商自己的 envelope 域名,所以只有 DKIM 才能让 DMARC 通过。在 SES 中:Verified identities ><mail-domain>> DKIM 必须显示为 Successful。
- 验证并汇报。
- 检查
docker ps和各服务的健康检查端点。 - 提供最终的连接信息和后续步骤。
SSH 更新流程
当用户要求“更新服务器”时:
- 询问目标主机/IP,以及 SSH 用户和密钥。
- 运行
wlycli deployment update --domain <domain> [--force-restart]。 - 检查容器和 Nginx 的状态。
资源
- DigitalOcean API 代码片段和示例:
references/digitalocean.md。
密钥对应的参数
密钥类信息请使用下面这些参数名:
- SMTP host:
--smtp-host - SMTP user:
--smtp-user - SMTP password:
--smtp-password - SMTP from:
--smtp-from - OTEL endpoint:
--otel-endpoint - OTEL headers:
--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)
使用 DigitalOcean 托管 Postgres 时,不要依赖 CLI 的默认值。请明确设置所有 --postgres-* 参数:
- DO 的典型默认值:
- 端口:
25060 - 数据库:
defaultdb - 用户:
doadmin
- 端口:
- CLI 的默认值(省略参数时):
- 端口:
5432 - 数据库:
wlsly - 用户:
wlsly
- 端口:
CLI 使用说明
- 检查版本:
wlycli -v或wlycli --version(参数形式)。没有version子命令。 - 只有想使用非默认位置时才需要
--base-dir(默认是~/.welley)。如果有权限,CLI 会自动创建这个目录。 - 通过 SSH 非交互式运行时,应带上
--email和其他必需的参数,避免出现提示。 - 如果用户已经在服务器上放了 CLI 二进制文件(例如
~/wcli),就直接使用它。除非用户要求,否则不要移动它。 - 所有 DO API 调用都要原样复制
references/digitalocean.md中的代码片段。不要重写、改编或临时发挥 Python 解析部分,哪怕是很小的改动(例如转义、引号),在不同的 shell 里也可能出错。 - 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