Files
vps-manager/deploy/setup.sh
T
gouki 46faadbcae feat(multicloud): 补齐上线前的多云管理缺口(适配器/动作层/DNS/定时同步)
评估发现项目只有台账能力,缺失真正的多云管理链路。本次按缺口逐项补齐:

适配层
- 新增 aws / linode / namesilo 适配器,registry 登记;阿里云、腾讯云补
  list_domains 与 get_account 余额
- NormalizedVPS 补 expiry_date + charge_type:此前云端同步进来的 VPS 拿不到
  到期日,永远进不了续费提醒——而续费提醒正是这套台账存在的理由
- base.py 统一云端错误可读化(http_error_message / cloud_error_text):各厂商
  把原因放的位置都不同(Linode errors[].reason、Cloudflare errors[].message、
  腾讯 Response.Error.Message、AWS XML),此前直接 str(e) 会把 httpx 的多行文本
  连同 MDN 链接弹给用户

动作层与 DNS
- 新增 /api/actions:实例启停/重启/续费,写操作全部二次确认 + 审计
- 新增 Cloudflare DNS 记录的增删改查

定时同步
- scripts/sync_all_assets.py + /api/sync/assets + vps-sync-assets.timer(08:30)
- 08:30 而非随机时刻:必须早于 09:00 的续费检查,否则提醒读到上一天的旧到期日
- sync_all_assets 修正计数:每一项子同步都失败时不再计为「成功」,否则凭证过期
  会显示「成功 1」,用户以为数据拉到了、实际一条没有

数据一致性
- AssetRead 输出 external_id(只出不进):前端「云操作」「DNS」按钮靠它渲染,
  缺了则所有按钮永远出不来
- import_assets 落库 external_id:导出带了去重键而导入丢弃,会让迁移后首次同步
  把所有云端资产当新增再建一份
- _align_preset_providers 取代 _backfill_provider_services:库里声明但注册表未
  实现的 sdk_type 清空(声明支持却不支持,比明说不支持更糟),services 只增量
  补标签不覆盖,用户自建平台不动

前端如实展示
- cost 为 0 统一显示「未填」而非「0 USD」:0 既可能是没填、也可能是云端不返回
  价格,而汇总处又把 0 当「无费用」排除,两处口径不一致
- 总览「本年支出」增加 year_cost_missing,把合计的覆盖缺口说出来
- DNS 弹窗补 MX/SRV 优先级与备注;列表请求失败时 provider 用资产自带 slug 兜底,
  否则 Cloudflare 代理勾选框永远不出现

测试:257 -> 309 passed
2026-10-12 00:43:37 +00:00

110 lines
4.4 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# vps-manager 一键部署脚本(在新服务器上运行)
#
# 用法(在新服务器以 root 运行):
# sudo bash setup.sh
# 可选环境变量:
# GITEA_REPO 代码仓库地址(默认 git@gitea.neatcn.com:gouki/vps-manager.git)
# APP_DIR 部署目录(默认 /opt/vps-manager)
#
# 前置要求:
# 1. 新服务器已安装 tailscale 并连入 tailnet(用于内网访问)
# 2. 新服务器已配置可访问 Gitea 的 SSH deploy key(读权限),
# 或将 GITEA_REPO 改为 HTTPS + token 形式
#
# 脚本会自动完成:
# 系统依赖 -> 克隆/更新代码 -> venv + Python 依赖 -> 生成 .env(含 MASTER_KEY)
# -> 配置 systemd 服务与全部 timer -> 启动服务
set -euo pipefail
APP_DIR="${APP_DIR:-/opt/vps-manager}"
GITEA_REPO="${GITEA_REPO:-git@gitea.neatcn.com:gouki/vps-manager.git}"
echo "==> [1/6] 安装系统依赖"
apt-get update -q
apt-get install -y -q python3 python3-venv git curl
echo "==> [2/6] 克隆 / 更新代码到 $APP_DIR"
if [ ! -d "$APP_DIR/.git" ]; then
git clone "$GITEA_REPO" "$APP_DIR"
fi
cd "$APP_DIR"
git pull --ff-only
echo "==> [3/6] 创建虚拟环境并安装 Python 依赖"
python3 -m venv .venv
.venv/bin/pip install -q --upgrade pip
.venv/bin/pip install -q -r requirements.txt
echo "==> [4/6] 生成 .env(若不存在)"
if [ ! -f .env ]; then
MASTER_KEY="$(.venv/bin/python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())")"
# API_KEY / AGENT_KEY 默认生成强随机值:留空时 Agent 上报接口对任意来源放行
# (require_agent_key 未配 key 即全放),而服务默认监听 0.0.0.0,
# 公网上任何人都能伪造监控数据上报
API_KEY="$(.venv/bin/python -c "import secrets; print(secrets.token_urlsafe(32))")"
AGENT_KEY="$(.venv/bin/python -c "import secrets; print(secrets.token_urlsafe(32))")"
cat > .env <<EOF
APP_NAME=VPS 资产管理系统
API_KEY=$API_KEY
AGENT_KEY=$AGENT_KEY
MASTER_KEY=$MASTER_KEY
TELEGRAM_BOT_TOKEN=
TELEGRAM_CHAT_ID=
SMTP_HOST=
SMTP_PORT=465
SMTP_USER=
SMTP_PASSWORD=
SMTP_FROM=
SMTP_TO=
RENEWAL_THRESHOLD_DAYS=30
S3_ENDPOINT_URL=
S3_ACCESS_KEY=
S3_SECRET_KEY=
S3_BUCKET=
S3_PREFIX=vps-manager
S3_REGION=auto
EOF
chmod 600 .env
echo " 已生成 .env(MASTER_KEY / API_KEY / AGENT_KEY 均自动生成,请妥善保管)"
echo " - API_KEY:填入前端「设置」后,外部(非 tailnet/本机)来源的写操作才能通过鉴权"
echo " - AGENT_KEY:需写入各 VPS 的 /etc/vps-agent.env(VPS_AGENT_KEY),否则 Agent 上报会 401"
else
echo " .env 已存在,跳过生成"
fi
echo "==> [5/6] 配置 systemd 服务与定时器"
cp deploy/vps-manager.service /etc/systemd/system/
cp deploy/vps-manager-update.service deploy/vps-manager-update.timer /etc/systemd/system/
cp deploy/vps-backup-assets.service deploy/vps-backup-assets.timer /etc/systemd/system/
cp deploy/vps-backup-metrics.service deploy/vps-backup-metrics.timer /etc/systemd/system/
cp deploy/vps-sync-ai.service deploy/vps-sync-ai.timer /etc/systemd/system/
cp deploy/vps-sync-assets.service deploy/vps-sync-assets.timer /etc/systemd/system/
cp deploy/vps-renewal-check.service deploy/vps-renewal-check.timer /etc/systemd/system/
cp deploy/vps-cert-check.service deploy/vps-cert-check.timer /etc/systemd/system/
systemctl daemon-reload
systemctl enable --now vps-manager
systemctl enable --now vps-manager-update.timer
systemctl enable --now vps-backup-assets.timer vps-backup-metrics.timer
# vps-sync-assets 必须 enable:它 08:30 跑,早于 09:00 的续费检查,漏了会让提醒读到旧到期日
systemctl enable --now vps-sync-ai.timer vps-sync-assets.timer vps-renewal-check.timer vps-cert-check.timer
echo "==> [6/6] 验证服务状态"
sleep 3
if systemctl is-active --quiet vps-manager; then
echo " vps-manager 服务运行正常"
else
echo " 警告:服务未正常运行,请检查 journalctl -u vps-manager"
fi
echo ""
echo "=========================================="
echo "部署完成!"
echo " 当前版本: v$(cat VERSION 2>/dev/null | tr -d '[:space:]' || echo dev) ($(git rev-parse --short HEAD 2>/dev/null || echo unknown))"
echo " 本地访问:http://127.0.0.1:8000"
echo " Tailscale 内网:http://<本机tailscale_ip>:8000"
echo " 如需 PWA/HTTPS:tailscale serve --bg --https=443 http://127.0.0.1:8000"
echo " 查看日志:journalctl -u vps-manager -f"
echo "=========================================="