Update ru

This commit is contained in:
2025-10-28 21:40:28 +08:00
committed by GitHub
parent ff48d84fb0
commit d0774b91ac

712
ru
View File

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