#!/bin/bash # # FunMC 一键部署脚本 # 用法: bash install.sh [ -force ] # - 无参数: 更新安装,保留数据库与现有配置(server.env / relay.env / credentials.txt) # - -force: 强制覆盖安装,清空数据库并重写所有配置 # set -e # 颜色定义 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' CYAN='\033[0;36m' NC='\033[0m' # 配置 FUNMC_VERSION="0.1.0" INSTALL_DIR="/opt/funmc" CONFIG_DIR="/etc/funmc" DATA_DIR="/var/lib/funmc" LOG_DIR="/var/log/funmc" echo -e "${CYAN}" echo "╔═══════════════════════════════════════════════════════════╗" echo "║ ║" echo "║ FunMC 服务端一键部署脚本 v${FUNMC_VERSION} ║" echo "║ ║" echo "║ 魔幻方开发 ║" echo "║ ║" echo "╚═══════════════════════════════════════════════════════════╝" echo -e "${NC}" if [ "$FORCE_INSTALL" -eq 1 ]; then echo -e "${YELLOW}运行模式: 强制覆盖安装(将清空数据库并重写配置)${NC}" else echo -e "${GREEN}运行模式: 更新安装(保留数据库与现有配置)${NC}" fi echo "" # 检查 root 权限 if [ "$EUID" -ne 0 ]; then echo -e "${RED}请使用 root 权限运行此脚本${NC}" echo "sudo bash install.sh" exit 1 fi # 解析参数:-force 或 --force 为强制覆盖安装,否则为更新(不覆盖数据) FORCE_INSTALL=0 for arg in "$@"; do if [ "$arg" = "-force" ] || [ "$arg" = "--force" ]; then FORCE_INSTALL=1 break fi done # 检测系统 detect_os() { if [ -f /etc/os-release ]; then . /etc/os-release OS=$ID OS_VERSION=$VERSION_ID else echo -e "${RED}无法检测操作系统${NC}" exit 1 fi echo -e "${GREEN}检测到系统: $OS $OS_VERSION${NC}" } # 安装依赖 install_deps() { echo -e "${YELLOW}[1/7] 安装系统依赖...${NC}" case $OS in ubuntu|debian) apt-get update -qq apt-get install -y -qq curl wget git build-essential pkg-config libssl-dev postgresql postgresql-contrib nginx certbot python3-certbot-nginx ;; centos|rhel|fedora) dnf install -y curl wget git gcc openssl-devel postgresql-server postgresql-contrib nginx certbot python3-certbot-nginx postgresql-setup --initdb ;; *) echo -e "${RED}不支持的操作系统: $OS${NC}" exit 1 ;; esac echo -e "${GREEN}✓ 系统依赖安装完成${NC}" } # 安装 Rust install_rust() { echo -e "${YELLOW}[2/7] 安装 Rust...${NC}" if command -v cargo &> /dev/null; then echo -e "${GREEN}✓ Rust 已安装${NC}" else curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y source $HOME/.cargo/env echo -e "${GREEN}✓ Rust 安装完成${NC}" fi } # 安装 Node.js install_nodejs() { echo -e "${YELLOW}[3/7] 安装 Node.js...${NC}" if command -v node &> /dev/null; then echo -e "${GREEN}✓ Node.js 已安装${NC}" else curl -fsSL https://deb.nodesource.com/setup_20.x | bash - apt-get install -y nodejs echo -e "${GREEN}✓ Node.js 安装完成${NC}" fi } # 配置数据库(-force 时强制删除并重建,否则仅确保库存在且不覆盖数据) setup_database() { echo -e "${YELLOW}[4/7] 配置数据库...${NC}" systemctl enable postgresql systemctl start postgresql if [ "$FORCE_INSTALL" -eq 1 ]; then # 强制断开对 funmc 库的所有连接,再删除库和用户 sudo -u postgres psql -d postgres -c "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = 'funmc' AND pid <> pg_backend_pid();" 2>/dev/null || true sudo -u postgres psql -d postgres -c "DROP DATABASE IF EXISTS funmc;" 2>/dev/null || true sudo -u postgres psql -d postgres -c "DROP USER IF EXISTS funmc;" 2>/dev/null || true sudo -u postgres psql -d postgres -c "CREATE USER funmc WITH PASSWORD '12345678';" sudo -u postgres psql -d postgres -c "CREATE DATABASE funmc OWNER funmc;" sudo -u postgres psql -d postgres -c "GRANT ALL PRIVILEGES ON DATABASE funmc TO funmc;" echo -e "${GREEN}✓ 数据库已强制重建(密码 12345678)${NC}" else # 更新模式:不删除,仅确保用户和库存在(若已存在则跳过) sudo -u postgres psql -d postgres -c "CREATE USER funmc WITH PASSWORD '12345678';" 2>/dev/null || true sudo -u postgres psql -d postgres -c "CREATE DATABASE funmc OWNER funmc;" 2>/dev/null || true sudo -u postgres psql -d postgres -c "GRANT ALL PRIVILEGES ON DATABASE funmc TO funmc;" 2>/dev/null || true echo -e "${GREEN}✓ 数据库检查完成(未覆盖现有数据)${NC}" fi # 配置 pg_hba.conf(仅追加缺失项) PG_HBA=$(sudo -u postgres psql -t -c "SHOW hba_file;" | xargs) if ! grep -q "funmc" "$PG_HBA"; then echo "local funmc funmc md5" >> "$PG_HBA" echo "host funmc funmc 127.0.0.1/32 md5" >> "$PG_HBA" systemctl reload postgresql fi } # 下载并编译 FunMC build_funmc() { echo -e "${YELLOW}[5/7] 编译 FunMC...${NC}" # 创建目录(含客户端下载目录) mkdir -p $INSTALL_DIR $INSTALL_DIR/downloads $CONFIG_DIR $DATA_DIR $LOG_DIR # 克隆或更新代码 if [ -d "$INSTALL_DIR/src" ]; then cd $INSTALL_DIR/src git pull else git clone https://gt.funmc.cn/xiaobai/FunConnect.git $INSTALL_DIR/src cd $INSTALL_DIR/src fi # 编译服务端 source $HOME/.cargo/env cargo build --release -p funmc-server -p funmc-relay-server # 复制二进制文件(包名与二进制名不同:server / relay-server) cp target/release/server $INSTALL_DIR/funmc-server cp target/release/relay-server $INSTALL_DIR/funmc-relay-server # 编译管理面板前端(使用官方 registry 避免镜像返回 HTML 导致 FETCH_ERROR) cd $INSTALL_DIR/src/admin-panel npm install --registry https://registry.npmjs.org/ npm run build cp -r dist $INSTALL_DIR/admin-panel echo -e "${GREEN}✓ FunMC 编译完成${NC}" } # 配置服务(-force 时重写配置;否则若已有配置则保留仅做迁移与重启) configure_services() { echo -e "${YELLOW}[6/7] 配置服务...${NC}" WROTE_CONFIG=0 if [ "$FORCE_INSTALL" -eq 1 ] || [ ! -f "$CONFIG_DIR/server.env" ]; then # 强制安装或首次安装:生成新配置 WROTE_CONFIG=1 DB_PASSWORD="12345678" JWT_SECRET=$(openssl rand -base64 48 | tr -dc 'a-zA-Z0-9' | head -c 48) ADMIN_PASSWORD=$(openssl rand -base64 16 | tr -dc 'a-zA-Z0-9' | head -c 12) SERVER_IP=$(curl -s ifconfig.me || curl -s ipinfo.io/ip || hostname -I | awk '{print $1}') cat > $CONFIG_DIR/server.env << EOF # FunMC 服务端配置 DATABASE_URL=postgres://funmc:${DB_PASSWORD}@localhost/funmc JWT_SECRET=${JWT_SECRET} BIND_ADDR=0.0.0.0:3000 QUIC_PORT=3001 RUST_LOG=info # 服务器信息 SERVER_NAME=FunMC Server SERVER_IP=${SERVER_IP} SERVER_DOMAIN= # 管理面板 ADMIN_ENABLED=true ADMIN_USERNAME=admin ADMIN_PASSWORD=${ADMIN_PASSWORD} # 客户端下载 CLIENT_DOWNLOAD_ENABLED=true CLIENT_VERSION=${FUNMC_VERSION} DOWNLOADS_DIR=$INSTALL_DIR/downloads EOF cat > $CONFIG_DIR/relay.env << EOF RELAY_PORT=7900 JWT_SECRET=${JWT_SECRET} RUST_LOG=info EOF else # 更新模式:保留现有配置,仅确保 DB_PASSWORD 等变量存在供后续迁移使用 DB_PASSWORD=$(grep DATABASE_URL "$CONFIG_DIR/server.env" 2>/dev/null | sed -n 's/.*:\/\/funmc:\([^@]*\)@.*/\1/p') if [ -z "$DB_PASSWORD" ]; then DB_PASSWORD="12345678" fi echo -e "${GREEN}✓ 保留现有配置(未覆盖 server.env / relay.env)${NC}" fi # 创建 systemd 服务文件(始终更新以便安装路径等变更生效) cat > /etc/systemd/system/funmc-server.service << EOF [Unit] Description=FunMC API Server After=network.target postgresql.service [Service] Type=simple User=root WorkingDirectory=$INSTALL_DIR EnvironmentFile=$CONFIG_DIR/server.env ExecStart=$INSTALL_DIR/funmc-server Restart=always RestartSec=10 [Install] WantedBy=multi-user.target EOF cat > /etc/systemd/system/funmc-relay.service << EOF [Unit] Description=FunMC Relay Server After=network.target [Service] Type=simple User=root WorkingDirectory=$INSTALL_DIR EnvironmentFile=$CONFIG_DIR/relay.env ExecStart=$INSTALL_DIR/funmc-relay-server Restart=always RestartSec=5 [Install] WantedBy=multi-user.target EOF # 安装 sqlx-cli(若未安装)并运行数据库迁移 export PATH="$HOME/.cargo/bin:$PATH" if ! command -v sqlx &> /dev/null; then cargo install sqlx-cli --no-default-features --features postgres fi cd $INSTALL_DIR/src/server export DATABASE_URL="postgres://funmc:${DB_PASSWORD}@localhost/funmc" sqlx migrate run # 启动服务 systemctl daemon-reload systemctl enable funmc-server funmc-relay systemctl start funmc-server funmc-relay echo -e "${GREEN}✓ 服务配置完成${NC}" # 仅强制/首次安装时写入凭据文件,更新模式不覆盖 if [ "$WROTE_CONFIG" -eq 1 ]; then cat > $CONFIG_DIR/credentials.txt << EOF ====================================== FunMC 服务端安装信息 ====================================== 服务器 IP: ${SERVER_IP} API 地址: http://${SERVER_IP}:3000 管理面板: http://${SERVER_IP}:3000/admin 管理员账号: admin 管理员密码: ${ADMIN_PASSWORD} 数据库密码: ${DB_PASSWORD} JWT 密钥: ${JWT_SECRET} ====================================== 请妥善保管此文件! ====================================== EOF chmod 600 $CONFIG_DIR/credentials.txt fi } # 配置防火墙 configure_firewall() { echo -e "${YELLOW}[7/7] 配置防火墙...${NC}" if command -v ufw &> /dev/null; then ufw allow 80/tcp ufw allow 443/tcp ufw allow 3000/tcp ufw allow 7900/udp ufw allow 7901/udp echo -e "${GREEN}✓ UFW 防火墙配置完成${NC}" elif command -v firewall-cmd &> /dev/null; then firewall-cmd --permanent --add-port=80/tcp firewall-cmd --permanent --add-port=443/tcp firewall-cmd --permanent --add-port=3000/tcp firewall-cmd --permanent --add-port=7900/udp firewall-cmd --permanent --add-port=7901/udp firewall-cmd --reload echo -e "${GREEN}✓ firewalld 防火墙配置完成${NC}" else echo -e "${YELLOW}! 未检测到防火墙,请手动开放端口 80, 443, 3000, 7900, 7901${NC}" fi } # 显示完成信息 show_completion() { SERVER_IP=$(cat $CONFIG_DIR/server.env | grep SERVER_IP | cut -d= -f2) ADMIN_PASSWORD=$(cat $CONFIG_DIR/server.env | grep ADMIN_PASSWORD | cut -d= -f2) echo "" echo -e "${CYAN}╔═══════════════════════════════════════════════════════════╗${NC}" echo -e "${CYAN}║ ║${NC}" echo -e "${CYAN}║ ${GREEN}FunMC 安装完成!${CYAN} ║${NC}" echo -e "${CYAN}║ ║${NC}" echo -e "${CYAN}╚═══════════════════════════════════════════════════════════╝${NC}" echo "" echo -e "${GREEN}服务器信息:${NC}" echo -e " API 地址: http://${SERVER_IP}:3000" echo -e " 管理面板: http://${SERVER_IP}:3000/admin" echo "" echo -e "${GREEN}管理员登录:${NC}" echo -e " 用户名: admin" echo -e " 密码: ${ADMIN_PASSWORD}" echo "" echo -e "${GREEN}客户端下载:${NC}" echo -e " http://${SERVER_IP}:3000/download" echo "" echo -e "${YELLOW}重要文件:${NC}" echo -e " 配置文件: $CONFIG_DIR/server.env" echo -e " 凭据信息: $CONFIG_DIR/credentials.txt" echo -e " 日志文件: $LOG_DIR/" echo "" echo -e "${CYAN}服务管理命令:${NC}" echo -e " 查看状态: systemctl status funmc-server" echo -e " 重启服务: systemctl restart funmc-server" echo -e " 查看日志: journalctl -u funmc-server -f" echo "" echo -e "${GREEN}魔幻方开发 - 让 Minecraft 联机变得简单${NC}" } # 主流程 main() { detect_os install_deps install_rust install_nodejs setup_database build_funmc configure_services configure_firewall show_completion } # 运行 main "$@"