forked from Eeveid/lightOps
新增主控一键安装脚本
This commit is contained in:
27
README.md
27
README.md
@@ -69,6 +69,33 @@ lightops/
|
|||||||
- Node.js 20 或更高版本。
|
- Node.js 20 或更高版本。
|
||||||
- Agent 运行能力优先面向 Linux 主机。
|
- Agent 运行能力优先面向 Linux 主机。
|
||||||
|
|
||||||
|
## 一条命令安装 Server
|
||||||
|
|
||||||
|
在目标 Linux 服务器上使用 root 执行:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -fsSL https://gitea.kmux.cn/Eeveid/lightOps/raw/branch/main/scripts/install-server.sh | bash
|
||||||
|
```
|
||||||
|
|
||||||
|
指定面板访问地址:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -fsSL https://gitea.kmux.cn/Eeveid/lightOps/raw/branch/main/scripts/install-server.sh | bash -s -- --public-url https://panel.example.com
|
||||||
|
```
|
||||||
|
|
||||||
|
安装脚本会自动安装基础依赖、Rust、Node.js,拉取远程仓库,构建前端和 Rust 二进制,写入 `/etc/lightops/server.toml`,注册并启动 `lightops-server` systemd 服务。安装完成后访问 `/init` 初始化管理员。
|
||||||
|
|
||||||
|
常用参数:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
--repo <url> Git 仓库地址
|
||||||
|
--branch <name> Git 分支,默认 main
|
||||||
|
--install-dir <path> 安装目录,默认 /opt/lightops
|
||||||
|
--bind <addr> 监听地址,默认 0.0.0.0:8080
|
||||||
|
--public-url <url> 面板外部访问地址
|
||||||
|
--skip-deps 跳过依赖安装检查
|
||||||
|
```
|
||||||
|
|
||||||
构建前端:
|
构建前端:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -1,32 +1,282 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env bash
|
||||||
set -eu
|
set -Eeuo pipefail
|
||||||
|
|
||||||
if [ "$(id -u)" -ne 0 ]; then
|
REPO_URL="https://gitea.kmux.cn/Eeveid/lightOps.git"
|
||||||
echo "请使用 root 用户运行" >&2
|
BRANCH="main"
|
||||||
|
INSTALL_DIR="/opt/lightops"
|
||||||
|
CONFIG_DIR="/etc/lightops"
|
||||||
|
BIND_ADDR="0.0.0.0:8080"
|
||||||
|
PUBLIC_URL=""
|
||||||
|
SKIP_DEPS="false"
|
||||||
|
FORCE="false"
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<'EOF'
|
||||||
|
LightOps Server 一键安装脚本
|
||||||
|
|
||||||
|
用法:
|
||||||
|
bash install-server.sh [选项]
|
||||||
|
|
||||||
|
选项:
|
||||||
|
--repo <url> Git 仓库地址,默认 https://gitea.kmux.cn/Eeveid/lightOps.git
|
||||||
|
--branch <name> Git 分支,默认 main
|
||||||
|
--install-dir <path> 安装目录,默认 /opt/lightops
|
||||||
|
--config-dir <path> 配置目录,默认 /etc/lightops
|
||||||
|
--bind <addr> 监听地址,默认 0.0.0.0:8080
|
||||||
|
--public-url <url> 面板访问地址,默认根据本机 IP 生成 http://<ip>:8080
|
||||||
|
--skip-deps 跳过系统依赖、Rust、Node.js 检查安装
|
||||||
|
--force 仓库存在未提交改动时仍继续,谨慎使用
|
||||||
|
-h, --help 显示帮助
|
||||||
|
|
||||||
|
示例:
|
||||||
|
curl -fsSL https://gitea.kmux.cn/Eeveid/lightOps/raw/branch/main/scripts/install-server.sh | bash
|
||||||
|
curl -fsSL https://gitea.kmux.cn/Eeveid/lightOps/raw/branch/main/scripts/install-server.sh | bash -s -- --public-url https://panel.example.com
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--repo)
|
||||||
|
REPO_URL="${2:?缺少 --repo 参数值}"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--branch)
|
||||||
|
BRANCH="${2:?缺少 --branch 参数值}"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--install-dir)
|
||||||
|
INSTALL_DIR="${2:?缺少 --install-dir 参数值}"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--config-dir)
|
||||||
|
CONFIG_DIR="${2:?缺少 --config-dir 参数值}"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--bind)
|
||||||
|
BIND_ADDR="${2:?缺少 --bind 参数值}"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--public-url)
|
||||||
|
PUBLIC_URL="${2:?缺少 --public-url 参数值}"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--skip-deps)
|
||||||
|
SKIP_DEPS="true"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--force)
|
||||||
|
FORCE="true"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-h|--help)
|
||||||
|
usage
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "未知参数:$1" >&2
|
||||||
|
usage >&2
|
||||||
|
exit 2
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ "$(id -u)" -ne 0 ]]; then
|
||||||
|
echo "请使用 root 用户运行,例如:curl -fsSL ... | bash" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
install -d /opt/lightops /etc/lightops
|
if [[ "$(uname -s)" != "Linux" ]]; then
|
||||||
chmod 0755 /opt/lightops
|
echo "LightOps Server 一键安装当前只支持 Linux 服务器" >&2
|
||||||
|
|
||||||
if [ ! -x /opt/lightops/lightops-server ]; then
|
|
||||||
echo "运行此脚本前,请先将 lightops-server 放到 /opt/lightops/lightops-server" >&2
|
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ ! -f /etc/lightops/server.toml ]; then
|
if ! command -v systemctl >/dev/null 2>&1; then
|
||||||
cat >/etc/lightops/server.toml <<'EOF'
|
echo "未检测到 systemd,当前一键安装脚本需要 systemd 管理服务" >&2
|
||||||
bind = "0.0.0.0:8080"
|
exit 1
|
||||||
database_url = "sqlite:///opt/lightops/lightops.db?mode=rwc"
|
fi
|
||||||
jwt_secret = "请替换为足够长的随机密钥"
|
|
||||||
public_url = "https://panel.example.com"
|
case "$INSTALL_DIR" in
|
||||||
static_dir = "/opt/lightops/web"
|
""|"/"|"/opt"|"/etc"|"/usr"|"/usr/local")
|
||||||
|
echo "安装目录过于危险:$INSTALL_DIR" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [[ "$INSTALL_DIR" == *" "* || "$CONFIG_DIR" == *" "* ]]; then
|
||||||
|
echo "安装目录和配置目录暂不支持空格" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log() {
|
||||||
|
printf '\033[1;32m[LightOps]\033[0m %s\n' "$*"
|
||||||
|
}
|
||||||
|
|
||||||
|
warn() {
|
||||||
|
printf '\033[1;33m[LightOps]\033[0m %s\n' "$*" >&2
|
||||||
|
}
|
||||||
|
|
||||||
|
fail() {
|
||||||
|
printf '\033[1;31m[LightOps]\033[0m %s\n' "$*" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
detect_public_url() {
|
||||||
|
local port
|
||||||
|
port="${BIND_ADDR##*:}"
|
||||||
|
local ip
|
||||||
|
ip="$(hostname -I 2>/dev/null | awk '{print $1}')"
|
||||||
|
if [[ -z "$ip" ]]; then
|
||||||
|
ip="127.0.0.1"
|
||||||
|
fi
|
||||||
|
echo "http://${ip}:${port}"
|
||||||
|
}
|
||||||
|
|
||||||
|
install_packages_apt() {
|
||||||
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
|
apt-get update
|
||||||
|
apt-get install -y ca-certificates curl git build-essential pkg-config sqlite3
|
||||||
|
}
|
||||||
|
|
||||||
|
install_packages_generic() {
|
||||||
|
if command -v apt-get >/dev/null 2>&1; then
|
||||||
|
install_packages_apt
|
||||||
|
elif command -v dnf >/dev/null 2>&1; then
|
||||||
|
dnf install -y ca-certificates curl git gcc gcc-c++ make pkgconf-pkg-config sqlite
|
||||||
|
elif command -v yum >/dev/null 2>&1; then
|
||||||
|
yum install -y ca-certificates curl git gcc gcc-c++ make pkgconfig sqlite
|
||||||
|
elif command -v pacman >/dev/null 2>&1; then
|
||||||
|
pacman -Sy --noconfirm ca-certificates curl git base-devel pkgconf sqlite
|
||||||
|
else
|
||||||
|
fail "未识别系统包管理器,请手动安装 curl、git、C/C++ 构建工具、pkg-config、sqlite3"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
node_major() {
|
||||||
|
node -v 2>/dev/null | sed -E 's/^v([0-9]+).*/\1/' || true
|
||||||
|
}
|
||||||
|
|
||||||
|
ensure_node() {
|
||||||
|
local major
|
||||||
|
major="$(node_major)"
|
||||||
|
if [[ -n "$major" && "$major" -ge 18 ]] && command -v npm >/dev/null 2>&1; then
|
||||||
|
log "Node.js 已安装:$(node -v)"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
if command -v apt-get >/dev/null 2>&1; then
|
||||||
|
log "安装 Node.js 20"
|
||||||
|
curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
|
||||||
|
apt-get install -y nodejs
|
||||||
|
elif command -v dnf >/dev/null 2>&1; then
|
||||||
|
dnf install -y nodejs npm
|
||||||
|
elif command -v yum >/dev/null 2>&1; then
|
||||||
|
yum install -y nodejs npm
|
||||||
|
elif command -v pacman >/dev/null 2>&1; then
|
||||||
|
pacman -Sy --noconfirm nodejs npm
|
||||||
|
else
|
||||||
|
fail "无法自动安装 Node.js,请手动安装 Node.js 18 或更高版本"
|
||||||
|
fi
|
||||||
|
major="$(node_major)"
|
||||||
|
if [[ -z "$major" || "$major" -lt 18 ]]; then
|
||||||
|
fail "Node.js 版本过低,需要 18 或更高版本,当前:$(node -v 2>/dev/null || echo 未安装)"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
ensure_rust() {
|
||||||
|
if command -v cargo >/dev/null 2>&1; then
|
||||||
|
log "Rust 已安装:$(cargo --version)"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
log "安装 Rust 稳定版工具链"
|
||||||
|
curl --proto '=https' --tlsv1.2 -fsSL https://sh.rustup.rs | sh -s -- -y --profile minimal
|
||||||
|
# shellcheck disable=SC1091
|
||||||
|
source "$HOME/.cargo/env"
|
||||||
|
if ! command -v cargo >/dev/null 2>&1; then
|
||||||
|
fail "Rust 安装失败,请检查网络或手动安装 rustup"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
ensure_deps() {
|
||||||
|
if [[ "$SKIP_DEPS" == "true" ]]; then
|
||||||
|
warn "已跳过依赖安装检查"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
log "安装系统依赖"
|
||||||
|
install_packages_generic
|
||||||
|
ensure_node
|
||||||
|
ensure_rust
|
||||||
|
}
|
||||||
|
|
||||||
|
prepare_repo() {
|
||||||
|
log "准备代码仓库:$INSTALL_DIR"
|
||||||
|
mkdir -p "$(dirname "$INSTALL_DIR")"
|
||||||
|
if [[ -d "$INSTALL_DIR/.git" ]]; then
|
||||||
|
cd "$INSTALL_DIR"
|
||||||
|
if [[ "$FORCE" != "true" && -n "$(git status --porcelain)" ]]; then
|
||||||
|
fail "安装目录存在未提交改动:$INSTALL_DIR。请先处理改动,或使用 --force"
|
||||||
|
fi
|
||||||
|
git remote set-url origin "$REPO_URL" || true
|
||||||
|
git fetch origin "$BRANCH"
|
||||||
|
git checkout "$BRANCH"
|
||||||
|
git pull --ff-only origin "$BRANCH"
|
||||||
|
elif [[ -e "$INSTALL_DIR" && -n "$(find "$INSTALL_DIR" -mindepth 1 -maxdepth 1 2>/dev/null | head -n 1)" ]]; then
|
||||||
|
fail "安装目录已存在且不是 Git 仓库:$INSTALL_DIR"
|
||||||
|
else
|
||||||
|
rm -rf "$INSTALL_DIR"
|
||||||
|
git clone --branch "$BRANCH" "$REPO_URL" "$INSTALL_DIR"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
build_project() {
|
||||||
|
log "构建前端"
|
||||||
|
cd "$INSTALL_DIR/web"
|
||||||
|
if [[ -f package-lock.json ]]; then
|
||||||
|
npm ci
|
||||||
|
else
|
||||||
|
npm install
|
||||||
|
fi
|
||||||
|
npm run build
|
||||||
|
|
||||||
|
log "构建 Server 和 Agent"
|
||||||
|
cd "$INSTALL_DIR"
|
||||||
|
cargo build --release -p lightops-server -p lightops-agent
|
||||||
|
|
||||||
|
install -m 0755 "$INSTALL_DIR/target/release/lightops-server" "$INSTALL_DIR/lightops-server"
|
||||||
|
install -m 0755 "$INSTALL_DIR/target/release/lightops-agent" "$INSTALL_DIR/lightops-agent"
|
||||||
|
install -m 0755 "$INSTALL_DIR/target/release/lightops-server" /usr/local/bin/lightops-server
|
||||||
|
install -m 0755 "$INSTALL_DIR/target/release/lightops-agent" /usr/local/bin/lightops-agent
|
||||||
|
}
|
||||||
|
|
||||||
|
write_config() {
|
||||||
|
mkdir -p "$CONFIG_DIR" "$INSTALL_DIR"
|
||||||
|
if [[ -z "$PUBLIC_URL" ]]; then
|
||||||
|
PUBLIC_URL="$(detect_public_url)"
|
||||||
|
fi
|
||||||
|
local jwt_secret
|
||||||
|
if command -v openssl >/dev/null 2>&1; then
|
||||||
|
jwt_secret="$(openssl rand -hex 32)"
|
||||||
|
else
|
||||||
|
jwt_secret="$(date +%s%N)-$(hostname)-$RANDOM-$RANDOM"
|
||||||
|
fi
|
||||||
|
if [[ -f "$CONFIG_DIR/server.toml" ]]; then
|
||||||
|
log "保留已有配置:$CONFIG_DIR/server.toml"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
log "生成 Server 配置:$CONFIG_DIR/server.toml"
|
||||||
|
cat >"$CONFIG_DIR/server.toml" <<EOF
|
||||||
|
bind = "$BIND_ADDR"
|
||||||
|
database_url = "sqlite://$INSTALL_DIR/lightops.db?mode=rwc"
|
||||||
|
jwt_secret = "$jwt_secret"
|
||||||
|
public_url = "$PUBLIC_URL"
|
||||||
|
static_dir = "$INSTALL_DIR/web/dist"
|
||||||
registration_token_ttl_minutes = 30
|
registration_token_ttl_minutes = 30
|
||||||
task_timeout_secs = 20
|
task_timeout_secs = 20
|
||||||
EOF
|
EOF
|
||||||
fi
|
chmod 0600 "$CONFIG_DIR/server.toml"
|
||||||
|
}
|
||||||
|
|
||||||
cat >/etc/systemd/system/lightops-server.service <<'EOF'
|
write_service() {
|
||||||
|
log "写入 systemd 服务"
|
||||||
|
cat >/etc/systemd/system/lightops-server.service <<EOF
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=LightOps Server
|
Description=LightOps Server
|
||||||
After=network-online.target
|
After=network-online.target
|
||||||
@@ -36,8 +286,8 @@ StartLimitBurst=10
|
|||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=simple
|
Type=simple
|
||||||
WorkingDirectory=/opt/lightops
|
WorkingDirectory=$INSTALL_DIR
|
||||||
ExecStart=/opt/lightops/lightops-server --config /etc/lightops/server.toml
|
ExecStart=$INSTALL_DIR/lightops-server --config $CONFIG_DIR/server.toml
|
||||||
Restart=always
|
Restart=always
|
||||||
RestartSec=5
|
RestartSec=5
|
||||||
KillSignal=SIGINT
|
KillSignal=SIGINT
|
||||||
@@ -47,13 +297,42 @@ User=root
|
|||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
||||||
EOF
|
EOF
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl enable lightops-server
|
||||||
|
}
|
||||||
|
|
||||||
systemctl daemon-reload
|
start_service() {
|
||||||
systemctl enable --now lightops-server
|
log "启动 LightOps Server"
|
||||||
sleep 2
|
systemctl restart lightops-server
|
||||||
if ! systemctl is-active --quiet lightops-server; then
|
sleep 2
|
||||||
echo "Server 启动失败,最近日志如下:" >&2
|
if ! systemctl is-active --quiet lightops-server; then
|
||||||
journalctl -u lightops-server -n 80 --no-pager >&2 || true
|
journalctl -u lightops-server -n 120 --no-pager >&2 || true
|
||||||
exit 1
|
fail "LightOps Server 启动失败"
|
||||||
fi
|
fi
|
||||||
echo "LightOps Server 已安装并运行"
|
}
|
||||||
|
|
||||||
|
print_result() {
|
||||||
|
local port
|
||||||
|
port="${BIND_ADDR##*:}"
|
||||||
|
cat <<EOF
|
||||||
|
|
||||||
|
LightOps Server 已安装完成
|
||||||
|
|
||||||
|
访问地址:$PUBLIC_URL
|
||||||
|
初始化入口:$PUBLIC_URL/init
|
||||||
|
安装目录:$INSTALL_DIR
|
||||||
|
配置文件:$CONFIG_DIR/server.toml
|
||||||
|
服务名称:lightops-server
|
||||||
|
查看日志:journalctl -u lightops-server -f
|
||||||
|
|
||||||
|
如果服务器启用了防火墙,请放行 TCP $port。
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
ensure_deps
|
||||||
|
prepare_repo
|
||||||
|
build_project
|
||||||
|
write_config
|
||||||
|
write_service
|
||||||
|
start_service
|
||||||
|
print_result
|
||||||
|
|||||||
Reference in New Issue
Block a user