209 lines
6.5 KiB
Bash
Executable File
209 lines
6.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
set -euo pipefail
|
||
|
||
if [[ "$(id -u)" -ne 0 ]]; then
|
||
echo "请使用 root 执行此脚本"
|
||
exit 1
|
||
fi
|
||
|
||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
CONFIG_FILE="${SCRIPT_DIR}/install_overseas_quick.conf"
|
||
CONFIG_EXAMPLE="${SCRIPT_DIR}/install_overseas_quick.conf.example"
|
||
|
||
if [[ ! -f "${CONFIG_FILE}" ]]; then
|
||
echo "未找到配置文件:${CONFIG_FILE}"
|
||
echo "请先执行:cp ${CONFIG_EXAMPLE} ${CONFIG_FILE}"
|
||
exit 1
|
||
fi
|
||
|
||
# shellcheck disable=SC1090
|
||
source "${CONFIG_FILE}"
|
||
|
||
: "${API_DOMAIN:=api.domain.com}"
|
||
: "${ADMIN_DOMAIN:=admin.domain}"
|
||
: "${DB_NAME:=domain}"
|
||
: "${DB_USER:=domainuser}"
|
||
: "${DB_PASSWORD:=CHANGE_ME_DB_PASSWORD}"
|
||
: "${OVERSEAS_NODE_CODE:=overseas-control-01}"
|
||
: "${NODE_VERSION:=20}"
|
||
: "${NODE_NVM_DIR:=}"
|
||
|
||
WORKSPACE_ROOT="/www/wwwroot"
|
||
REPO_DIR="${WORKSPACE_ROOT}/getDomain"
|
||
BASE_DIR="/opt/domaincheck"
|
||
DOMAINCHECK_DIR="${BASE_DIR}/domainCheck"
|
||
DOMAIN_API_DIR="${BASE_DIR}/domain-api"
|
||
DOMAIN_WEB_DIR="${BASE_DIR}/domain-web"
|
||
REPO_OWNER=""
|
||
REPO_OWNER_HOME=""
|
||
|
||
if [[ "${DB_PASSWORD}" == "CHANGE_ME_DB_PASSWORD" ]]; then
|
||
echo "请先修改配置文件中的必填项:DB_PASSWORD"
|
||
exit 1
|
||
fi
|
||
|
||
mkdir -p "${WORKSPACE_ROOT}"
|
||
if [[ ! -d "${REPO_DIR}/.git" ]]; then
|
||
echo "未找到仓库目录:${REPO_DIR}"
|
||
echo "全新机器首次部署,必须先手动执行 git clone,把仓库拉到 /www/wwwroot/getDomain"
|
||
exit 1
|
||
fi
|
||
|
||
REPO_OWNER="$(stat -c '%U' "${REPO_DIR}")"
|
||
REPO_OWNER_HOME="$(getent passwd "${REPO_OWNER}" | cut -d: -f6)"
|
||
if [[ -z "${REPO_OWNER}" || -z "${REPO_OWNER_HOME}" ]]; then
|
||
echo "无法识别仓库属主或 HOME:${REPO_DIR}"
|
||
exit 1
|
||
fi
|
||
|
||
run_as_repo_owner() {
|
||
local cmd="$1"
|
||
runuser -u "${REPO_OWNER}" -- env HOME="${REPO_OWNER_HOME}" bash -lc "${cmd}"
|
||
}
|
||
|
||
echo "已检测到仓库目录:${REPO_DIR}"
|
||
echo "当前脚本不会执行任何 Git 命令。"
|
||
echo "仓库属主:${REPO_OWNER}"
|
||
echo "如需更新代码,请先手动切到仓库属主完成 git pull,再重新执行本脚本。"
|
||
|
||
mkdir -p "${BASE_DIR}"
|
||
ln -sfn "${REPO_DIR}/domain-api" "${DOMAIN_API_DIR}"
|
||
ln -sfn "${REPO_DIR}/domain-web" "${DOMAIN_WEB_DIR}"
|
||
ln -sfn "${REPO_DIR}/domainCheck" "${DOMAINCHECK_DIR}"
|
||
|
||
cd "${DOMAINCHECK_DIR}"
|
||
python3.11 -m venv .venv || true
|
||
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
|
||
"${DOMAINCHECK_DIR}/.venv/bin/pip" install fastapi uvicorn pydantic-settings psycopg2-binary redis openpyxl python-multipart
|
||
|
||
cat >"${DOMAINCHECK_DIR}/.env" <<EOF
|
||
DB_HOST=127.0.0.1
|
||
DB_PORT=5432
|
||
DB_DATABASE=${DB_NAME}
|
||
DB_USER=${DB_USER}
|
||
DB_PASSWORD=${DB_PASSWORD}
|
||
|
||
REDIS_HOST=127.0.0.1
|
||
REDIS_PORT=6379
|
||
REDIS_PASSWORD=
|
||
REDIS_DB=0
|
||
EOF
|
||
|
||
"${DOMAINCHECK_DIR}/.venv/bin/python" "${DOMAINCHECK_DIR}/init_database.py"
|
||
|
||
cat >"${DOMAIN_WEB_DIR}/.env.production" <<EOF
|
||
VITE_API_BASE_URL=https://${API_DOMAIN}/api/v1
|
||
EOF
|
||
|
||
chown "${REPO_OWNER}:${REPO_OWNER}" "${DOMAIN_WEB_DIR}/.env.production"
|
||
|
||
cd "${DOMAIN_WEB_DIR}"
|
||
run_as_repo_owner "
|
||
set -euo pipefail
|
||
cd '${DOMAIN_WEB_DIR}'
|
||
NODE_READY=false
|
||
resolve_nvm_dir() {
|
||
local candidate
|
||
for candidate in \
|
||
'${NODE_NVM_DIR}' \
|
||
\"\${NVM_DIR:-}\" \
|
||
'${REPO_OWNER_HOME}/.nvm' \
|
||
'/home/www/.nvm' \
|
||
'/www/server/nvm' \
|
||
'/usr/local/nvm'
|
||
do
|
||
if [[ -n \"\${candidate}\" && -s \"\${candidate}/nvm.sh\" ]]; then
|
||
echo \"\${candidate}\"
|
||
return 0
|
||
fi
|
||
done
|
||
return 1
|
||
}
|
||
if RESOLVED_NVM_DIR=\"\$(resolve_nvm_dir)\"; then
|
||
export NVM_DIR=\"\${RESOLVED_NVM_DIR}\"
|
||
source \"\${NVM_DIR}/nvm.sh\"
|
||
echo '检测到 nvm:'\"\${NVM_DIR}\"
|
||
nvm install '${NODE_VERSION}'
|
||
nvm use '${NODE_VERSION}'
|
||
NODE_READY=true
|
||
elif command -v node >/dev/null 2>&1 && command -v npm >/dev/null 2>&1; then
|
||
echo '未检测到 nvm,改用系统已安装的 node/npm'
|
||
echo '当前 node 版本:'\"\$(node -v)\"
|
||
NODE_READY=true
|
||
fi
|
||
if [[ \"\${NODE_READY}\" != 'true' ]]; then
|
||
echo '未找到可用的 Node 运行环境。'
|
||
echo '请执行以下任一方案后重试:'
|
||
echo '1. 为仓库属主安装 nvm,并确保 ~/.nvm/nvm.sh 存在'
|
||
echo '2. 在 install_overseas_quick.conf 中填写 NODE_NVM_DIR,例如:/home/www/.nvm'
|
||
echo '3. 预先安装系统全局 node 和 npm'
|
||
exit 1
|
||
fi
|
||
npm install
|
||
npm run build
|
||
"
|
||
|
||
cp "${DOMAIN_API_DIR}/deploy/multi-region/templates/domaincheck-api.env.example" /etc/default/domaincheck-api
|
||
sed -i "s#^DOMAIN_ROOT=.*#DOMAIN_ROOT=${DOMAINCHECK_DIR}#" /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_NODE_CODE}#" /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
|
||
|
||
cp "${DOMAIN_API_DIR}/deploy/systemd/domain-api.service" /etc/systemd/system/domaincheck-api.service
|
||
cp "${DOMAIN_API_DIR}/deploy/systemd/domain-worker.service" /etc/systemd/system/domaincheck-worker.service
|
||
|
||
mkdir -p "${DOMAIN_API_DIR}/runtime"
|
||
touch "${DOMAINCHECK_DIR}/detect_worker.log"
|
||
chown -R www:www "${DOMAIN_API_DIR}/runtime"
|
||
chown www:www "${DOMAINCHECK_DIR}/detect_worker.log"
|
||
chmod 664 "${DOMAINCHECK_DIR}/detect_worker.log"
|
||
|
||
systemctl daemon-reload
|
||
systemctl enable domaincheck-api
|
||
systemctl enable domaincheck-worker
|
||
systemctl restart domaincheck-api
|
||
systemctl restart domaincheck-worker
|
||
chown -R www:www "${REPO_DIR}"
|
||
|
||
echo
|
||
echo "国外主控机部署完成,建议继续执行:"
|
||
echo "curl http://127.0.0.1:8100/health"
|
||
echo "curl http://127.0.0.1:8100/api/v1/runtime/preflight"
|
||
echo "curl http://127.0.0.1:8100/api/v1/runtime/readiness"
|