Files
getDomain/docs/18_domainCheck_CentOS9一键复制部署与更新文档.md
Your Name 0e096947fc debug
2026-04-17 15:13:46 +08:00

1197 lines
30 KiB
Markdown
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.
# 18 domainCheck CentOS9 全自动一键部署与更新文档
## 一、文档用途
这份文档只做一件事:
> 给你一套可以直接复制执行的命令,完成 `1 台国外机器 + 2 台国内机器` 的傻瓜式部署和后续更新。
文档边界:
- 这里只讲一键自动部署
- 默认你会使用仓库里的 3 个一键脚本
- 不展开手工逐条部署步骤
- 如果你想完全手工部署,请改看:
- [17_domainCheck_全流程部署实操手册.md](/www/wwwroot/getDomain/docs/17_domainCheck_全流程部署实操手册.md:1)
统一前提:
- 系统:`CentOS Stream 9`
- 代码管理:统一 `git`
- API 域名:`api.domain.com`
- 后台域名:`admin.domain`
- 分支:默认 `main`
- 脚本约定:所有一键 `.sh` 只做部署,不执行任何 `git` 命令
目标机器:
- 国外机器 `1`
- 角色:`overseas-control`
- 国内机器 `2`
- `mainland-controller-01`
- `mainland-worker-01`
一句话部署口径:
- 国外机器:`宝塔管理 Nginx / PostgreSQL / Redis + systemd 管理项目服务`
- 国内机器:`纯 systemd 执行节点,不装宝塔`
## 二、先改这里
正式执行本文命令前,先把下面这些变量替换成你自己的真实值。
```text
API_DOMAIN=api.domain.com
ADMIN_DOMAIN=admin.domain
DB_NAME=domain
DB_USER=domainuser
DB_PASSWORD=请改成你的强密码
SYNC_SHARED_TOKEN=请改成你的共享令牌
OVERSEAS_NODE_CODE=overseas-control-01
MAINLAND_CONTROLLER_NODE_CODE=mainland-controller-01
MAINLAND_WORKER_NODE_CODE=mainland-worker-01
MAINLAND_CONTROLLER_IP=国内controller机器IP
NODE_VERSION=20
NODE_NVM_DIR=
```
最少必须先替换这 5 个:
- `DB_PASSWORD`
- `REDIS_PASSWORD`
- `SYNC_SHARED_TOKEN`
- `API_DOMAIN`
- `ADMIN_DOMAIN`
- `MAINLAND_CONTROLLER_IP`
如果你用 `root` 执行一键脚本,但 `nvm` 实际装在别的用户目录下,再额外补一个:
- `NODE_NVM_DIR`
例如:
```text
NODE_NVM_DIR=/home/www/.nvm
```
## 三、统一约定
### 1. 仓库目录
```text
/www/wwwroot/getDomain
```
### 2. 运行目录
```text
/opt/domaincheck
```
### 3. 统一更新命令
后续所有机器代码更新统一执行:
```bash
cd /www/wwwroot/getDomain
git fetch --all
git checkout main
git pull --ff-only origin main
```
### 3.1 首次全新机器先做什么
如果这台机器是第一次部署,而且本机还没有:
```text
/www/wwwroot/getDomain
```
那么要先手动拉一次代码,因为脚本文件本身也在仓库里。
首次最小步骤:
```bash
mkdir -p /www/wwwroot
cd /www/wwwroot
git clone 你的仓库地址 getDomain
cd getDomain
git checkout main
git pull --ff-only origin main
```
然后再:
1. 复制对应的 `.conf.example`
2. 编辑 `.conf`
3. 执行对应的 `.sh`
关键结论:
- 新机器第一次:必须先手动 `git clone`
- 后续每次更新:先手动 `git pull`
- 后续执行脚本:不负责 `clone`,也不负责 `pull`
- 脚本只负责“基于当前仓库代码做部署或更新”
### 3.2 这些命令用哪个用户执行
结论:
- 整套部署命令建议统一使用 `root`
- 不建议用 `www` 执行部署脚本
- 但前端 `npm install``npm run build` 会由脚本自动切到仓库属主执行
原因:
- 脚本会写:
- `/etc/default/...`
- `/etc/systemd/system/...`
- `/opt/domaincheck/...`
- 脚本会执行:
- `systemctl enable`
- `systemctl restart`
- `chown`
- 可能还有 `dnf`
这些都属于 `root` 口径,不适合 `www` 用户执行。
补充说明:
- 脚本入口仍然是 `root`
- 但国外机的一键脚本内部会自动识别仓库属主
- 然后把前端构建切到仓库属主执行
- 这样可以避免把 `node_modules``dist`、源码目录权限烧成 `root`
- `/etc/default/domaincheck-api` 里的 `CORS_ORIGINS` 必须使用 JSON 数组格式
- 正确示例:
- `CORS_ORIGINS='["https://admin.domain","http://127.0.0.1:3201","http://localhost:3201"]'`
- 不能写成逗号拼接字符串:
- `CORS_ORIGINS=https://admin.domain,http://127.0.0.1:3201,http://localhost:3201`
最稳的执行方式:
```bash
sudo -i
```
然后再继续后面的复制、编辑和执行脚本。
### 4. 统一软链接
所有机器都统一建立:
```bash
mkdir -p /opt/domaincheck
ln -sfn /www/wwwroot/getDomain/domain-api /opt/domaincheck/domain-api
ln -sfn /www/wwwroot/getDomain/domain-web /opt/domaincheck/domain-web
ln -sfn /www/wwwroot/getDomain/domainCheck /opt/domaincheck/domainCheck
```
### 5. 并发配置约定
- 默认检测并发由后台系统设置里的 `默认检测线程数` 控制
- 若某台机器需要单独并发,可在后台系统设置里增加 `节点独立线程覆盖`
- 远端日志回传由后台 `系统设置 -> 运行配置``检测控制` 顶部按钮控制
- `关闭回传`
- 不追加远端 Worker 日志镜像
- 适合正式长期运行,减少额外事件写入
- `关键回传`
- 只回传启动、停止、代理刷新、批次完成、异常、完成等关键过程
- 适合大多数联调和线上观察
- `全量回传`
- 在关键模式基础上,额外回传取任务、建线程、线程数变化、域名开始/完成/失败等过程
- 适合临时排查问题,定位完成后建议切回 `关键``关闭`
- 检测控制页日志窗口现在会合并展示:
- controller 本机可见的 Worker 日志尾部
- 远端 Worker 回传的流程事件日志
- 如果开启了远端日志回传但页面仍无新增输出,优先检查:
- `domaincheck-worker` 是否已更新到最新代码
- Worker 是否能连上 Redis
- 检测任务是否由当前控制面发起,并带有 `job_id / cycle_token`
- 规则是:
- 节点已单独配置:走该节点自己的线程数
- 节点未单独配置:回退到默认线程数
- 节点编码必须和该机器 `/etc/default/domaincheck-worker` 里的 `NODE_CODE` 一致
- 配置会同时写入:
- Redis`domain_tool:thread_count`
- Redis`domain_tool:node_thread_counts`
- 本地文件:`thread_count.json`
- 本地文件:`node_thread_counts.json`
### 6. 宝塔与 `nvm` 口径
- 国外主控机:
- 你如果已经长期用宝塔管理 `PostgreSQL``Redis``Nginx`,可以继续用
-`domain-api``domaincheck-worker``domaincheck-sync-agent` 仍建议走 `systemd`
- 国内机器:
- 不建议为了纯 `worker` 节点额外安装宝塔
- 原因不是不能用,而是会多一层面板进程、端口、权限和故障面
- 国内机器的最佳形态是:
- 只装 Python 运行环境
- 只装项目代码
- 只跑 `domaincheck-worker`
- 若是 controller再加 `domaincheck-sync-agent`
- Node
- 继续用 `nvm` 没问题,不需要改成系统全局安装
- 建议统一到 `Node 20`
- 生产构建时只要保证执行构建命令前已经 `nvm use 20`
### 6.1 `nvm` 安装命令
如果机器还没有安装 `nvm`,先执行:
```bash
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.5/install.sh | bash
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"
nvm -v
nvm install 20
nvm use 20
```
补充说明:
- 国外机器如果要构建前端,必须先确保 `nvm` 可用
- 一键部署脚本会调用 `nvm install 20``nvm use 20`
- 前端构建由仓库属主执行,不是由 `root` 直接执行
- 如果你用 `root` 执行脚本,而 `nvm` 实际装在别的用户目录下:
- 不需要改成 `www` 执行脚本
- 直接在 `install_overseas_quick.conf` 里填写:
- `NODE_NVM_DIR=/home/www/.nvm`
- 当前一键脚本会按这个顺序找 Node 运行环境:
- `NODE_NVM_DIR`
- 当前环境变量里的 `NVM_DIR`
- `/root/.nvm`
- `/home/www/.nvm`
- `/www/server/nvm`
- `/usr/local/nvm`
- 最后再尝试系统全局 `node``npm`
### 6.2 国内机器已经装了宝塔怎么办
结论:
- 不需要为了接入 `controller` / `worker` 专门重装系统
- 机器上已经有宝塔,不等于这台机器不能继续用
- 关键不是“有没有宝塔”,而是“不要让宝塔深度接管项目服务”
推荐做法:
- 保留宝塔本身
- 如果你已经习惯用宝塔管理:
- `PostgreSQL`
- `Redis`
- 防火墙 / 端口
- 证书
这些可以继续保留
- 但项目服务仍然统一交给 `systemd`
- `domaincheck-worker`
- `domaincheck-sync-agent`
- 不要把这些项目服务交给宝塔的守护进程或计划任务反复接管
对于国内 `controller`
- 已装宝塔可以继续用
- Redis / PostgreSQL 可以继续由宝塔安装和管理
-`domaincheck-worker` / `domaincheck-sync-agent` 仍建议走 `systemd`
对于国内 `worker`
- 已装宝塔也不用重装
- 但尽量不要再给它额外配置站点、反代、复杂 PHP/Node 面板功能
- 把它当普通 Linux 节点使用即可
- 核心目标就是稳定运行 `domaincheck-worker`
只有在下面这些情况,才建议考虑重装:
- 机器上历史站点和旧服务太多,端口冲突严重
- Redis / PostgreSQL / Nginx 已经被旧项目改得很乱
- 系统里残留环境过多,你自己也不再信任这台机器的稳定性
如果只是“已经装了宝塔”,但系统仍然清晰可控,就不建议为了这个项目重装。
### 7. 你实际应该怎么选
- 如果国外主控机已经是宝塔机:
- 继续沿用宝塔即可
- 宝塔负责:
- `Nginx`
- `PostgreSQL`
- `Redis`
- SSL 证书
- 项目自身服务继续交给:
- `domaincheck-api.service`
- `domaincheck-worker.service`
- 如果国内机器只是跑检测:
- 不要装宝塔
- 直接按本文的纯命令部署
- 这样最轻、最稳、最容易横向复制
### 8. Python 3.11 必须单独安装
- 这里不能只依赖系统默认 `python3`
- 必须明确安装 `python3.11`
- 因为本文后续所有部署命令都直接使用:
- `python3.11 -m venv .venv`
安装命令:
```bash
dnf install -y python3.11 python3.11-devel
```
安装后先验证:
```bash
python3.11 --version
```
期望输出类似:
```text
Python 3.11.x
```
### 8.1 Linux 依赖安装特别说明
`domainCheck/requirements.txt` 是从桌面版沿用过来的,里面包含 Windows 专用依赖,例如:
- `pywin32`
- `pywin32-ctypes`
- `twisted-iocpsupport`
- `win32-setctime`
这些包在 Linux 上不能直接安装。
现在的 3 个一键部署脚本已经内置了兼容处理:
- 会自动读取 `domainCheck/requirements.txt`
- 自动生成 `requirements.linux.txt`
- 自动过滤掉 Windows-only 依赖
- 然后再执行 Linux 环境安装
所以现在在 Linux 上看到这类报错时,正确处理方式不是手工删仓库依赖,而是:
1.`git pull`
2. 确认脚本已经更新到最新版本
3. 重新执行一键部署脚本
如果你是手工部署,不走一键脚本,那就不要直接跑:
```bash
pip install -r requirements.txt
```
而应该改成:
```bash
cd /opt/domaincheck/domainCheck
python3.11 - <<'PY'
from pathlib import Path
source = Path("requirements.txt")
target = Path("requirements.linux.txt")
raw = source.read_bytes()
for encoding in ("utf-8", "utf-16", "utf-16-le", "utf-16-be", "gbk"):
try:
text = raw.decode(encoding)
break
except UnicodeDecodeError:
continue
else:
raise SystemExit("无法解析 requirements.txt 编码")
skip_prefixes = (
"pywin32==",
"pywin32-ctypes==",
"twisted-iocpsupport==",
"win32-setctime==",
)
lines = []
for line in text.splitlines():
normalized = line.strip().lstrip("\ufeff")
if normalized.lower().startswith(skip_prefixes):
continue
lines.append(normalized)
target.write_text("\n".join(lines) + "\n", encoding="utf-8")
PY
source .venv/bin/activate
pip install -r requirements.linux.txt
```
## 四、最短复制块
这一节给你三段最短命令。
用法:
- 急着部署时,先用这里
- 想看每一步解释,再看后面的完整章节
### 1. 国外主控机最短复制块
先把下面 5 个值替换掉再执行:
```text
API_DOMAIN
ADMIN_DOMAIN
DB_PASSWORD
OVERSEAS_NODE_CODE
NODE_VERSION
```
也可以直接改脚本头部变量后执行:
```bash
cp /www/wwwroot/getDomain/domain-api/deploy/multi-region/install_overseas_quick.conf.example \
/www/wwwroot/getDomain/domain-api/deploy/multi-region/install_overseas_quick.conf
# 先编辑 install_overseas_quick.conf
bash /www/wwwroot/getDomain/domain-api/deploy/multi-region/install_overseas_quick.sh
```
注意:
- 这条脚本不会执行 `git fetch`
- 这条脚本不会执行 `git pull`
- 你要先自己把 `/www/wwwroot/getDomain` 更新到目标版本,再跑脚本
- 这条脚本会自动过滤 Windows-only Python 依赖
- 这条脚本会自动把 `CORS_ORIGINS` 写成 systemd 可用的安全格式
- 这条脚本结束时会自动执行:`chown -R www:www /www/wwwroot/getDomain`
```bash
hostname
systemctl status domaincheck-api --no-pager -l
systemctl status domaincheck-worker --no-pager -l
curl http://127.0.0.1:8100/health
curl http://127.0.0.1:8100/api/v1/runtime/preflight
curl http://127.0.0.1:8100/api/v1/runtime/readiness
```
判断标准:
- `health.status=ok`
- `runtime/preflight.data.ok=true`
- 如果此时还没有接入大陆 `controller` / `worker``runtime/readiness.data.status=attention` 是正常现象
- 只有国外机自己的 PostgreSQL、Redis、API、systemd 报错时,才算国外主控机没部署好
### 2. 国内 controller 最短复制块
先把下面 3 个值替换掉再执行:
先把下面 5 个值替换掉再执行:
```text
DB_NAME
DB_USER
DB_PASSWORD
REDIS_PASSWORD
SYNC_SHARED_TOKEN
MAINLAND_CONTROLLER_NODE_CODE
TARGET_API_BASE_URL
```
也可以直接改脚本头部变量后执行:
```bash
cp /www/wwwroot/getDomain/domain-api/deploy/multi-region/install_mainland_controller_quick.conf.example \
/www/wwwroot/getDomain/domain-api/deploy/multi-region/install_mainland_controller_quick.conf
# 先编辑 install_mainland_controller_quick.conf
bash /www/wwwroot/getDomain/domain-api/deploy/multi-region/install_mainland_controller_quick.sh
```
注意:
- 这条脚本不会执行 `git fetch`
- 这条脚本不会执行 `git pull`
- 你要先自己把 `/www/wwwroot/getDomain` 更新到目标版本,再跑脚本
- 这条脚本会自动过滤 Windows-only Python 依赖
- 这条脚本结束时会自动执行:`chown -R www:www /www/wwwroot/getDomain`
```bash
hostname
systemctl status domaincheck-worker --no-pager -l
systemctl status domaincheck-sync-agent --no-pager -l
cd /opt/domaincheck/domain-api
bash deploy/multi-region/check_mainland_controller.sh
```
### 3. 国内 worker 最短复制块
先把下面 4 个值替换掉再执行:
先把下面 7 个值替换掉再执行:
```text
DB_NAME
DB_USER
DB_PASSWORD
REDIS_PASSWORD
SYNC_SHARED_TOKEN
MAINLAND_WORKER_NODE_CODE
MAINLAND_CONTROLLER_IP
TARGET_API_BASE_URL
```
也可以直接改脚本头部变量后执行:
```bash
cp /www/wwwroot/getDomain/domain-api/deploy/multi-region/install_mainland_worker_quick.conf.example \
/www/wwwroot/getDomain/domain-api/deploy/multi-region/install_mainland_worker_quick.conf
# 先编辑 install_mainland_worker_quick.conf
bash /www/wwwroot/getDomain/domain-api/deploy/multi-region/install_mainland_worker_quick.sh
```
注意:
- 这条脚本不会执行 `git fetch`
- 这条脚本不会执行 `git pull`
- 你要先自己把 `/www/wwwroot/getDomain` 更新到目标版本,再跑脚本
- 这条脚本会自动过滤 Windows-only Python 依赖
- 这条脚本结束时会自动执行:`chown -R www:www /www/wwwroot/getDomain`
```bash
hostname
systemctl status domaincheck-worker --no-pager -l
```
## 五、所有机器先执行一次
### 1. 安装基础环境
```bash
dnf update -y
dnf install -y epel-release
dnf install -y git nginx redis postgresql postgresql-server postgresql-contrib gcc gcc-c++ make wget curl tar policycoreutils-python-utils
dnf install -y python3.11 python3.11-devel
```
### 2. 克隆代码
```bash
mkdir -p /www/wwwroot
cd /www/wwwroot
git clone 你的仓库地址 getDomain
cd getDomain
git checkout main
git pull --ff-only origin main
```
### 3. 建立运行目录软链接
```bash
mkdir -p /opt/domaincheck
ln -sfn /www/wwwroot/getDomain/domain-api /opt/domaincheck/domain-api
ln -sfn /www/wwwroot/getDomain/domain-web /opt/domaincheck/domain-web
ln -sfn /www/wwwroot/getDomain/domainCheck /opt/domaincheck/domainCheck
```
### 4. 创建 Python 虚拟环境
```bash
cd /opt/domaincheck/domainCheck
python3.11 -m venv .venv
source .venv/bin/activate
pip install --upgrade pip
python3.11 - <<'PY'
from pathlib import Path
source = Path("requirements.txt")
target = Path("requirements.linux.txt")
raw = source.read_bytes()
for encoding in ("utf-8", "utf-16", "utf-16-le", "utf-16-be", "gbk"):
try:
text = raw.decode(encoding)
break
except UnicodeDecodeError:
continue
else:
raise SystemExit("无法解析 requirements.txt 编码")
skip_prefixes = (
"pywin32==",
"pywin32-ctypes==",
"twisted-iocpsupport==",
"win32-setctime==",
)
lines = []
for line in text.splitlines():
normalized = line.strip().lstrip("\ufeff")
if normalized.lower().startswith(skip_prefixes):
continue
lines.append(normalized)
target.write_text("\n".join(lines) + "\n", encoding="utf-8")
PY
pip install -r requirements.linux.txt
cd /opt/domaincheck/domain-api
/opt/domaincheck/domainCheck/.venv/bin/pip install fastapi uvicorn pydantic-settings psycopg2-binary redis openpyxl python-multipart
```
## 六、国外机器一键部署
这一节默认你是:
- 国外主控机
- 可以使用宝塔管理 `Nginx / PostgreSQL / Redis`
- 项目进程仍由 `systemd` 托管
国外机器承担:
- `domain-web`
- `domain-api`
- PostgreSQL
- Redis
- `domaincheck-worker`
### 1. PostgreSQL 和 Redis 处理方式
如果你已经用宝塔装好了:
- `PostgreSQL`
- `Redis`
那这一步可以跳过,直接看后面的数据库账号和项目配置。
如果你不用宝塔,就执行下面命令。
### 2. 初始化 PostgreSQL
```bash
postgresql-setup --initdb
systemctl enable postgresql
systemctl start postgresql
```
创建数据库:
```bash
sudo -u postgres psql <<'SQL'
CREATE USER domainuser WITH PASSWORD '请改成你的强密码';
CREATE DATABASE domain OWNER domainuser;
GRANT ALL PRIVILEGES ON DATABASE domain TO domainuser;
SQL
```
### 3. 启动 Redis
```bash
systemctl enable redis
systemctl start redis
```
### 4. 配置 `domainCheck/.env`
```bash
cat >/opt/domaincheck/domainCheck/.env <<'EOF'
DB_HOST=127.0.0.1
DB_PORT=5432
DB_DATABASE=domain
DB_USER=domainuser
DB_PASSWORD=请改成你的强密码
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
REDIS_PASSWORD=
REDIS_DB=0
EOF
```
### 5. 初始化数据库结构
```bash
cd /opt/domaincheck/domainCheck
/opt/domaincheck/domainCheck/.venv/bin/python init_database.py
```
### 6. 配置前端生产环境
```bash
cat >/opt/domaincheck/domain-web/.env.production <<'EOF'
VITE_API_BASE_URL=https://api.domain.com/api/v1
EOF
```
### 7. 用 `nvm` 构建前端
如果这台机器还没装 `nvm`,先执行:
```bash
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.5/install.sh | bash
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"
nvm -v
```
然后固定使用:
```bash
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
nvm install 20
nvm use 20
node -v
```
然后再构建:
```bash
cd /opt/domaincheck/domain-web
npm install
npm run build
```
### 8. 配置 API 环境变量
```bash
cp /opt/domaincheck/domain-api/deploy/multi-region/templates/domaincheck-api.env.example /etc/default/domaincheck-api
sed -i 's#^DOMAIN_ROOT=.*#DOMAIN_ROOT=/opt/domaincheck/domainCheck#' /etc/default/domaincheck-api
sed -i 's#^API_HOST=.*#API_HOST=0.0.0.0#' /etc/default/domaincheck-api
sed -i 's#^API_PORT=.*#API_PORT=8100#' /etc/default/domaincheck-api
sed -i 's#^NODE_CODE=.*#NODE_CODE=overseas-control-01#' /etc/default/domaincheck-api
sed -i 's#^NODE_REGION=.*#NODE_REGION=overseas#' /etc/default/domaincheck-api
sed -i 's#^NODE_ROLE=.*#NODE_ROLE=control#' /etc/default/domaincheck-api
sed -i 's#^SYNC_PUSH_ENABLED=.*#SYNC_PUSH_ENABLED=false#' /etc/default/domaincheck-api
sed -i 's#^CORS_ORIGINS=.*#CORS_ORIGINS='\''["https://admin.domain","http://127.0.0.1:3201","http://localhost:3201"]'\''#' /etc/default/domaincheck-api
```
### 9. 安装 systemd
```bash
cp /opt/domaincheck/domain-api/deploy/systemd/domain-api.service /etc/systemd/system/domaincheck-api.service
cp /opt/domaincheck/domain-api/deploy/systemd/domain-worker.service /etc/systemd/system/domaincheck-worker.service
```
### 10. 修正权限
```bash
mkdir -p /opt/domaincheck/domain-api/runtime
touch /opt/domaincheck/domainCheck/detect_worker.log
chown -R www:www /opt/domaincheck/domain-api/runtime
chown www:www /opt/domaincheck/domainCheck/detect_worker.log
chmod 664 /opt/domaincheck/domainCheck/detect_worker.log
chown -R www:www /www/wwwroot/getDomain
```
### 11. 启动国外服务
```bash
systemctl daemon-reload
systemctl enable domaincheck-api
systemctl enable domaincheck-worker
systemctl restart domaincheck-api
systemctl restart domaincheck-worker
```
### 12. 配置 Nginx
如果你已经用宝塔建好了:
- `admin.domain`
- `api.domain.com`
并且已经在宝塔里配好了反代和静态站点,那么这一节可以不执行。
如果你不用宝塔,就直接执行下面命令。
后台站点:
```bash
cat >/etc/nginx/conf.d/admin.domain.conf <<'EOF'
server {
listen 80;
server_name admin.domain;
root /opt/domaincheck/domain-web/dist;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
}
EOF
```
API 站点:
```bash
cat >/etc/nginx/conf.d/api.domain.com.conf <<'EOF'
server {
listen 80;
server_name api.domain.com;
location / {
proxy_pass http://127.0.0.1:8100;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
EOF
```
启动 Nginx
```bash
nginx -t
systemctl enable nginx
systemctl restart nginx
```
### 13. 国外机器验收
```bash
curl http://127.0.0.1:8100/health
curl http://127.0.0.1:8100/api/v1/runtime/preflight
curl http://127.0.0.1:8100/api/v1/runtime/readiness
cd /opt/domaincheck/domain-api/deploy/linux
python3 smoke_test.py --base-url http://127.0.0.1:8100
```
结果解释:
- `runtime/preflight.data.ok=true` 说明国外主控机自身部署已经通过
- 如果此时 `runtime/readiness.data.status=attention`,而提示内容是“尚未观察到在线的大陆 controller / worker 节点”,这是正常现象
- `RedisBloom` 出现降级告警不算阻塞项,只是性能优化项
- 只有国外机自己的 PostgreSQL、Redis、systemd、DOMAIN_ROOT、API 启动失败时,才算国外主控机没收口
## 七、国内 controller 一键部署
这一节默认你是:
- 国内 controller
- 不装宝塔
- 只跑 `domaincheck-worker + domaincheck-sync-agent`
- 本机承载 Redis / PostgreSQL 控制面
### 1. 先准备 Redis 和 PostgreSQL
```bash
postgresql-setup --initdb
systemctl enable postgresql
systemctl start postgresql
systemctl enable redis
systemctl start redis
```
创建数据库:
```bash
sudo -u postgres psql <<'SQL'
CREATE USER domainuser WITH PASSWORD '请改成你的强密码';
CREATE DATABASE domain OWNER domainuser;
GRANT ALL PRIVILEGES ON DATABASE domain TO domainuser;
SQL
```
### 2. 配置 `domainCheck/.env`
```bash
cat >/opt/domaincheck/domainCheck/.env <<'EOF'
DB_HOST=127.0.0.1
DB_PORT=5432
DB_DATABASE=domain
DB_USER=domainuser
DB_PASSWORD=请改成你的强密码
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
REDIS_PASSWORD=
REDIS_DB=0
EOF
```
### 3. 执行 bootstrap
```bash
cd /opt/domaincheck/domain-api
bash deploy/multi-region/bootstrap_mainland.sh /opt/domaincheck controller
```
### 4. 配置 `/etc/default/domaincheck-worker`
```bash
cat >/etc/default/domaincheck-worker <<'EOF'
WORKER_MODE=linux-systemd
QT_QPA_PLATFORM=offscreen
NODE_CODE=mainland-controller-01
NODE_REGION=mainland
NODE_ROLE=control
DB_HOST=127.0.0.1
DB_PORT=5432
DB_DATABASE=domain
DB_USER=domainuser
DB_PASSWORD=请改成你的强密码
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
REDIS_PASSWORD=
REDIS_DB=0
SYNC_PUSH_ENABLED=true
SYNC_SOURCE_REGION=mainland
SYNC_TARGET_REGION=overseas
SYNC_TARGET_API_BASE_URL=https://api.domain.com/api/v1
SYNC_SHARED_TOKEN=请改成你的共享令牌
SYNC_BATCH_SIZE=200
SYNC_POLL_INTERVAL_SECONDS=30
EOF
```
### 5. 启动 controller 服务
```bash
systemctl daemon-reload
systemctl enable domaincheck-worker
systemctl enable domaincheck-sync-agent
systemctl restart domaincheck-worker
systemctl restart domaincheck-sync-agent
```
### 6. 本机检查
```bash
cd /opt/domaincheck/domain-api
bash deploy/multi-region/check_mainland_controller.sh
```
## 八、国内 worker 一键部署
这一节默认你是:
- 国内纯 worker 节点
- 不装宝塔
- 不承载后台
- 不承载 API
- 不承载 Nginx
### 1. 配置 `domainCheck/.env`
如果它连接 controller 的同一套 Redis / PostgreSQL就改成 controller 地址:
```bash
cat >/opt/domaincheck/domainCheck/.env <<'EOF'
DB_HOST=国内controller机器IP
DB_PORT=5432
DB_DATABASE=domain
DB_USER=domainuser
DB_PASSWORD=请改成你的强密码
REDIS_HOST=国内controller机器IP
REDIS_PORT=6379
REDIS_PASSWORD=
REDIS_DB=0
EOF
```
### 2. 执行 bootstrap
```bash
cd /opt/domaincheck/domain-api
bash deploy/multi-region/bootstrap_mainland.sh /opt/domaincheck worker
```
### 3. 配置 `/etc/default/domaincheck-worker`
```bash
cat >/etc/default/domaincheck-worker <<'EOF'
WORKER_MODE=linux-systemd
QT_QPA_PLATFORM=offscreen
NODE_CODE=mainland-worker-01
NODE_REGION=mainland
NODE_ROLE=worker
DB_HOST=国内controller机器IP
DB_PORT=5432
DB_DATABASE=domain
DB_USER=domainuser
DB_PASSWORD=请改成你的强密码
REDIS_HOST=国内controller机器IP
REDIS_PORT=6379
REDIS_PASSWORD=
REDIS_DB=0
SYNC_PUSH_ENABLED=true
SYNC_SOURCE_REGION=mainland
SYNC_TARGET_REGION=overseas
SYNC_TARGET_API_BASE_URL=https://api.domain.com/api/v1
SYNC_SHARED_TOKEN=请改成你的共享令牌
SYNC_BATCH_SIZE=200
SYNC_POLL_INTERVAL_SECONDS=30
EOF
```
### 4. 启动 worker
```bash
systemctl daemon-reload
systemctl enable domaincheck-worker
systemctl restart domaincheck-worker
```
## 九、统一更新命令
以后你更新代码,三台机器统一执行:
```bash
cd /www/wwwroot/getDomain
git fetch --all
git checkout main
git pull --ff-only origin main
```
然后:
### 国外机器
如果国外机器前端构建使用 `nvm`,更新时建议固定这么跑:
```bash
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
nvm install 20
nvm use 20
cd /opt/domaincheck/domain-web
npm install
npm run build
systemctl restart domaincheck-api
systemctl restart domaincheck-worker
systemctl restart nginx
```
如果国外机 Redis 只做本机运行态使用,并且当前 Redis 没有密码,记得保持:
```bash
sed -i 's#^REDIS_PASSWORD=.*#REDIS_PASSWORD=#' /opt/domaincheck/domainCheck/.env
systemctl restart domaincheck-api
systemctl restart domaincheck-worker
```
### 国内 controller
```bash
systemctl restart domaincheck-worker
systemctl restart domaincheck-sync-agent
```
### 国内 worker
```bash
systemctl restart domaincheck-worker
```
补充说明:
- 一键部署脚本更新后,会在脚本末尾自动执行一次:
- `chown -R www:www /www/wwwroot/getDomain`
- 如果你是完全手工更新,也建议补执行一次,避免后续 `www` 用户 `git pull` 或宝塔读写再次撞权限
## 十、最终联调检查
在国外机器执行:
```bash
curl https://api.domain.com/api/v1/runtime/readiness
curl https://api.domain.com/api/v1/runtime/cluster
curl https://api.domain.com/api/v1/runtime/sync-summary
```
期望:
- `runtime/readiness.status` 不是 `blocking`
- `runtime/cluster` 能看到:
- `overseas-control-01`
- `mainland-controller-01`
- `mainland-worker-01`
- `runtime/sync-summary` 能看到 `detect_result_batches`
## 十一、如果当前还不能上国内机器
先在国外机器演练:
```bash
cd /opt/domaincheck/domain-api
bash deploy/multi-region/rehearse_multi_region.sh http://127.0.0.1:8100
```
如果它输出:
```text
rehearsal passed
```
说明:
- 多机脚本没问题
- readiness 判断没问题
- cluster 视图没问题
- 可以开始把同样方式复制到其他机器
## 十二、最推荐的真实落地顺序
如果按你的使用习惯,我建议你就按下面走:
### 方案 A最符合你现在的习惯
- 国外主控机:
- 宝塔管理 `Nginx / PostgreSQL / Redis / SSL`
- `systemd` 管理 `domaincheck-api / domaincheck-worker`
- 前端构建使用 `nvm`
- 国内 controller
- 不装宝塔
-`PostgreSQL / Redis / domaincheck-worker / domaincheck-sync-agent`
- 国内 worker
- 不装宝塔
- 只跑 `domaincheck-worker`
### 方案 B如果以后你想进一步简化
- 国外机继续保持不变
- 国内 controller 也可以后续去掉本地 PostgreSQL只保留
- `Redis`
- `domaincheck-worker`
- `domaincheck-sync-agent`
- 国内 worker 全部连 controller 的 Redis 和数据库
### 当前阶段我建议你先不要改的
- 不要为了统一而让国内 worker 也装宝塔
- 不要为了“更标准”把 `nvm` 改成全局 Node
- 不要让项目服务交给宝塔守护进程
## 十三、最终建议
你现在最稳的部署顺序就是:
1. 先部署国外机器
2. 国外机器 smoke test 通过
3. 国外机器多机模拟演练通过
4. 再部署国内 controller
5. 再部署国内 worker
6. 最后看 `api.domain.com` 的 readiness / cluster / sync-summary
一句话总结:
> 先把国外主控机跑稳,再用同样脚本扩到 2 台国内机器;代码更新统一走 git部署执行直接复制这份文档里的命令。