diff --git a/ru b/ru index 2292347..de6c7e5 100644 --- a/ru +++ b/ru @@ -8,66 +8,56 @@ RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' -NC='\033[0m' - -# 全局变量 -SCRIPT_DIR="/data/rustdesk" -FIXED_KEY_PUB="Doo0qYGYNSEzxoZRPrnV9AtkeX5FFLjcweiH4K1nIJM=" -FIXED_KEY_PRIV="" +NC='\033[0m' # 无颜色 # 日志函数 -log_info() { echo -e "${BLUE}[信息]${NC} $1"; } -log_success() { echo -e "${GREEN}[成功]${NC} $1"; } -log_warning() { echo -e "${YELLOW}[警告]${NC} $1"; } -log_error() { echo -e "${RED}[错误]${NC} $1"; } - -# 安全清理函数 -cleanup() { - echo "执行清理操作..." - rm -f /tmp/rustdesk_keys - unset admin_password +log_info() { + echo -e "${BLUE}[信息]${NC} $1" } -# 信号处理 -trap cleanup EXIT INT TERM +log_success() { + echo -e "${GREEN}[成功]${NC} $1" +} -# 检查命令是否存在 -check_command() { - if ! command -v "$1" &>/dev/null; then - echo "错误: 必需命令 '$1' 未找到" - return 1 - fi - return 0 +log_warning() { + echo -e "${YELLOW}[警告]${NC} $1" +} + +log_error() { + echo -e "${RED}[错误]${NC} $1" } # 检查端口是否被占用 check_port() { local port=$1 + local protocol=${2:-tcp} - if [[ ! "$port" =~ ^[0-9]+$ ]] || [[ "$port" -lt 1024 || "$port" -gt 65535 ]]; then - echo "错误: 端口号 $port 无效 (必须是1024-65535)" - return 2 + if [[ "$port" -lt 1024 || "$port" -gt 65535 ]]; then + log_error "端口号 $port 超出范围 (1024-65535)" + return 1 fi local port_in_use=false + # 检查端口占用 if command -v netstat &>/dev/null; then - if netstat -tuln 2>/dev/null | grep -q ":${port}[[:space:]]"; then - echo "警告: 端口 $port 被占用 (netstat)" + if netstat -tuln | grep -q ":${port}[[:space:]]"; then + log_warning "端口 $port 被占用 (netstat)" port_in_use=true fi fi if command -v ss &>/dev/null; then - if ss -tuln 2>/dev/null | grep -q ":${port}[[:space:]]"; then - echo "警告: 端口 $port 被占用 (ss)" + if ss -tuln | grep -q ":${port}[[:space:]]"; then + log_warning "端口 $port 被占用 (ss)" port_in_use=true fi fi + # 检查 Docker 容器 if command -v docker &>/dev/null; then - if docker ps --format "table {{.Ports}}" 2>/dev/null | grep -q ":${port}->"; then - echo "警告: 端口 $port 被 Docker 容器占用" + if docker ps --format "table {{.Ports}}" | grep -q ":${port}->"; then + log_warning "端口 $port 被 Docker 容器占用" port_in_use=true fi fi @@ -79,7 +69,7 @@ check_port() { return 0 } -# 检查 Docker 环境(修复版) +# 检查 Docker 是否安装 check_docker() { log_info "检查 Docker 环境..." @@ -93,24 +83,26 @@ check_docker() { exit 1 fi - # 检查 Docker Compose 并直接返回命令 + local compose_available=false if command -v docker-compose &>/dev/null; then + compose_available=true log_info "使用 docker-compose" - echo "docker-compose" elif docker compose version &>/dev/null; then + compose_available=true log_info "使用 docker compose" - echo "docker compose" - else + fi + + if [[ "$compose_available" == "false" ]]; then log_error "Docker Compose 未安装" exit 1 fi + + log_success "Docker 环境检查通过" } # 创建目录结构 create_directories() { - log_info "创建目录结构..." - - local dirs=("$SCRIPT_DIR/server" "$SCRIPT_DIR/api" "$SCRIPT_DIR/db") + local dirs=("/data/rustdesk/server" "/data/rustdesk/api" "/data/rustdesk/db") for dir in "${dirs[@]}"; do if [[ ! -d "$dir" ]]; then @@ -121,93 +113,104 @@ create_directories() { fi done - sudo chmod 755 "$SCRIPT_DIR" - sudo chmod 755 "$SCRIPT_DIR/server" - sudo chmod 755 "$SCRIPT_DIR/api" - sudo chmod 755 "$SCRIPT_DIR/db" + sudo chmod 755 /data/rustdesk + sudo chmod 755 /data/rustdesk/server + sudo chmod 755 /data/rustdesk/api + sudo chmod 755 /data/rustdesk/db if [[ "$(id -u)" -ne 0 ]]; then - sudo chown -R "$(id -u):$(id -g)" "$SCRIPT_DIR" + sudo chown -R "$(id -u):$(id -g)" /data/rustdesk fi } -# 固定密钥设置函数 -setup_fixed_key() { - local server_dir="$SCRIPT_DIR/server" +# 修复密钥对问题 +fix_keypair() { + local server_dir="/data/rustdesk/server" - log_info "设置固定客户端密钥..." + log_info "检查并修复密钥对问题..." + # 备份现有密钥(如果存在) if [[ -f "$server_dir/id_ed25519" || -f "$server_dir/id_ed25519.pub" ]]; then - local backup_dir="$SCRIPT_DIR/backup_$(date +%Y%m%d_%H%M%S)" + log_warning "发现现有密钥文件,进行备份..." + local backup_dir="/data/rustdesk/backup_$(date +%Y%m%d_%H%M%S)" mkdir -p "$backup_dir" cp -f "$server_dir/id_ed25519" "$backup_dir/" 2>/dev/null || true cp -f "$server_dir/id_ed25519.pub" "$backup_dir/" 2>/dev/null || true - log_info "旧密钥备份到: $backup_dir" + log_info "旧密钥已备份到: $backup_dir" fi + # 删除现有密钥文件 rm -f "$server_dir/id_ed25519" "$server_dir/id_ed25519.pub" - echo "$FIXED_KEY_PUB" > "$server_dir/id_ed25519.pub" - touch "$server_dir/id_ed25519" + # 生成新的密钥对 + log_info "生成新的 RustDesk 密钥对..." - chmod 644 "$server_dir/id_ed25519.pub" - chmod 600 "$server_dir/id_ed25519" + local max_retries=3 + local retry_count=0 - if [[ -f "$server_dir/id_ed25519.pub" ]]; then - local saved_key=$(cat "$server_dir/id_ed25519.pub") - if [[ "$saved_key" == "$FIXED_KEY_PUB" ]]; then - log_success "固定密钥设置成功" - return 0 - else - log_error "密钥写入验证失败" - return 1 + while [[ $retry_count -lt $max_retries ]]; do + if docker run --rm --entrypoint /usr/bin/rustdesk-utils lejianwen/rustdesk-server-s6:latest genkeypair > /tmp/rustdesk_keys 2>/dev/null; then + # 解析生成的密钥 + KEY_PUB=$(grep "Public Key:" /tmp/rustdesk_keys | awk '{print $3}') + KEY_PRIV=$(grep "Secret Key:" /tmp/rustdesk_keys | awk '{print $3}') + + # 验证密钥格式 + if [[ -n "$KEY_PUB" && -n "$KEY_PRIV" ]]; then + # 保存密钥到文件 + echo "$KEY_PUB" > "$server_dir/id_ed25519.pub" + echo "$KEY_PRIV" > "$server_dir/id_ed25519" + + # 设置文件权限 + chmod 600 "$server_dir/id_ed25519" + chmod 644 "$server_dir/id_ed25519.pub" + + # 验证密钥文件 + if [[ -f "$server_dir/id_ed25519" && -f "$server_dir/id_ed25519.pub" ]]; then + local pub_content=$(cat "$server_dir/id_ed25519.pub") + local priv_content=$(cat "$server_dir/id_ed25519") + + if [[ "$pub_content" == "$KEY_PUB" && "$priv_content" == "$KEY_PRIV" ]]; then + log_success "密钥对生成并验证成功" + log_info "公钥: $KEY_PUB" + log_info "私钥: ${KEY_PRIV:0:20}..." + rm -f /tmp/rustdesk_keys + return 0 + fi + fi + fi fi - else - log_error "密钥文件创建失败" - return 1 - fi + + retry_count=$((retry_count + 1)) + log_warning "密钥生成失败,重试第 $retry_count 次..." + sleep 2 + done + + log_error "密钥对生成失败,使用空密钥(容器将自行生成)" + KEY_PUB="" + KEY_PRIV="" + rm -f /tmp/rustdesk_keys + return 1 } -# 安全密码生成 +# 生成随机密码 generate_password() { local length=12 - tr -dc 'A-Za-z0-9@#$%^&*+' < /dev/urandom 2>/dev/null | head -c $length + tr -dc 'A-Za-z0-9!@#$%' < /dev/urandom | head -c $length } -# 获取本机IP -get_ip_address() { - local local_ip public_ip +# 检查端口占用情况 +check_ports_availability() { + local ports=("$api_port" "$hbbs_port" "$hbbr_port" "21115" "21118" "21119") - local_ip=$(hostname -I | awk '{print $1}' | head -1) - if [[ -z "$local_ip" ]]; then - local_ip="127.0.0.1" - fi + log_info "检查端口占用情况..." - public_ip=$(curl -s --connect-timeout 3 -m 5 ifconfig.me 2>/dev/null || echo "无法获取") - - echo "$local_ip" "$public_ip" -} - -# 验证用户输入 -validate_input() { - local type=$1 - local value=$2 - - case $type in - "project_name") - [[ "$value" =~ ^[a-zA-Z0-9_-]+$ ]] && return 0 - echo "错误: 项目名称只能包含字母、数字、连字符和下划线" - ;; - "port") - [[ "$value" =~ ^[0-9]+$ ]] && [[ "$value" -ge 1024 && "$value" -le 65535 ]] && return 0 - echo "错误: 端口号必须是 1024-65535 之间的数字" - ;; - "password") - [[ -n "$value" && ${#value} -ge 8 ]] && return 0 - echo "错误: 密码不能为空且至少 8 位" - ;; - esac - return 1 + for port in "${ports[@]}"; do + if ! check_port "$port"; then + log_warning "端口 $port 被占用,可能影响服务启动" + else + log_info "端口 $port 可用" + fi + done } # 获取用户输入 @@ -216,74 +219,117 @@ get_user_input() { local default_api_port="21114" local default_hbbs_port="21116" local default_hbbr_port="21117" - + + # 读取项目名称 while true; do read -p "请输入项目名称(默认: $default_project): " input_project project_name=$(echo "$input_project" | xargs) project_name=${project_name:-$default_project} - if validate_input "project_name" "$project_name"; then + if [[ "$project_name" =~ ^[a-zA-Z0-9_-]+$ ]]; then break + else + log_error "项目名称只能包含字母、数字、连字符和下划线" fi done - local ports=("api_port" "hbbs_port" "hbbr_port") - local defaults=("$default_api_port" "$default_hbbs_port" "$default_hbbr_port") - local descriptions=("API服务端口" "ID服务器端口" "中继服务器端口") - - for i in "${!ports[@]}"; do - while true; do - read -p "请输入${descriptions[i]}(默认: ${defaults[i]}): " input_port - local port_val=$(echo "$input_port" | xargs) - port_val=${port_val:-${defaults[i]}} - - if validate_input "port" "$port_val"; then - if check_port "$port_val"; then - declare -g "${ports[i]}=$port_val" + # 读取API端口 + while true; do + read -p "请输入API服务端口(默认: $default_api_port): " input_port + api_port=$(echo "$input_port" | xargs) + api_port=${api_port:-$default_api_port} + + if [[ "$api_port" =~ ^[0-9]+$ ]] && [[ "$api_port" -ge 1024 && "$api_port" -le 65535 ]]; then + if ! check_port "$api_port"; then + log_warning "端口 $api_port 已被占用" + read -p "是否继续使用此端口?(y/N): " use_occupied_port + if [[ "$use_occupied_port" =~ ^[Yy]$ ]]; then break - else - echo "警告: 端口 $port_val 已被占用" - read -p "是否强制使用此端口?(y/N): " use_occupied_port - if [[ "$use_occupied_port" =~ ^[Yy]$ ]]; then - declare -g "${ports[i]}=$port_val" - break - fi fi + else + break fi - done + else + log_error "端口号必须是 1024-65535 之间的数字" + fi done + # 读取ID服务器端口 + while true; do + read -p "请输入ID服务器端口(默认: $default_hbbs_port): " input_port + hbbs_port=$(echo "$input_port" | xargs) + hbbs_port=${hbbs_port:-$default_hbbs_port} + + if [[ "$hbbs_port" =~ ^[0-9]+$ ]] && [[ "$hbbs_port" -ge 1024 && "$hbbs_port" -le 65535 ]]; then + if ! check_port "$hbbs_port"; then + log_warning "端口 $hbbs_port 已被占用" + read -p "是否继续使用此端口?(y/N): " use_occupied_port + if [[ "$use_occupied_port" =~ ^[Yy]$ ]]; then + break + fi + else + break + fi + else + log_error "端口号必须是 1024-65535 之间的数字" + fi + done + + # 读取中继服务器端口 + while true; do + read -p "请输入中继服务器端口(默认: $default_hbbr_port): " input_port + hbbr_port=$(echo "$input_port" | xargs) + hbbr_port=${hbbr_port:-$default_hbbr_port} + + if [[ "$hbbr_port" =~ ^[0-9]+$ ]] && [[ "$hbbr_port" -ge 1024 && "$hbbr_port" -le 65535 ]]; then + if ! check_port "$hbbr_port"; then + log_warning "端口 $hbbr_port 已被占用" + read -p "是否继续使用此端口?(y/N): " use_occupied_port + if [[ "$use_occupied_port" =~ ^[Yy]$ ]]; then + break + fi + else + break + fi + else + log_error "端口号必须是 1024-65535 之间的数字" + fi + done + + # 询问是否使用随机密码 read -p "是否生成随机管理员密码?(y/N): " use_random_pwd if [[ "$use_random_pwd" =~ ^[Yy]$ ]]; then admin_password=$(generate_password) log_info "已生成随机密码" else while true; do - read -sp "请输入管理员密码(最少 8 位): " password1 + read -sp "请输入管理员密码(最少 8 位): " admin_password echo - read -sp "请确认管理员密码: " password2 - echo - - if validate_input "password" "$password1" && [[ "$password1" == "$password2" ]]; then - admin_password="$password1" - break - elif [[ "$password1" != "$password2" ]]; then - echo "错误: 两次输入的密码不一致" + if [[ -n "$admin_password" && ${#admin_password} -ge 8 ]]; then + read -sp "请确认管理员密码: " admin_password_confirm + echo + if [[ "$admin_password" == "$admin_password_confirm" ]]; then + break + else + log_error "两次输入的密码不一致" + fi + else + log_error "密码不能为空且至少 8 位" fi done fi - local ip_info=($(get_ip_address)) - local local_ip="${ip_info[0]}" - local public_ip="${ip_info[1]}" - + # 获取本机 IP + local_ip=$(hostname -I | awk '{print $1}') + public_ip=$(curl -s --connect-timeout 5 ifconfig.me || echo "无法获取公网IP") + echo log_info "配置摘要:" log_info "项目名称: $project_name" log_info "API服务端口: $api_port" log_info "ID服务器端口: $hbbs_port" log_info "中继服务器端口: $hbbr_port" - log_info "管理员密码: ${admin_password:0:2}******" + log_info "管理员密码: ${admin_password:0:4}******" log_info "本地 IP: $local_ip" log_info "公网 IP: $public_ip" echo @@ -295,25 +341,35 @@ get_user_input() { fi } -# 生成 Docker Compose 配置 +# 生成 Docker Compose 配置文件 generate_compose_file() { - local project_name="$1" api_port="$2" hbbs_port="$3" hbbr_port="$4" + local project_name="$1" + local api_port="$2" + local hbbs_port="$3" + local hbbr_port="$4" local admin_password="$5" + local key_pub="$6" + local key_priv="$7" - local file_path="$SCRIPT_DIR/docker-compose.yml" - local ip_info=($(get_ip_address)) - local local_ip="${ip_info[0]}" + # 生成 JWT 密钥 + local jwt_key=$(openssl rand -base64 32 2>/dev/null || echo "default_jwt_key_$(date +%s)") - local jwt_key=$(openssl rand -base64 32 2>/dev/null || - echo "fallback_jwt_key_$(date +%s)") + local file_path="/data/rustdesk/docker-compose.yml" + + # 如果密钥为空,则不设置密钥环境变量,让容器自己生成 + local key_envs="" + if [[ -n "$key_pub" && -n "$key_priv" ]]; then + key_envs=" - KEY_PUB=$key_pub + - KEY_PRIV=$key_priv" + log_info "使用自定义密钥对" + else + log_info "未提供密钥对,容器将自动生成" + fi cat > "$file_path" << EOF # RustDesk Server 配置 # 生成时间: $(date) # 项目名称: $project_name -# 使用固定客户端密钥 - -version: '3.8' networks: rustdesk-net: @@ -326,10 +382,10 @@ services: image: lejianwen/rustdesk-server-s6:latest ports: - "${api_port}:21114" # API 服务器 - - "21115:21115" # Web客户端 + - "21115:21115" # 其他服务 - "${hbbs_port}:21116" # ID 服务器 (hbbs) - "${hbbr_port}:21117" # 中继服务器 (hbbr) - - "21118:21118" # 文件传输 + - "21118:21118" # 其他服务 - "21119:21119" # 其他服务 - "${hbbs_port}:21116/udp" # UDP 端口 environment: @@ -337,17 +393,17 @@ services: - ENCRYPTED_ONLY=1 - MUST_LOGIN=n - TZ=Asia/Shanghai - # 语言设置 + # 设置中文语言 - LANG=zh_CN.UTF-8 - LANGUAGE=zh_CN:zh - LC_ALL=zh_CN.UTF-8 - # 端口配置 + # 自定义端口 - 关键配置! - PORT=${hbbs_port} - BIND_PORT=${hbbr_port} - # 网络配置 + # 强制所有连接通过中继服务器 - ALWAYS_USE_RELAY=Y - # 固定密钥配置 - - KEY_PUB=${FIXED_KEY_PUB} + # 密钥配置 +$key_envs # API 配置 - RUSTDESK_API_RUSTDESK_ID_SERVER=${local_ip}:${hbbs_port} - RUSTDESK_API_RUSTDESK_RELAY_SERVER=${local_ip}:${hbbr_port} @@ -357,9 +413,9 @@ services: # 数据库配置 - DB_URL=/db/db_v2.sqlite3 volumes: - - $SCRIPT_DIR/server:/data - - $SCRIPT_DIR/api:/app/data - - $SCRIPT_DIR/db:/db + - /data/rustdesk/server:/data + - /data/rustdesk/api:/app/data + - /data/rustdesk/db:/db networks: - rustdesk-net restart: unless-stopped @@ -374,151 +430,341 @@ EOF log_success "Docker Compose 配置文件已生成: $file_path" } -# 部署服务(修复版) -deploy_service() { - local project_name="$1" admin_password="$2" - local compose_cmd="$3" - local file_path="$SCRIPT_DIR/docker-compose.yml" +# 检查容器运行状态 +check_container_health() { + local container_name="$1" + local max_checks=20 + local check_interval=5 - log_info "开始部署 RustDesk 服务..." + log_info "检查容器 $container_name 运行状态..." - cd "$SCRIPT_DIR" || { - log_error "无法进入目录: $SCRIPT_DIR" - return 1 - } - - # 停止现有服务 - if docker ps -a --filter "name=${project_name}-rustdesk" | grep -q "${project_name}-rustdesk"; then - log_info "停止现有服务..." - eval "$compose_cmd -f \"$file_path\" down" || true - sleep 5 - fi - - # 启动服务 - log_info "启动服务..." - if ! eval "$compose_cmd -f \"$file_path\" up -d"; then - log_error "服务启动失败" - log_info "尝试查看 Docker 日志..." - docker logs "${project_name}-rustdesk" 2>/dev/null | tail -20 || true - return 1 - fi - - # 等待服务启动 - sleep 15 - - # 设置管理员密码 - log_info "设置管理员密码..." - for ((i=1; i<=5; i++)); do - if docker exec "${project_name}-rustdesk" sh -c "./apimain reset-admin-pwd \"$admin_password\"" 2>/dev/null; then - log_success "管理员密码设置成功" + for ((i=1; i<=max_checks; i++)); do + # 检查容器是否存在 + if ! docker ps -a | grep -q "$container_name"; then + log_error "容器 $container_name 不存在" + return 1 + fi + + # 检查容器状态 + local status=$(docker inspect --format='{{.State.Status}}' "$container_name" 2>/dev/null) + + case "$status" in + "running") + # 检查关键进程 + if docker exec "$container_name" pgrep hbbs >/dev/null 2>&1 && \ + docker exec "$container_name" pgrep hbbr >/dev/null 2>&1; then + log_success "容器运行正常 (关键进程运行中)" + + # 额外检查服务是否真正就绪 + if docker exec "$container_name" curl -f http://localhost:21114 >/dev/null 2>&1; then + log_success "API 服务就绪" + return 0 + else + log_info "等待API服务就绪... ($i/$max_checks)" + fi + elif [[ $i -gt 5 ]]; then + log_info "等待关键进程启动... ($i/$max_checks)" + fi + ;; + "exited") + local exit_code=$(docker inspect --format='{{.State.ExitCode}}' "$container_name") + log_error "容器已退出,退出码: $exit_code" + log_info "查看容器日志:" + docker logs "$container_name" | tail -30 + return 1 + ;; + "restarting") + log_info "容器正在重启... ($i/$max_checks)" + ;; + *) + log_error "容器状态异常: $status" + return 1 + ;; + esac + + if [[ $i -eq $max_checks ]]; then + log_warning "容器状态检查超时,但继续部署流程" return 0 fi - log_warning "密码设置失败,重试第 $i 次..." - sleep 10 + + sleep $check_interval done - log_warning "密码设置失败,请手动执行:" - log_info "docker exec ${project_name}-rustdesk ./apimain reset-admin-pwd \"YOUR_PASSWORD\"" return 0 } -# 显示部署信息 +# 部署服务 +deploy_service() { + local project_name="$1" + local admin_password="$2" + local file_path="/data/rustdesk/docker-compose.yml" + + log_info "开始部署 RustDesk 服务..." + + # 使用 docker-compose 或 docker compose + local compose_cmd + if command -v docker-compose &>/dev/null; then + compose_cmd="docker-compose" + else + compose_cmd="docker compose" + fi + + # 停止并删除现有容器(如果存在) + if docker ps -a --filter "name=${project_name}-rustdesk" | grep -q "${project_name}-rustdesk"; then + log_info "停止并删除现有容器..." + cd /data/rustdesk + sudo $compose_cmd -f "$file_path" down || true + sleep 5 + fi + + # 部署服务 + cd /data/rustdesk + log_info "启动服务..." + if ! sudo $compose_cmd -f "$file_path" up -d; then + log_error "服务启动失败" + return 1 + fi + + sleep 10 + + # 检查容器运行状态 + if ! check_container_health "${project_name}-rustdesk"; then + log_warning "容器启动过程中遇到问题,尝试继续配置..." + fi + + # 等待服务完全启动 + log_info "等待服务初始化完成..." + sleep 15 + + # 重置管理员密码 + log_info "设置管理员密码..." + local password_retries=5 + local password_success=false + + for ((i=1; i<=password_retries; i++)); do + if docker exec "${project_name}-rustdesk" sh -c "./apimain reset-admin-pwd \"$admin_password\"" 2>/dev/null; then + log_success "管理员密码设置成功" + password_success=true + break + else + log_warning "密码设置失败,重试第 $i 次... (等待服务完全启动)" + sleep 10 + fi + done + + if [[ "$password_success" == "false" ]]; then + log_warning "密码设置失败,可能需要手动设置" + log_info "请手动执行: docker exec ${project_name}-rustdesk ./apimain reset-admin-pwd \"$admin_password\"" + fi + + return 0 +} + +# 验证服务连通性 +test_service_connectivity() { + local api_port="$1" + local hbbs_port="$2" + local hbbr_port="$3" + + log_info "测试服务连通性..." + + # 测试API服务 + if curl -s --connect-timeout 10 "http://localhost:${api_port}" > /dev/null; then + log_success "API 服务连通正常" + else + log_warning "API 服务连通异常" + fi + + # 测试端口连通性 + if command -v nc &>/dev/null; then + if nc -z -w 3 localhost "$hbbs_port"; then + log_success "ID服务器端口 $hbbs_port 连通正常" + else + log_warning "ID服务器端口 $hbbs_port 连通异常" + fi + + if nc -z -w 3 localhost "$hbbr_port"; then + log_success "中继服务器端口 $hbbr_port 连通正常" + else + log_warning "中继服务器端口 $hbbr_port 连通异常" + fi + fi +} + +# 验证部署 +verify_deployment() { + local project_name="$1" + local api_port="$2" + local hbbs_port="$3" + local hbbr_port="$4" + + log_info "验证部署结果..." + + # 检查容器状态 + if docker ps --filter "name=${project_name}-rustdesk" --format "table {{.Names}}\t{{.Status}}" | grep -q "Up"; then + log_success "容器运行正常" + else + log_error "容器未运行" + return 1 + fi + + sleep 10 + + # 检查关键服务进程 + if docker exec "${project_name}-rustdesk" pgrep hbbs > /dev/null 2>&1; then + log_success "hbbs (ID服务器) 运行正常" + else + log_warning "hbbs (ID服务器) 异常" + fi + + if docker exec "${project_name}-rustdesk" pgrep hbbr > /dev/null 2>&1; then + log_success "hbbr (中继服务器) 运行正常" + else + log_warning "hbbr (中继服务器) 异常" + fi + + # 测试服务连通性 + test_service_connectivity "$api_port" "$hbbs_port" "$hbbr_port" + + # 检查端口监听情况 + log_info "检查端口监听状态..." + if netstat -tuln | grep -q ":${hbbs_port}[[:space:]]"; then + log_success "ID服务器端口 $hbbs_port 监听正常" + else + log_warning "ID服务器端口 $hbbs_port 未监听" + fi + + if netstat -tuln | grep -q ":${hbbr_port}[[:space:]]"; then + log_success "中继服务器端口 $hbbr_port 监听正常" + else + log_warning "中继服务器端口 $hbbr_port 未监听" + fi + + return 0 +} + +# 显示部署结果 show_deployment_info() { - local project_name="$1" api_port="$2" hbbs_port="$3" hbbr_port="$4" + local project_name="$1" + local api_port="$2" + local hbbs_port="$3" + local hbbr_port="$4" local admin_password="$5" + local key_pub="$6" - local ip_info=($(get_ip_address)) - local local_ip="${ip_info[0]}" - local public_ip="${ip_info[1]}" + local local_ip=$(hostname -I | awk '{print $1}') + local public_ip=$(curl -s --connect-timeout 5 ifconfig.me || echo "无法获取公网IP") echo - echo "========================================" - echo "🎉 RustDesk 部署完成!" - echo "========================================" + log_success "🎉 RustDesk 部署完成!" echo - echo "=== 访问信息 ===" - echo "Web管理界面: http://${local_ip}:${api_port}" - if [[ "$public_ip" != "无法获取" ]]; then - echo "公网访问: http://${public_ip}:${api_port}" + echo "=================== 访问信息 ===================" + echo -e "Web管理界面: ${GREEN}http://${local_ip}:${api_port}${NC}" + if [[ "$public_ip" != "无法获取公网IP" ]]; then + echo -e "公网访问: ${GREEN}http://${public_ip}:${api_port}${NC}" fi echo - echo "=== 账号信息 ===" - echo "管理员账号: admin" - echo "管理员密码: ${admin_password}" + echo "=================== 账号信息 ===================" + echo -e "管理员账号: ${GREEN}admin${NC}" + echo -e "管理员密码: ${GREEN}${admin_password}${NC}" echo - echo "=== 密钥信息 ===" - echo "固定客户端密钥: ${FIXED_KEY_PUB}" - echo "密钥状态: 已预配置" + + # 重新读取实际的公钥 + local actual_pub_key="" + if [[ -f "/data/rustdesk/server/id_ed25519.pub" ]]; then + actual_pub_key=$(cat "/data/rustdesk/server/id_ed25519.pub") + fi + + if [[ -n "$actual_pub_key" ]]; then + echo "=================== 密钥信息 ===================" + echo -e "公钥 (KEY): ${GREEN}${actual_pub_key}${NC}" + echo + fi + + echo "=================== 服务器配置 ===================" + echo -e "ID 服务器: ${GREEN}${local_ip}:${hbbs_port}${NC}" + echo -e "中继服务器: ${GREEN}${local_ip}:${hbbr_port}${NC}" + echo -e "API 服务器: ${GREEN}http://${local_ip}:${api_port}${NC}" echo - echo "=== 服务器配置 ===" - echo "ID 服务器: ${local_ip}:${hbbs_port}" - echo "中继服务器: ${local_ip}:${hbbr_port}" - echo "API 服务器: http://${local_ip}:${api_port}" - echo - echo "=== 客户端配置步骤 ===" + echo "=================== 客户端配置步骤 ===================" echo "1. 打开 RustDesk 客户端" echo "2. 点击 ID/中继服务器 设置" echo "3. 填写以下信息:" echo " - ID 服务器: ${local_ip}:${hbbs_port}" echo " - 中继服务器: ${local_ip}:${hbbr_port}" - echo " - Key: ${FIXED_KEY_PUB}" + if [[ -n "$actual_pub_key" ]]; then + echo " - Key: ${actual_pub_key}" + fi echo "4. 点击 '应用' 保存" - echo "5. 重启 RustDesk 客户端生效" + echo "5. 重启 RustDesk 客户端" + echo "===================================================" echo - echo "=== 管理命令 ===" - echo "查看服务状态: docker ps -f name=${project_name}" - echo "查看服务日志: docker logs ${project_name}-rustdesk" - echo "停止服务: cd $SCRIPT_DIR && $compose_cmd down" - echo "重启服务: cd $SCRIPT_DIR && $compose_cmd restart" + echo "=================== 管理命令 ===================" + echo -e "查看服务状态: ${YELLOW}docker ps -f name=${project_name}${NC}" + echo -e "查看服务日志: ${YELLOW}docker logs ${project_name}-rustdesk${NC}" + echo -e "停止服务: ${YELLOW}cd /data/rustdesk && docker compose down${NC}" + echo -e "重启服务: ${YELLOW}cd /data/rustdesk && docker compose restart${NC}" + echo "================================================" echo - echo "=== 重要提示 ===" - echo "请确保防火墙已开放以下端口:" - echo " - API服务端口: ${api_port}" - echo " - ID服务器端口: ${hbbs_port}" - echo " - 中继服务器端口: ${hbbr_port}" - echo " - 其他端口: 21115, 21118, 21119" - echo - echo "所有客户端必须使用相同的密钥: ${FIXED_KEY_PUB}" - echo "此密钥已预配置,客户端连接时无需额外设置" + log_warning "请确保防火墙已开放以下端口:" + echo -e " - API服务端口: ${YELLOW}${api_port}${NC}" + echo -e " - ID服务器端口: ${YELLOW}${hbbs_port}${NC}" + echo -e " - 中继服务器端口: ${YELLOW}${hbbr_port}${NC}" + echo -e " - 其他端口: ${YELLOW}21115, 21118, 21119${NC}" + + # 显示诊断信息 echo + echo "=================== 诊断信息 ===================" + log_info "如果客户端显示'未就绪',请检查:" + echo "1. 防火墙端口是否开放" + echo "2. 客户端配置是否正确" + echo "3. 服务日志: docker logs ${project_name}-rustdesk" + echo "================================================" } # 主函数 main() { echo log_info "开始 RustDesk 服务器部署" - log_info "使用固定客户端密钥: ${FIXED_KEY_PUB:0:20}..." echo "========================================" - # 检查依赖 - compose_cmd=$(check_docker) - log_info "使用命令: $compose_cmd" + # 检查 Docker + check_docker - # 初始化环境 + # 创建目录 create_directories - # 获取配置 + # 获取用户输入 get_user_input - # 设置固定密钥 - setup_fixed_key + # 检查端口 + check_ports_availability + + # 修复密钥对问题(强制重新生成) + fix_keypair # 生成配置文件 - generate_compose_file "$project_name" "$api_port" "$hbbs_port" "$hbbr_port" "$admin_password" + generate_compose_file "$project_name" "$api_port" "$hbbs_port" "$hbbr_port" "$admin_password" "$KEY_PUB" "$KEY_PRIV" # 部署服务 - if deploy_service "$project_name" "$admin_password" "$compose_cmd"; then - # 显示部署信息 - show_deployment_info "$project_name" "$api_port" "$hbbs_port" "$hbbr_port" "$admin_password" + if deploy_service "$project_name" "$admin_password"; then + # 验证部署 + verify_deployment "$project_name" "$api_port" "$hbbs_port" "$hbbr_port" + # 显示部署结果 + show_deployment_info "$project_name" "$api_port" "$hbbs_port" "$hbbr_port" "$admin_password" "$KEY_PUB" log_success "部署脚本执行完成" - # 显示最终状态 + # 显示最终检查 echo log_info "最终状态检查:" docker ps -f "name=${project_name}-rustdesk" else log_error "部署失败,请检查上述错误信息" - log_info "尝试手动启动: cd $SCRIPT_DIR && $compose_cmd up -d" + log_info "故障排除建议:" + log_info "1. 检查 Docker 日志: docker logs ${project_name}-rustdesk" + log_info "2. 检查端口占用: netstat -tulpn | grep 2111" + log_info "3. 检查防火墙设置" + log_info "4. 尝试手动重启: cd /data/rustdesk && docker compose down && docker compose up -d" exit 1 fi }