#!/bin/sh set -eu SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) PROJECT_ROOT=$(CDPATH= cd -- "$SCRIPT_DIR/.." && pwd) PREFIX="${PREFIX:-/opt/backupx}" ETC_DIR="${ETC_DIR:-/etc/backupx}" SERVICE_NAME="backupx" APP_USER="backupx" APP_GROUP="backupx" if [ -f "$SCRIPT_DIR/backupx" ] && [ -d "$SCRIPT_DIR/web" ]; then BIN_SOURCE="${BIN_SOURCE:-$SCRIPT_DIR/backupx}" WEB_SOURCE="${WEB_SOURCE:-$SCRIPT_DIR/web}" CONFIG_TEMPLATE="${CONFIG_TEMPLATE:-$SCRIPT_DIR/config.example.yaml}" NGINX_SOURCE="${NGINX_SOURCE:-$SCRIPT_DIR/nginx.conf}" else SOURCE_BIN_DEFAULT="$PROJECT_ROOT/server/bin/backupx" # Keep compatibility with contributors who built the historical path by # hand, while matching the canonical `make build` output first. if [ ! -f "$SOURCE_BIN_DEFAULT" ] && [ -f "$PROJECT_ROOT/server/backupx" ]; then SOURCE_BIN_DEFAULT="$PROJECT_ROOT/server/backupx" fi BIN_SOURCE="${BIN_SOURCE:-$SOURCE_BIN_DEFAULT}" WEB_SOURCE="${WEB_SOURCE:-$PROJECT_ROOT/web/dist}" CONFIG_TEMPLATE="${CONFIG_TEMPLATE:-$PROJECT_ROOT/server/config.example.yaml}" NGINX_SOURCE="${NGINX_SOURCE:-$PROJECT_ROOT/deploy/nginx.conf}" fi SERVICE_SOURCE="${SERVICE_SOURCE:-$PROJECT_ROOT/deploy/backupx.service}" if [ "$(id -u)" -ne 0 ]; then echo "请使用 root 或 sudo 执行安装脚本。" >&2 exit 1 fi if [ ! -f "$BIN_SOURCE" ]; then echo "Backend binary not found / 未找到后端二进制:$BIN_SOURCE" >&2 echo "源码树安装请先在仓库根目录执行 make build(产物:server/bin/backupx)。" >&2 echo "For a source install, run 'make build' in the repository root first." >&2 echo "发布包安装请确认当前目录包含 ./backupx、./web 和 ./install.sh。" >&2 exit 1 fi if [ ! -d "$WEB_SOURCE" ]; then echo "未找到前端构建产物:$WEB_SOURCE" >&2 echo "源码树安装请先执行:cd \"$PROJECT_ROOT/web\" && npm run build" >&2 echo "发布包安装请确认当前目录包含 ./web。" >&2 exit 1 fi if [ ! -f "$CONFIG_TEMPLATE" ]; then echo "未找到配置模板:$CONFIG_TEMPLATE" >&2 exit 1 fi if ! getent group "$APP_GROUP" >/dev/null 2>&1; then groupadd --system "$APP_GROUP" fi if ! id "$APP_USER" >/dev/null 2>&1; then useradd --system --gid "$APP_GROUP" --home-dir "$PREFIX" --shell /usr/sbin/nologin "$APP_USER" fi install -d -o "$APP_USER" -g "$APP_GROUP" "$PREFIX" "$PREFIX/bin" "$PREFIX/web" "$PREFIX/data" "$ETC_DIR" install -m 0755 "$BIN_SOURCE" "$PREFIX/bin/backupx" cp -R "$WEB_SOURCE/." "$PREFIX/web/" chown -R "$APP_USER:$APP_GROUP" "$PREFIX" if [ ! -f "$ETC_DIR/config.yaml" ]; then install -o "$APP_USER" -g "$APP_GROUP" -m 0640 "$CONFIG_TEMPLATE" "$ETC_DIR/config.yaml" fi # 确保服务账户能读取配置:历史版本曾以 root:root 0640 安装配置, # 导致以 backupx 身份运行的服务因无权读取配置而启动失败(exit 1)。 chown "$APP_USER:$APP_GROUP" "$ETC_DIR/config.yaml" if [ -f "$SERVICE_SOURCE" ]; then install -m 0644 "$SERVICE_SOURCE" "/etc/systemd/system/$SERVICE_NAME.service" else cat > "/etc/systemd/system/$SERVICE_NAME.service" </dev/null 2>&1; then if curl -fsS --max-time 2 "$HEALTH_URL" >/dev/null 2>&1; then READY=1 break fi elif command -v wget >/dev/null 2>&1; then if wget -q -T 2 -O /dev/null "$HEALTH_URL"; then READY=1 break fi else echo "Warning / 警告:未找到 curl 或 wget,仅验证 systemd 服务状态。" >&2 READY=1 break fi fi ATTEMPT=$((ATTEMPT + 1)) sleep 1 done if [ "$READY" -ne 1 ]; then echo "BackupX did not become ready at $HEALTH_URL / 服务未通过就绪检查。" >&2 systemctl status "$SERVICE_NAME" --no-pager >&2 || true journalctl -u "$SERVICE_NAME" -n 50 --no-pager >&2 || true exit 1 fi if [ -d "/etc/nginx/conf.d" ] && [ -f "$NGINX_SOURCE" ]; then install -m 0644 "$NGINX_SOURCE" "/etc/nginx/conf.d/$SERVICE_NAME.conf" if command -v nginx >/dev/null 2>&1; then nginx -t systemctl reload nginx || true fi fi cat <:8340 首次访问 / First sign-in: 1. 打开上面的地址,并可在登录页右上角选择 中文 或 English。 2. 页面显示“系统初始化 / System setup”时,创建首个管理员用户名和密码。 3. 如果未显示初始化表单,请先检查:$HEALTH_URL (如已安装 nginx,脚本会自动写入反向代理配置,可继续用 80 端口访问。) 排查:若服务未监听端口,请查看日志: journalctl -u "$SERVICE_NAME" -n 50 --no-pager 如需修改监听地址、数据库路径或日志级别,请编辑 "$ETC_DIR/config.yaml" 后执行: systemctl restart "$SERVICE_NAME" MESSAGE