#!/usr/bin/env bash # ========================================================= # VNC 远程桌面 (TigerVNC + 多桌面) - 动态传参版 # 适用系统: Ubuntu / Debian / CentOS / RHEL / Rocky / Alma # ========================================================= set -euo pipefail SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)" LOG_PREFIX="[VNC 远程桌面]" log() { echo -e "\e[32m${LOG_PREFIX} $*\e[0m" ; } warn() { echo -e "\e[33m${LOG_PREFIX} WARN: $*\e[0m" >&2 ; } die() { echo -e "\e[31m${LOG_PREFIX} ERROR: $*\e[0m" >&2 ; exit 1 ; } # 1. 检查 root 权限 [ "$(id -u)" -eq 0 ] || die "此脚本必须以 root 权限运行,请使用 sudo。" # 2. 解析命令行参数 (-u, -p, -P) VNC_USER="" VNC_PASS="" VNC_PORT="" usage() { echo "用法: $0 -u <用户名> -p <密码> -P <端口号或桌面编号>" echo "示例: $0 -u user1 -p 123456 -P 5901 (对应桌面号 :1)" echo "示例: $0 -u user2 -p 654321 -P 2 (对应端口号 5902)" exit 1 } while getopts "u:p:P:h" opt; do case $opt in u) VNC_USER="$OPTARG" ;; p) VNC_PASS="$OPTARG" ;; P) VNC_PORT="$OPTARG" ;; h) usage ;; *) usage ;; esac done # 校验参数是否为空 if [[ -z "$VNC_USER" || -z "$VNC_PASS" || -z "$VNC_PORT" ]]; then die "参数缺失!\n请使用: $0 -u <用户名> -p <密码> -P <端口号/桌面号>\n使用 $0 -h 查看帮助。" fi # 智能换算端口与显示编号 (>= 5900 视为端口,反之视为桌面号) if [[ "$VNC_PORT" -ge 5900 ]]; then VNC_DISP=$((VNC_PORT - 5900)) CURRENT_PORT=$VNC_PORT else VNC_DISP=$VNC_PORT CURRENT_PORT=$((5900 + VNC_DISP)) fi log "目标用户: $VNC_USER" log "VNC密码: (已隐藏)" log "桌面编号: :$VNC_DISP (监听端口: $CURRENT_PORT)" echo "----------------------------------------" # 3. 检测 Linux 发行版 . /etc/os-release 2>/dev/null || true DISTRO_ID="${ID:-unknown}" DISTRO_LIKE="${ID_LIKE:-}" case "$DISTRO_ID" in ubuntu|debian) PKG="apt-get"; PKG_INSTALL="DEBIAN_FRONTEND=noninteractive apt-get install -y" ;; centos|rhel|rocky|almalinux|ol) PKG="yum"; PKG_INSTALL="yum install -y" ;; fedora) PKG="dnf"; PKG_INSTALL="dnf install -y" ;; *) if echo "$DISTRO_LIKE" | grep -qiE "rhel|centos|fedora"; then PKG="yum"; PKG_INSTALL="yum install -y" elif echo "$DISTRO_LIKE" | grep -qi "debian"; then PKG="apt-get"; PKG_INSTALL="DEBIAN_FRONTEND=noninteractive apt-get install -y" else die "不支持的系统发行版: $DISTRO_ID" fi ;; esac log "更新软件包缓存并安装 VNC 桌面环境依赖..." if [[ "$PKG" == "apt-get" ]]; then apt-get update -qq DEBIAN_FRONTEND=noninteractive apt-get install -yqq \ ubuntu-desktop-minimal \ dbus-x11 tigervnc-standalone-server tigervnc-common tigervnc-xorg-extension \ xvfb x11vnc x11-utils 2>/dev/null || \ DEBIAN_FRONTEND=noninteractive apt-get install -yqq \ gnome-session gnome-shell gnome-terminal nautilus metacity \ dbus-x11 tigervnc-standalone-server tigervnc-common \ xvfb x11vnc x11-utils \ xserver-xorg-video-dummy \ gnome-shell-extension-desktop-icons-ng gnome-terminal nautilus-extension-gnome-terminal gnome-tweaks fi # 4. 用户及目录配置 log "配置用户 '$VNC_USER' 及工作目录..." id "$VNC_USER" >/dev/null 2>&1 || useradd -m -s /bin/bash "$VNC_USER" USER_HOME="$(getent passwd "$VNC_USER" | cut -d: -f6)" CURRENT_SHELL="$(getent passwd "$VNC_USER" | cut -d: -f7)" if [ "$CURRENT_SHELL" != "/bin/bash" ]; then usermod -s /bin/bash "$VNC_USER" fi install -d -o "$VNC_USER" -g "$VNC_USER" -m 0750 "$USER_HOME" install -d -o "$VNC_USER" -g "$VNC_USER" -m 0700 "$USER_HOME/.vnc" # 设置 VNC 密码 log "生成 VNC 密码..." printf "%s\n" "$VNC_PASS" | vncpasswd -f > "$USER_HOME/.vnc/passwd" chmod 600 "$USER_HOME/.vnc/passwd" chown "$VNC_USER":"$VNC_USER" "$USER_HOME/.vnc/passwd" # 5. 写入 xstartup (桌面启动脚本) log "写入 VNC 桌面环境启动脚本 (xstartup)..." cat > "$USER_HOME/.vnc/xstartup" <<'XSTARTUP_EOF' #!/bin/sh unset SESSION_MANAGER unset DBUS_SESSION_BUS_ADDRESS export XDG_CURRENT_DESKTOP=ubuntu:GNOME export XDG_SESSION_TYPE=x11 export GNOME_SHELL_SESSION_MODE=ubuntu exec dbus-launch --exit-with-session gnome-session XSTARTUP_EOF chmod +x "$USER_HOME/.vnc/xstartup" chown "$VNC_USER":"$VNC_USER" "$USER_HOME/.vnc/xstartup" # 6. 配置 Systemd 服务 SERVICE_FILE="/etc/systemd/system/vncserver-${VNC_USER}.service" log "写入专属 systemd 守护进程服务: $SERVICE_FILE" cat > "$SERVICE_FILE" </dev/null | grep -q "/tmp/.X11-unix/X${VNC_DISP} "; then warn "⚠️ 桌面编号 :$VNC_DISP (端口 $CURRENT_PORT) 似乎正被其他进程占用!" warn "我们将尝试强制接管该端口..." fi log "清理底层的历史残留套接字..." rm -f /tmp/.X${VNC_DISP}-lock /tmp/.X11-unix/X${VNC_DISP} 2>/dev/null || true pkill -f "Xvnc.*:${VNC_DISP} " 2>/dev/null || true pkill -f "Xtigervnc.*:${VNC_DISP}" 2>/dev/null || true log "启动 VNC 服务..." systemctl daemon-reload systemctl enable "vncserver-${VNC_USER}.service" systemctl restart "vncserver-${VNC_USER}.service" sleep 3 # 8. 检查结果 if systemctl is-active --quiet "vncserver-${VNC_USER}.service"; then log "🎯 部署完毕!" echo "=====================================================" echo " 用户: $VNC_USER" echo " 服务: systemctl status vncserver-${VNC_USER}.service" echo " 连接: 使用 VNC Viewer 连接 <服务器IP>:$CURRENT_PORT" echo "=====================================================" else die "服务启动失败,请运行 'journalctl -xeu vncserver-${VNC_USER}.service' 查看日志。" fi