Files
QZMusic-Web/install.sh

207 lines
6.7 KiB
Bash
Executable File
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.
#!/bin/bash
# QZMusic-Web 一键安装脚本
# 从 Gitea 仓库获取并自动部署,安装后以 systemd 服务对外暴露 1219 端口
# 使用方法:
# bash <(curl -sL http://171.80.3.149:4321/miao-moe/QZMusic-Web/raw/branch/master/install.sh)
# 或直接在项目目录运行: ./install.sh
set -e
echo "=========================================="
echo " QZMusic-Web 一键安装 (systemd)"
echo "=========================================="
echo ""
# ========= 配置 =========
REPO_URL="http://171.80.3.149:4321/miao-moe/QZMusic-Web.git"
INSTALL_DIR="/opt/QZMusic-Web"
PORT=1219
SERVICE_NAME="qzmusic-web"
BRANCH="master"
# ========= 颜色 =========
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
NC='\033[0m'
log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
# ========= 权限 =========
SUDO=""
if [ "$EUID" -ne 0 ]; then
SUDO="sudo"
log_warn "当前非 root将使用 sudo 执行系统级操作。"
fi
# ========= Node.js 检查 =========
if ! command -v node &> /dev/null; then
log_error "Node.js 未安装!请先安装 Node.js (推荐 v18+)"
echo " Ubuntu/Debian: curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - && sudo apt-get install -y nodejs"
echo " CentOS/RHEL: curl -fsSL https://rpm.nodesource.com/setup_20.x | sudo bash - && sudo yum install -y nodejs"
exit 1
fi
log_info "Node.js 版本: $(node -v)"
log_info "npm 版本: $(npm -v)"
echo ""
# ========= 克隆/拉取代码 =========
if [ -d "$INSTALL_DIR" ]; then
if [ -d "$INSTALL_DIR/.git" ]; then
log_info "检测到已有 git 仓库,正在更新到最新版本..."
cd "$INSTALL_DIR"
git fetch origin "$BRANCH"
git reset --hard "origin/$BRANCH"
if [ $? -ne 0 ]; then
log_error "更新失败!"
exit 1
fi
else
log_warn "目录 $INSTALL_DIR 已存在但不是 git 仓库,将清理后重新克隆..."
$SUDO rm -rf "$INSTALL_DIR"
log_info "正在从仓库获取代码 ($REPO_URL)..."
$SUDO git clone -b "$BRANCH" "$REPO_URL" "$INSTALL_DIR"
$SUDO chown -R "$(whoami)" "$INSTALL_DIR" 2>/dev/null || true
fi
else
log_info "正在创建安装目录: $INSTALL_DIR"
$SUDO mkdir -p "$(dirname "$INSTALL_DIR")"
log_info "正在从仓库获取代码 ($REPO_URL)..."
$SUDO git clone -b "$BRANCH" "$REPO_URL" "$INSTALL_DIR"
$SUDO chown -R "$(whoami)" "$INSTALL_DIR" 2>/dev/null || true
fi
cd "$INSTALL_DIR"
echo ""
# ========= 安装依赖 =========
log_info "正在安装依赖 (使用淘宝镜像加速)..."
npm install --registry=https://registry.npmmirror.com --loglevel=error
if [ $? -ne 0 ]; then
log_error "依赖安装失败!"
exit 1
fi
log_info "依赖安装成功!"
echo ""
# ========= 构建 =========
log_info "正在构建项目..."
npm run build
if [ $? -ne 0 ]; then
log_error "构建失败!"
exit 1
fi
log_info "项目构建成功!"
echo ""
# ========= 部署 systemd 服务 =========
log_info "正在部署 systemd 服务: $SERVICE_NAME"
SERVICE_FILE="/etc/systemd/system/$SERVICE_NAME.service"
# 停止旧的监听(以防之前有进程占端口)
if command -v lsof &> /dev/null; then
OLD_PID=$(lsof -ti:$PORT 2>/dev/null || true)
if [ -n "$OLD_PID" ]; then
log_warn "端口 $PORT 已被占用 (PID: $OLD_PID),正在清理..."
$SUDO kill $OLD_PID 2>/dev/null || true
sleep 2
fi
fi
# 如果之前有同名服务,先停掉
if systemctl list-unit-files 2>/dev/null | grep -q "$SERVICE_NAME.service"; then
$SUDO systemctl stop "$SERVICE_NAME" 2>/dev/null || true
$SUDO systemctl disable "$SERVICE_NAME" 2>/dev/null || true
fi
# 写入服务文件
$SUDO tee "$SERVICE_FILE" > /dev/null <<EOF
[Unit]
Description=QZMusic Web Server
After=network.target
[Service]
Type=simple
WorkingDirectory=$INSTALL_DIR
ExecStart=$(command -v node) $INSTALL_DIR/server.cjs
Restart=always
RestartSec=3
Environment=NODE_ENV=production
Environment=QZMUSIC_PORT=$PORT
Environment=QZMUSIC_HOST=0.0.0.0
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
EOF
# 重载 & 启动
$SUDO systemctl daemon-reload
$SUDO systemctl enable "$SERVICE_NAME"
$SUDO systemctl restart "$SERVICE_NAME"
sleep 2
# ========= 防火墙开放 =========
log_info "正在开放防火墙端口 $PORT..."
if command -v firewall-cmd &> /dev/null && systemctl is-active --quiet firewalld 2>/dev/null; then
$SUDO firewall-cmd --permanent --add-port=${PORT}/tcp >/dev/null
$SUDO firewall-cmd --reload >/dev/null
log_info "firewalld: 已放行 $PORT/tcp"
elif command -v ufw &> /dev/null && systemctl is-active --quiet ufw 2>/dev/null; then
$SUDO ufw allow ${PORT}/tcp >/dev/null
log_info "ufw: 已放行 $PORT/tcp"
else
log_warn "未检测到活动的 firewalld/ufw跳过防火墙配置。如有其他防火墙请手动放行 $PORT/tcp。"
fi
# ========= 云服务器安全组提醒 =========
log_info "已处理系统防火墙。如果你的机器是云服务器,请记得在云厂商控制台的『安全组』也放行 $PORT/tcp。"
echo ""
# ========= 验证 =========
log_info "等待服务启动..."
for i in 1 2 3 4 5; do
if curl -s -o /dev/null -w "%{http_code}" "http://127.0.0.1:$PORT/" 2>/dev/null | grep -q "200"; then
break
fi
sleep 1
done
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" "http://127.0.0.1:$PORT/" 2>/dev/null || echo "000")
STATUS=$($SUDO systemctl is-active "$SERVICE_NAME" 2>/dev/null || echo "unknown")
# 获取本机公网/局域网 IP
LAN_IP=$(hostname -I 2>/dev/null | awk '{print $1}')
WAN_IP=$(curl -s --max-time 5 https://ifconfig.me 2>/dev/null || curl -s --max-time 5 https://api.ipify.org 2>/dev/null || echo "")
echo ""
echo "=========================================="
echo " 🎉 安装完成!"
echo "=========================================="
echo ""
echo "📂 安装目录: $INSTALL_DIR"
echo "🖥 服务状态: $STATUS"
echo "🌐 本地访问: http://127.0.0.1:$PORT (HTTP $HTTP_CODE)"
if [ -n "$LAN_IP" ]; then
echo "🏠 局域网: http://$LAN_IP:$PORT"
fi
if [ -n "$WAN_IP" ]; then
echo "🌍 公网: http://$WAN_IP:$PORT"
fi
echo ""
echo "管理命令:"
echo " 查看日志: sudo journalctl -u $SERVICE_NAME -f --since \"5 min ago\""
echo " 启动服务: sudo systemctl start $SERVICE_NAME"
echo " 停止服务: sudo systemctl stop $SERVICE_NAME"
echo " 重启服务: sudo systemctl restart $SERVICE_NAME"
echo " 开机自启: sudo systemctl enable $SERVICE_NAME"
echo " 更新代码: cd $INSTALL_DIR && git pull && npm run build && sudo systemctl restart $SERVICE_NAME"
echo ""
echo "卸载/清除所有部署: bash $INSTALL_DIR/uninstall.sh"
echo ""