From 50bc6f5432a008e35d633a180fda29a3ccf6a7ca Mon Sep 17 00:00:00 2001 From: root Date: Sat, 6 Sep 2025 00:50:50 +0900 Subject: [PATCH] =?UTF-8?q?docs:=20README=20=EC=97=85=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=8A=B8=20=EB=B0=8F=20Perfect=20=EB=B2=84=EC=A0=84=20?= =?UTF-8?q?=EC=8A=A4=ED=81=AC=EB=A6=BD=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - proxmox-auto-rdp-perfect.sh 추가 (개선된 버전) - README.md 대폭 업데이트 - 웹 제어 패널 설치 방법 추가 - Perfect 버전 한 줄 설치 명령 추가 - 서비스 관리 명령어 추가 - 업데이트 이력 추가 (v1.1) - 마우스 커서 문제 해결 내용 문서화 - Tailscale 통합 기능 설명 추가 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- README.md | 106 +++++++- proxmox-auto-rdp-perfect.sh | 507 ++++++++++++++++++++++++++++++++++++ 2 files changed, 606 insertions(+), 7 deletions(-) create mode 100644 proxmox-auto-rdp-perfect.sh diff --git a/README.md b/README.md index 6089583..590bd59 100644 --- a/README.md +++ b/README.md @@ -4,26 +4,53 @@ Proxmox VE 호스트가 부팅 시 자동으로 RDP 연결하도록 설정하는 ## 🚀 한 줄 설치 +### 기본 설치 스크립트 ```bash bash -c "$(curl -fsSL https://git.0bin.in/thug0bin/proxmox-rdp-autosetup/raw/branch/main/proxmox-auto-rdp-setup.sh)" ``` -## 📋 기능 +### 개선된 설치 스크립트 (Perfect 버전) +```bash +bash -c "$(curl -fsSL https://git.0bin.in/thug0bin/proxmox-rdp-autosetup/raw/branch/main/proxmox-auto-rdp-perfect.sh)" +``` +### 웹 제어 패널 설치 +```bash +# 리포지토리 클론 후 +git clone https://git.0bin.in/thug0bin/proxmox-rdp-autosetup.git +cd proxmox-rdp-autosetup + +# 웹 제어 패널 설치 +bash install_web_control.sh +``` + +## 📋 주요 기능 + +### 자동 RDP 설정 - **완전 자동화**: 사용자 입력 후 모든 설정 자동 수행 - **강화된 검증**: 입력값 검증 및 네트워크 연결 테스트 - **에러 처리**: 단계별 실패 처리 및 재시도 로직 - **백업**: 기존 설정 자동 백업 - **사용자 친화적**: 컬러 출력 및 진행 상황 표시 +- **마우스 커서 문제 해결**: 최신 버전에서 마우스 커서 사라짐 문제 수정 + +### 웹 제어 패널 (신규) +- **Flask 기반 웹 인터페이스**: RDP 자동 로그인을 웹에서 제어 +- **토글 스위치**: 간단한 ON/OFF 제어 +- **Tailscale 통합**: Tailscale IP로 원격 접속 가능 +- **실시간 상태 모니터링**: 서비스 상태 실시간 확인 +- **로그 뷰어**: 시스템 로그 확인 기능 ## 🎯 지원 환경 - **OS**: Proxmox VE 8.x 이상 (Debian 기반) - **권한**: root 권한 필요 - **네트워크**: 인터넷 연결 필요 +- **Python**: 3.x (웹 제어 패널용) ## 📖 동작 원리 +### RDP 자동 연결 1. **부팅 완료** → systemd가 tty1에서 rdpuser 자동 로그인 2. **로그인** → .bash_profile이 tty1에서 startx 실행 3. **X 시작** → .xinitrc가 실행됨 @@ -31,28 +58,52 @@ bash -c "$(curl -fsSL https://git.0bin.in/thug0bin/proxmox-rdp-autosetup/raw/bra 5. **FreeRDP3 실행** → 풀스크린 RDP 연결 6. **RDP 종료시** → X 세션도 함께 종료 +### 웹 제어 패널 +1. **Flask 서버** → Gunicorn으로 실행 +2. **systemd 서비스** → 부팅 시 자동 시작 +3. **REST API** → 상태 조회 및 제어 +4. **웹 UI** → 토글 스위치로 간편 제어 + ## 🔧 설치 과정 +### RDP 자동 설정 스크립트 실행 시 다음 정보를 입력하세요: - - **RDP 서버 주소** (예: example.com:3389) - **RDP 사용자명** - **RDP 패스워드** - **로컬 사용자명** (기본값: rdpuser) +### 웹 제어 패널 +```bash +# 설치 +bash install_web_control.sh + +# 접속 +http://[서버IP]:5000 +http://[Tailscale IP]:5000 + +# 제거 +bash uninstall_web_control.sh +``` + ## 📝 설정 파일 -스크립트가 자동 생성하는 주요 설정 파일들: - +### RDP 관련 파일 - `/etc/systemd/system/getty@tty1.service.d/override.conf` - 자동 로그인 - `/home/[사용자]/.bash_profile` - X 자동 시작 - `/home/[사용자]/.xinitrc` - RDP 연결 실행 - `/home/[사용자]/.config/openbox/rc.xml` - 풀스크린 최적화 +### 웹 제어 패널 파일 +- `/root/proxmox-rdp-autosetup/rdp_control_web.py` - Flask 애플리케이션 +- `/root/proxmox-rdp-autosetup/templates/index.html` - 웹 UI +- `/etc/systemd/system/rdp-control-web.service` - systemd 서비스 + ## 🛡️ 보안 고려사항 - RDP 패스워드가 설정 파일에 평문으로 저장됩니다 - 운영 환경에서는 보안 강화 조치 필요 +- 웹 제어 패널은 기본적으로 인증 없이 접근 가능 (필요시 인증 추가) - 시스템 접근을 위해 Ctrl+Alt+F2로 다른 터미널 사용 가능 ## 🔄 문제 해결 @@ -68,12 +119,49 @@ bash -c "$(curl -fsSL https://git.0bin.in/thug0bin/proxmox-rdp-autosetup/raw/bra - X 서버 로그 확인: `cat /home/rdpuser/.local/share/xorg/Xorg.0.log` - systemd 로그 확인: `journalctl -u getty@tty1.service -f` -3. **설정 초기화** +3. **마우스 커서 사라짐** + - 최신 버전 스크립트로 재설치 + - openbox 설정에 커서 테마 확인 + +4. **웹 제어 패널 접속 불가** + - 서비스 상태 확인: `systemctl status rdp-control-web` + - 방화벽 설정 확인 (포트 5000) + - 로그 확인: `journalctl -u rdp-control-web -f` + +5. **설정 초기화** - 백업에서 복원: `/root/proxmox-rdp-backup-[날짜시간]/` +## 🔍 서비스 관리 명령어 + +### RDP 자동 로그인 +```bash +# 상태 확인 +systemctl status xrdp-autologin.service + +# 서비스 재시작 +systemctl restart xrdp +systemctl restart xrdp-sesman + +# 로그 확인 +journalctl -u xrdp -f +``` + +### 웹 제어 패널 +```bash +# 상태 확인 +systemctl status rdp-control-web + +# 재시작 +systemctl restart rdp-control-web + +# 로그 확인 +journalctl -u rdp-control-web -f +``` + ## 📚 상세 문서 -더 자세한 설정 과정과 문제 해결 방법은 [proxmox_auto_rdp_setup_korean.md](./proxmox_auto_rdp_setup_korean.md)를 참고하세요. +- [상세 설정 가이드](./proxmox_auto_rdp_setup_korean.md) - RDP 자동 설정 상세 문서 +- [PBS 자동 등록 기획서](./pbs_auto_registration.md) - Proxmox Backup Server 자동 등록 (개발 예정) ## 🤝 기여 @@ -87,7 +175,11 @@ MIT License **개발**: 시골약사 & Claude Code Assistant **생성일**: 2025-08-24 -**최종 업데이트**: v1.0 +**최종 업데이트**: v1.1 (2025-09-06) + +### 📌 업데이트 이력 +- v1.1 (2025-09-06): 웹 제어 패널 추가, 마우스 커서 문제 해결 +- v1.0 (2025-08-24): 최초 릴리즈 🤖 Generated with [Claude Code](https://claude.ai/code) diff --git a/proxmox-auto-rdp-perfect.sh b/proxmox-auto-rdp-perfect.sh new file mode 100644 index 0000000..9c2a71f --- /dev/null +++ b/proxmox-auto-rdp-perfect.sh @@ -0,0 +1,507 @@ +#!/bin/bash + +# Proxmox Auto RDP Setup Script - Fixed Version +# 자동으로 Proxmox 호스트를 RDP VM에 연결하는 설정을 수행합니다 +# 원본 스크립트의 깜빡임 문제를 해결한 개선된 버전 + +set -euo pipefail + +# 색상 코드 정의 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +PURPLE='\033[0;35m' +CYAN='\033[0;36m' +NC='\033[0m' # No Color + +# 로그 함수들 +msg_info() { + echo -e "${BLUE}[INFO]${NC} $1" +} + +msg_ok() { + echo -e "${GREEN}[OK]${NC} $1" +} + +msg_error() { + echo -e "${RED}[ERROR]${NC} $1" + exit 1 +} + +msg_warn() { + echo -e "${YELLOW}[WARN]${NC} $1" +} + +# 헤더 출력 +print_header() { + clear + echo -e "${PURPLE}" + echo "═══════════════════════════════════════════════════════════════════" + echo " Proxmox Auto RDP Setup Script v2.0 (Fixed)" + echo "═══════════════════════════════════════════════════════════════════" + echo -e "${NC}" + echo "이 스크립트는 Proxmox VE 호스트가 부팅 시 자동으로 RDP 연결하도록 설정합니다." + echo "원본 스크립트의 깜빡임 문제를 해결한 개선된 버전입니다." + echo "" +} + +# Proxmox 버전 확인 +check_proxmox_version() { + msg_info "Proxmox VE 버전 확인 중..." + + if [ ! -f /etc/pve/.version ] && ! command -v pveversion > /dev/null 2>&1; then + msg_error "Proxmox VE가 설치되어 있지 않습니다." + fi + + local version_info + if command -v pveversion > /dev/null 2>&1; then + version_info=$(pveversion 2>/dev/null | head -n1 | awk '{print $1}' | cut -d'/' -f2 2>/dev/null || echo "unknown") + else + version_info="unknown" + fi + + if [[ "$version_info" =~ ^[0-9]+\.[0-9]+ ]]; then + local pve_version=$(echo "$version_info" | cut -d'.' -f1) + + if [ "$pve_version" -lt 8 ]; then + msg_error "지원되지 않는 Proxmox VE 버전입니다. 8.x 이상이 필요합니다." + fi + + msg_ok "Proxmox VE $pve_version.x 버전 확인됨" + else + msg_warn "Proxmox VE 버전을 확인할 수 없습니다. 계속 진행합니다..." + fi +} + +# 루트 권한 확인 +check_root() { + if [ "$EUID" -ne 0 ]; then + msg_error "이 스크립트는 root 권한으로 실행해야 합니다. sudo를 사용하세요." + fi +} + +# 입력 검증 함수 +validate_rdp_server() { + local server="$1" + + if [[ ! "$server" =~ ^[a-zA-Z0-9.-]+(:([0-9]{1,5}))?$ ]]; then + return 1 + fi + + if [[ "$server" =~ :([0-9]+)$ ]]; then + local port="${BASH_REMATCH[1]}" + if [ "$port" -gt 65535 ]; then + return 1 + fi + fi + + return 0 +} + +validate_username() { + local username="$1" + if [[ ! "$username" =~ ^[a-zA-Z0-9._-]+$ ]]; then + return 1 + fi + return 0 +} + +# 사용자 입력 받기 (환경변수 또는 대화형) +get_user_input() { + echo -e "${CYAN}RDP 연결 정보를 입력해주세요:${NC}" + echo "" + + # 환경변수에서 먼저 확인 + if [ -n "${RDP_SERVER:-}" ] && [ -n "${RDP_USER:-}" ] && [ -n "${RDP_PASSWORD:-}" ]; then + RDP_USERNAME="$RDP_USER" + LOCAL_USER="${LOCAL_USER:-rdpuser}" + + msg_info "환경변수에서 설정을 읽었습니다." + echo " RDP 서버: $RDP_SERVER" + echo " RDP 사용자: $RDP_USERNAME" + echo " 로컬 사용자: $LOCAL_USER" + return 0 + fi + + # RDP 서버 주소 + while true; do + read -p "RDP 서버 주소 (예: example.com:3389): " RDP_SERVER + if [ -z "$RDP_SERVER" ]; then + msg_warn "RDP 서버 주소는 필수입니다." + elif ! validate_rdp_server "$RDP_SERVER"; then + msg_warn "잘못된 서버 주소 형식입니다." + else + break + fi + done + + # RDP 사용자명 + while true; do + read -p "RDP 사용자명: " RDP_USERNAME + if [ -z "$RDP_USERNAME" ]; then + msg_warn "RDP 사용자명은 필수입니다." + elif ! validate_username "$RDP_USERNAME"; then + msg_warn "잘못된 사용자명 형식입니다." + else + break + fi + done + + # 패스워드 (표준 입력으로 받기) + while true; do + echo -n "RDP 패스워드: " + read -s RDP_PASSWORD + echo "" + if [ -z "$RDP_PASSWORD" ]; then + msg_warn "RDP 패스워드는 필수입니다." + continue + fi + + echo -n "패스워드 확인: " + read -s password_confirm + echo "" + + if [ "$RDP_PASSWORD" != "$password_confirm" ]; then + msg_warn "패스워드가 일치하지 않습니다." + continue + else + break + fi + done + + # 로컬 사용자명 + read -p "로컬 사용자명 [rdpuser]: " LOCAL_USER + LOCAL_USER=${LOCAL_USER:-rdpuser} + + echo "" + echo -e "${YELLOW}입력된 정보:${NC}" + echo " RDP 서버: $RDP_SERVER" + echo " RDP 사용자: $RDP_USERNAME" + echo " 로컬 사용자: $LOCAL_USER" + echo "" + + read -p "설정을 계속하시겠습니까? [y/N]: " confirm + case $confirm in + [yY]|[yY][eE][sS]) + return 0 + ;; + *) + msg_error "설정이 취소되었습니다." + ;; + esac +} + +# 백업 생성 +create_backup() { + msg_info "기존 설정 백업 중..." + + local backup_dir="/root/proxmox-rdp-backup-$(date +%Y%m%d-%H%M%S)" + mkdir -p "$backup_dir" + + if [ -f /etc/systemd/system/getty@tty1.service.d/override.conf ]; then + cp -r /etc/systemd/system/getty@tty1.service.d "$backup_dir/" 2>/dev/null || true + fi + + if id "$LOCAL_USER" &>/dev/null; then + cp -r "/home/$LOCAL_USER" "$backup_dir/home-$LOCAL_USER" 2>/dev/null || true + fi + + msg_ok "백업 완료: $backup_dir" +} + +# 네트워크 연결 확인 +check_network() { + msg_info "네트워크 연결 확인 중..." + + if ! ping -c 1 -W 5 8.8.8.8 > /dev/null 2>&1; then + msg_warn "인터넷 연결을 확인할 수 없습니다." + fi + + # RDP 서버 연결 가능 여부 확인 + local rdp_host=$(echo "$RDP_SERVER" | cut -d: -f1) + local rdp_port=$(echo "$RDP_SERVER" | grep -oE ':[0-9]+' | tr -d ':' || echo "3389") + + msg_info "RDP 서버 연결 테스트 ($rdp_host:$rdp_port)..." + + if timeout 5 bash -c "echo > /dev/tcp/$rdp_host/$rdp_port" 2>/dev/null; then + msg_ok "RDP 서버에 연결 가능합니다." + else + msg_warn "RDP 서버에 연결할 수 없습니다. 설정 후 연결을 확인하세요." + fi +} + +# 필수 패키지 설치 +install_packages() { + msg_info "필수 패키지 설치 중..." + + # 패키지 목록 + local packages=( + "freerdp3-x11" + "openbox" + "xinit" + "xterm" + "xorg" + "dbus-x11" + ) + + # APT 업데이트 + apt-get update > /dev/null 2>&1 + + # 패키지 설치 + for pkg in "${packages[@]}"; do + if ! dpkg -l "$pkg" 2>/dev/null | grep -q "^ii"; then + msg_info "설치 중: $pkg" + DEBIAN_FRONTEND=noninteractive apt-get install -y "$pkg" > /dev/null 2>&1 + fi + done + + msg_ok "모든 필수 패키지가 설치되었습니다." +} + +# 사용자 생성 +create_user() { + msg_info "사용자 설정 중..." + + if ! id "$LOCAL_USER" &>/dev/null; then + msg_info "새 사용자 생성: $LOCAL_USER" + useradd -m -s /bin/bash "$LOCAL_USER" + echo "$LOCAL_USER:$RDP_PASSWORD" | chpasswd + usermod -aG audio,video "$LOCAL_USER" + msg_ok "사용자 생성 완료: $LOCAL_USER" + else + msg_info "기존 사용자 사용: $LOCAL_USER" + usermod -aG audio,video "$LOCAL_USER" 2>/dev/null || true + fi +} + +# 자동 로그인 설정 (개선된 버전) +configure_autologin() { + msg_info "자동 로그인 설정 중..." + + # getty@tty1 서비스 중지 + systemctl stop getty@tty1.service 2>/dev/null || true + + # getty@tty1 서비스 override 디렉토리 생성 + mkdir -p /etc/systemd/system/getty@tty1.service.d/ + + # 자동 로그인 설정 (Type=idle 추가로 재시작 방지) + cat > /etc/systemd/system/getty@tty1.service.d/override.conf << EOF +[Service] +ExecStart= +ExecStart=-/sbin/agetty --autologin $LOCAL_USER --noclear %I \$TERM +Type=idle +RestartSec=0 +Restart=no +EOF + + # systemd 재로드 + systemctl daemon-reload + + msg_ok "자동 로그인 설정 완료" +} + +# X 세션 설정 +configure_x_session() { + msg_info "X 세션 설정 중..." + + # .bash_profile 설정 (tty1에서만 X 시작) + cat > "/home/$LOCAL_USER/.bash_profile" << 'EOF' +# Auto-start X on tty1 +if [[ -z $DISPLAY ]] && [[ $(tty) = /dev/tty1 ]]; then + exec startx 2>/dev/null +fi +EOF + + # .xinitrc 설정 (RDP 연결) + cat > "/home/$LOCAL_USER/.xinitrc" << EOF +#!/bin/sh + +# D-Bus 세션 버스 시작 +if [ -z "\$DBUS_SESSION_BUS_ADDRESS" ]; then + eval \$(dbus-launch --sh-syntax --exit-with-session) +fi + +# Openbox 시작 +openbox-session & + +# 화면 해상도 설정 +xrandr --output Virtual-1 --mode 1920x1080 2>/dev/null || true + +# RDP 연결 (재시도 로직 포함) +while true; do + echo "Connecting to RDP server: $RDP_SERVER" >> /home/$LOCAL_USER/rdp.log + xfreerdp3 /v:$RDP_SERVER /u:$RDP_USERNAME /p:'$RDP_PASSWORD' \\ + /f /cert:ignore /network:auto /dynamic-resolution \\ + /audio-mode:2 +clipboard +home-drive \\ + /log-level:ERROR 2>> /home/$LOCAL_USER/rdp-error.log + + # 연결 실패 시 5초 대기 후 재시도 + echo "RDP connection closed. Retrying in 5 seconds..." >> /home/$LOCAL_USER/rdp.log + sleep 5 +done +EOF + + chmod +x "/home/$LOCAL_USER/.xinitrc" + + msg_ok "X 세션 설정 완료" +} + +# Openbox 설정 +configure_openbox() { + msg_info "Openbox 설정 중..." + + mkdir -p "/home/$LOCAL_USER/.config/openbox" + + # Openbox 설정 (풀스크린, 장식 제거) + cat > "/home/$LOCAL_USER/.config/openbox/rc.xml" << 'EOF' + + + + + no + yes + yes + + + + + + + + + 400 + 0 + + +EOF + + # autostart 파일 생성 + cat > "/home/$LOCAL_USER/.config/openbox/autostart" << 'EOF' +# 화면 보호기 비활성화 +xset s off +xset -dpms +xset s noblank +EOF + + chmod +x "/home/$LOCAL_USER/.config/openbox/autostart" + + msg_ok "Openbox 설정 완료" +} + +# 권한 설정 +set_permissions() { + msg_info "권한 설정 중..." + + chown -R "$LOCAL_USER:$LOCAL_USER" "/home/$LOCAL_USER" + chmod 755 "/home/$LOCAL_USER" + + msg_ok "권한 설정 완료" +} + +# 서비스 활성화 +enable_services() { + msg_info "서비스 활성화 중..." + + # getty@tty1 서비스 활성화 (마스킹 해제) + systemctl unmask getty@tty1.service 2>/dev/null || true + systemctl enable getty@tty1.service + + # 기본 타겟 확인 + if [ "$(systemctl get-default)" != "graphical.target" ]; then + systemctl set-default graphical.target + fi + + msg_ok "서비스 활성화 완료" +} + +# 설정 검증 +verify_configuration() { + msg_info "설정 검증 중..." + + local errors=0 + + # 설정 파일 존재 확인 + local required_files=( + "/etc/systemd/system/getty@tty1.service.d/override.conf" + "/home/$LOCAL_USER/.bash_profile" + "/home/$LOCAL_USER/.xinitrc" + "/home/$LOCAL_USER/.config/openbox/rc.xml" + ) + + for file in "${required_files[@]}"; do + if [ ! -f "$file" ]; then + msg_warn "설정 파일이 없습니다: $file" + ((errors++)) + fi + done + + # 서비스 상태 확인 + if ! systemctl is-enabled getty@tty1.service > /dev/null 2>&1; then + msg_warn "getty@tty1 서비스가 활성화되지 않았습니다." + ((errors++)) + fi + + if [ $errors -eq 0 ]; then + msg_ok "모든 설정이 정상적으로 완료되었습니다." + return 0 + else + msg_warn "일부 설정에 문제가 있을 수 있습니다." + return 1 + fi +} + +# 완료 메시지 +print_completion() { + echo "" + echo -e "${GREEN}═══════════════════════════════════════════════════════════════════${NC}" + echo -e "${GREEN} 설정이 완료되었습니다!${NC}" + echo -e "${GREEN}═══════════════════════════════════════════════════════════════════${NC}" + echo "" + echo "설정 정보:" + echo " - RDP 서버: $RDP_SERVER" + echo " - RDP 사용자: $RDP_USERNAME" + echo " - 로컬 사용자: $LOCAL_USER" + echo "" + echo "다음 명령으로 즉시 시작할 수 있습니다:" + echo -e " ${CYAN}systemctl restart getty@tty1.service${NC}" + echo "" + echo "또는 시스템을 재부팅하면 자동으로 RDP에 연결됩니다:" + echo -e " ${CYAN}reboot${NC}" + echo "" + echo "문제가 발생하면 다음 로그를 확인하세요:" + echo " - /home/$LOCAL_USER/rdp.log" + echo " - /home/$LOCAL_USER/rdp-error.log" + echo " - journalctl -u getty@tty1.service -f" + echo "" + echo "다른 터미널로 접속하려면 Ctrl+Alt+F2를 사용하세요." + echo "" +} + +# 메인 함수 +main() { + print_header + check_root + check_proxmox_version + get_user_input + check_network + create_backup + install_packages + create_user + configure_autologin + configure_x_session + configure_openbox + set_permissions + enable_services + verify_configuration + print_completion +} + +# 환경변수 지원 (비대화형 설치) +# 사용법: RDP_SERVER="server:port" RDP_USER="username" RDP_PASSWORD="password" ./script.sh +if [ -n "${RDP_SERVER:-}" ] && [ -n "${RDP_USER:-}" ] && [ -n "${RDP_PASSWORD:-}" ]; then + export NON_INTERACTIVE=1 +fi + +# 스크립트 실행 +main "$@" \ No newline at end of file