130 lines
5.0 KiB
Bash
Executable File
130 lines
5.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# 家里 Station NAS(192.168.110.29 · DS213j · 无 Docker)部署工作手机网站
|
||
#
|
||
# 用法(Mac 与 NAS 同网):
|
||
# export NAS_HOST=192.168.110.29 NAS_USER=admin NAS_PASS='zhiqun1984'
|
||
# bash sdk/scripts/deploy_home_station.sh
|
||
#
|
||
# 访问(部署成功后):
|
||
# 内网(最稳) http://192.168.110.29:8899/hub
|
||
# 公网 HTTPS https://workphone.quwanzhi.com/hub (推荐;kr Nginx 443 → frp 8889 → NAS 8899)
|
||
# 公网 HTTP http://workphone.quwanzhi.com/hub (部分网络/Clash 下 80 可能 Empty reply)
|
||
# frp 直连 http://opennas2.quwanzhi.com:8889/hub
|
||
# API Key workphone-secret-key(Header: X-API-Key)
|
||
#
|
||
# 外网验收注意:
|
||
# - kr 本机 curl 127.0.0.1 + Host 已 200;链路正常
|
||
# - Mac 开 Clash 时域名可能解析到 fake-ip(198.18.x)→ 请加 DIRECT 或 --resolve
|
||
# - 腾讯云安全组 API 凭证失效时需控制台手动放行 80/443/8889
|
||
|
||
set -euo pipefail
|
||
|
||
NAS_HOST="${NAS_HOST:-192.168.110.29}"
|
||
NAS_USER="${NAS_USER:-admin}"
|
||
NAS_PASS="${NAS_PASS:-zhiqun1984}"
|
||
NAS_SDK_DIR="${NAS_SDK_DIR:-/volume1/web/workphone-sdk}"
|
||
NAS_CKB_WEB="${NAS_CKB_WEB:-/volume1/web/cunkebao}"
|
||
SDK_PORT="${SDK_PORT:-8899}"
|
||
CKB_WEB_PORT="${CKB_WEB_PORT:-8800}"
|
||
|
||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
SDK_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||
REPO_ROOT="$(cd "$SDK_ROOT/.." && pwd)"
|
||
CKB_ROOT="$(cd "$REPO_ROOT/../cunkebao_v3" 2>/dev/null && pwd || echo "")"
|
||
|
||
SSH_OPTS=(-o StrictHostKeyChecking=no -o ConnectTimeout=15
|
||
-o KexAlgorithms=+diffie-hellman-group1-sha1
|
||
-o Ciphers=+aes128-cbc,3des-cbc,aes192-cbc,aes256-cbc)
|
||
|
||
ssh_nas() {
|
||
sshpass -p "$NAS_PASS" ssh "${SSH_OPTS[@]}" "${NAS_USER}@${NAS_HOST}" "$@"
|
||
}
|
||
|
||
rsync_nas() {
|
||
sshpass -p "$NAS_PASS" rsync -avz -e "ssh ${SSH_OPTS[*]}" "$@"
|
||
}
|
||
|
||
echo ">>> 探测家里 NAS ${NAS_HOST} …"
|
||
ssh_nas "hostname; free -m | head -2"
|
||
|
||
echo ">>> 同步工作手机 SDK -> ${NAS_SDK_DIR}"
|
||
ssh_nas "mkdir -p '${NAS_SDK_DIR}'"
|
||
rsync_nas \
|
||
--exclude '.git' --exclude '__pycache__' --exclude '*.pyc' --exclude 'node_modules' \
|
||
--exclude '.venv' --exclude 'venv' --exclude '.pytest_cache' \
|
||
--exclude 'android-app' --exclude 'admin' --exclude 'phone' \
|
||
--exclude 'scripts/gadget_work' --exclude 'scripts/**/*.apk' \
|
||
--exclude 'data/operation_logs' --exclude '*.md' \
|
||
"${SDK_ROOT}/app" "${SDK_ROOT}/scripts" \
|
||
"${SDK_ROOT}/requirements.nas-lite.txt" "${SDK_ROOT}/requirements.txt" \
|
||
"${SDK_ROOT}/Dockerfile" "${SDK_ROOT}/docker-compose.nas.yml" \
|
||
"${NAS_USER}@${NAS_HOST}:${NAS_SDK_DIR}/"
|
||
|
||
echo ">>> 安装 Python 依赖(NAS 精简版)…"
|
||
ssh_nas "bash -s" <<REMOTE
|
||
set -e
|
||
export PATH="/var/services/homes/admin/.local/bin:/usr/local/bin:\$PATH"
|
||
PY=/usr/local/bin/python3
|
||
SDK_DIR='${NAS_SDK_DIR}'
|
||
cd "\$SDK_DIR"
|
||
"\$PY" -m pip install --user -q -r requirements.nas-lite.txt 2>&1 | tail -5 || true
|
||
REMOTE
|
||
|
||
echo ">>> 写入启动脚本 …"
|
||
ssh_nas "bash -s" <<REMOTE
|
||
set -e
|
||
SDK_DIR='${NAS_SDK_DIR}'
|
||
PORT='${SDK_PORT}'
|
||
cat > "\$SDK_DIR/start_workphone.sh" <<'EOS'
|
||
#!/bin/sh
|
||
export PATH="/var/services/homes/admin/.local/bin:/usr/local/bin:\$PATH"
|
||
cd __SDK_DIR__/app
|
||
export ENV=production
|
||
export API_KEY=workphone-secret-key
|
||
export AI_BRAIN_ENABLED=false
|
||
# 家里 NAS 无 Mongo/Redis 容器;SDK 可降级运行
|
||
export MONGO_URI=
|
||
export REDIS_URL=
|
||
exec /usr/local/bin/python3 -m uvicorn main:app --host 0.0.0.0 --port __PORT__
|
||
EOS
|
||
sed -i "s|__SDK_DIR__|\$SDK_DIR|g; s|__PORT__|\$PORT|g" "\$SDK_DIR/start_workphone.sh"
|
||
chmod +x "\$SDK_DIR/start_workphone.sh"
|
||
|
||
# 停止旧进程
|
||
pkill -f "uvicorn main:app.*${SDK_PORT}" 2>/dev/null || true
|
||
sleep 1
|
||
nohup "\$SDK_DIR/start_workphone.sh" > "\$SDK_DIR/workphone.log" 2>&1 &
|
||
sleep 8
|
||
REMOTE
|
||
|
||
echo ">>> 健康检查 …"
|
||
if ssh_nas "wget -qO- http://127.0.0.1:${SDK_PORT}/health 2>/dev/null | head -c 200"; then
|
||
echo ""
|
||
echo "✅ 工作手机 SDK 已启动"
|
||
else
|
||
echo "⚠️ health 未响应,查看日志:"
|
||
ssh_nas "tail -30 '${NAS_SDK_DIR}/workphone.log' 2>/dev/null || true"
|
||
fi
|
||
|
||
# 存客宝前端(可选:本地构建后 rsync)
|
||
if [[ -d "${CKB_ROOT}/Cunkebao" ]]; then
|
||
echo ">>> 构建存客宝前端(本机)…"
|
||
if command -v pnpm >/dev/null 2>&1; then
|
||
(cd "${CKB_ROOT}/Cunkebao" && pnpm install --silent 2>/dev/null && VITE_API_BASE_URL="" pnpm run build 2>&1 | tail -5) || echo "存客宝构建跳过(pnpm 失败)"
|
||
fi
|
||
if [[ -d "${CKB_ROOT}/Cunkebao/dist" ]]; then
|
||
echo ">>> 同步存客宝静态站到 NAS ${NAS_CKB_WEB} …"
|
||
ssh_nas "mkdir -p '${NAS_CKB_WEB}'"
|
||
rsync_nas -a --delete "${CKB_ROOT}/Cunkebao/dist/" "${NAS_USER}@${NAS_HOST}:${NAS_CKB_WEB}/"
|
||
echo " 存客宝静态:http://${NAS_HOST}:${CKB_WEB_PORT}/ (需 WebStation/反代,或 python -m http.server)"
|
||
fi
|
||
fi
|
||
|
||
echo ""
|
||
echo "=============================================="
|
||
echo " 家里 NAS 部署完成"
|
||
echo " 工作手机控制台: http://${NAS_HOST}:${SDK_PORT}/hub"
|
||
echo " SDK API / 文档: http://${NAS_HOST}:${SDK_PORT}/docs"
|
||
echo " 请在 DSM 防火墙放行 TCP ${SDK_PORT}"
|
||
echo "=============================================="
|