diff --git a/VNC/README.md b/VNC/README.md new file mode 100644 index 0000000..56a7e25 --- /dev/null +++ b/VNC/README.md @@ -0,0 +1,436 @@ +# PharmQ noVNC 자동 설치 스크립트 + +각 약국 Proxmox Host에 noVNC over WebSocket을 자동으로 설치하는 대화형 스크립트입니다. + +## 📦 개요 + +이 스크립트는 Proxmox VE 환경에서 실행 중인 VM의 VNC 화면을 웹 브라우저로 제공하는 시스템을 자동으로 설치합니다. + +**주요 기능:** +- ✅ 대화형 설치 (VM 자동 감지 및 선택) +- ✅ Python 가상환경 자동 구성 +- ✅ systemd 서비스 자동 등록 +- ✅ 방화벽 설정 (Tailscale VPN 전용) +- ✅ 헬스체크 및 상태 확인 +- ✅ 재설치 및 업데이트 지원 + +## 🚀 빠른 설치 + +### 원클릭 설치 (curl) + +```bash +curl -fsSL https://git.0bin.in/thug0bin/pve9-repo-fix/raw/branch/main/VNC/pharmq-novnc-setup.sh | bash +``` + +### 수동 다운로드 후 설치 + +```bash +wget https://git.0bin.in/thug0bin/pve9-repo-fix/raw/branch/main/VNC/pharmq-novnc-setup.sh +chmod +x pharmq-novnc-setup.sh +./pharmq-novnc-setup.sh +``` + +## 📋 사전 요구사항 + +### 필수 조건 +- ✅ Proxmox VE 환경 +- ✅ Root 권한 +- ✅ 실행 중인 VM (VNC 활성화) +- ✅ 인터넷 연결 + +### 자동 설치되는 패키지 +- `python3`, `python3-venv`, `python3-pip` +- `git`, `curl` +- `websockify` +- Flask 및 관련 Python 패키지 + +## 🎯 설치 과정 + +### 1단계: 스크립트 실행 + +```bash +curl -fsSL https://git.0bin.in/thug0bin/pve9-repo-fix/raw/branch/main/VNC/pharmq-novnc-setup.sh | bash +``` + +### 2단계: VM 선택 + +스크립트가 자동으로 실행 중인 VM 목록을 표시합니다: + +``` +실행 중인 VM 목록: + + 1) VM 201 - PharmQ Server (VM 201) (VNC: 5988) + 2) VM 202 - PharmQ Client (VM 202) (VNC: 5989) + +VM1 선택 (번호 입력): 1 +VM2를 추가하시겠습니까? [y/N]: y +VM2 선택 (번호 입력): 2 +``` + +### 3단계: 약국 정보 입력 + +``` +약국 코드 (예: P0014): P0014 +약국 이름 (예: 늘기쁨약국): 늘기쁨약국 +Proxmox 호스트 IP [192.168.0.200]: (Enter) +Proxmox 사용자명 [root@pam]: (Enter) +Proxmox 비밀번호: ******** +``` + +### 4단계: 자동 설치 + +- ✅ 패키지 설치 +- ✅ pharmq-novnc 다운로드 +- ✅ Python 가상환경 구성 +- ✅ 설정 파일 생성 +- ✅ systemd 서비스 등록 +- ✅ 서비스 시작 + +### 5단계: 완료 + +``` +═══════════════════════════════════════════════════════════════════ + 설치가 완료되었습니다! +═══════════════════════════════════════════════════════════════════ + +설정 요약: + 약국 코드: P0014 + 약국 이름: 늘기쁨약국 + 설치 경로: /srv/pharmq-novnc + +VM 설정: + VM1: 201 - PharmQ Server (VM 201) + - VNC 포트: 5988 + - WebSocket 포트: 6085 + VM2: 202 - PharmQ Client (VM 202) + - VNC 포트: 5989 + - WebSocket 포트: 6086 + +접속 URL: + 로컬 헬스체크: http://localhost:6000/health + VM1 noVNC: http://localhost:6000/ + VM2 noVNC: http://localhost:6000/vnc2 + +Gateway를 통한 접속 (외부): + https://gateway.pharmq.kr/api/novnc/P0014/vnc1 + https://gateway.pharmq.kr/api/novnc/P0014/vnc2 +``` + +## 🔧 설치 후 확인 + +### 서비스 상태 확인 + +```bash +systemctl status pharmq-vnc-app.service +systemctl status pharmq-websockify-vnc1.service +systemctl status pharmq-websockify-vnc2.service +``` + +### 포트 리스닝 확인 + +```bash +ss -tlnp | grep -E "6000|6085|6086" +``` + +### 헬스체크 + +```bash +curl http://localhost:6000/health +``` + +**정상 응답 예시:** +```json +{ + "status": "healthy", + "pharmacy_id": "P0014", + "pharmacy_name": "늘기쁨약국", + "vms": [ + { + "id": 201, + "name": "PharmQ Server (VM 201)", + "vnc_connected": true + }, + { + "id": 202, + "name": "PharmQ Client (VM 202)", + "vnc_connected": true + } + ] +} +``` + +## 🌐 접속 방법 + +### 1. 로컬 접속 (Proxmox Host 내부) + +``` +http://localhost:6000/ # VM1 +http://localhost:6000/vnc2 # VM2 +http://localhost:6000/health # 헬스체크 +``` + +### 2. Tailscale VPN을 통한 직접 접속 + +``` +http://100.64.0.24:6000/ # VM1 (약국 VPN IP 사용) +http://100.64.0.24:6000/vnc2 # VM2 +``` + +### 3. Gateway를 통한 접속 (권장) + +``` +https://gateway.pharmq.kr/api/novnc/P0014/vnc1 # VM1 +https://gateway.pharmq.kr/api/novnc/P0014/vnc2 # VM2 +``` + +## 🔒 보안 설정 + +스크립트 실행 중 방화벽 설정 옵션: + +``` +방화벽 설정을 진행하시겠습니까? [y/N]: y +``` + +이 옵션을 선택하면: +- ✅ Tailscale VPN(`tailscale0`)에서만 접근 허용 +- ✅ 외부 인터넷에서 직접 접근 차단 +- ✅ SSH 접속은 영향 없음 + +### 수동 방화벽 설정 + +```bash +# Tailscale VPN 인터페이스에서만 허용 +ufw allow in on tailscale0 to any port 6000,6085,6086 proto tcp + +# 외부 접근 차단 +ufw deny 6000/tcp +ufw deny 6085/tcp +ufw deny 6086/tcp + +# 방화벽 활성화 +ufw enable +``` + +## 🔄 재설치 및 업데이트 + +### 재설치 + +스크립트를 다시 실행하면 기존 설치를 감지하고 옵션을 제공합니다: + +```bash +curl -fsSL https://git.0bin.in/thug0bin/pve9-repo-fix/raw/branch/main/VNC/pharmq-novnc-setup.sh | bash +``` + +``` +✅ PharmQ noVNC가 이미 설치되어 있습니다! + +현재 설정: + 약국 코드: P0014 + 약국 이름: 늘기쁨약국 + +다음 중 선택하세요: + 1) 상태 확인 + 2) 재설치 (기존 설정 백업 후 새로 설치) + 3) 종료 + +선택 [1/2/3]: +``` + +### 서비스 재시작 + +```bash +# 전체 서비스 재시작 +systemctl restart pharmq-websockify-vnc1.service +systemctl restart pharmq-websockify-vnc2.service +systemctl restart pharmq-vnc-app.service +``` + +### 설정 파일 수동 편집 + +```bash +nano /srv/pharmq-novnc/config.json +systemctl restart pharmq-vnc-app.service +``` + +## 📊 관리 명령어 + +### 상태 확인 + +```bash +/srv/pharmq-novnc/scripts/check-status.sh +``` + +### 로그 확인 + +```bash +# 실시간 로그 +journalctl -u pharmq-vnc-app.service -f +journalctl -u pharmq-websockify-vnc1.service -f + +# 최근 로그 +journalctl -u pharmq-vnc-app.service -n 100 +``` + +### 서비스 중지 + +```bash +systemctl stop pharmq-vnc-app.service +systemctl stop pharmq-websockify-vnc1.service +systemctl stop pharmq-websockify-vnc2.service +``` + +### 서비스 비활성화 + +```bash +systemctl disable pharmq-vnc-app.service +systemctl disable pharmq-websockify-vnc1.service +systemctl disable pharmq-websockify-vnc2.service +``` + +## 🐛 트러블슈팅 + +### 문제: 서비스가 시작되지 않음 + +```bash +# 로그 확인 +journalctl -xeu pharmq-vnc-app.service + +# 수동 테스트 +source /srv/pharmq-novnc/venv/bin/activate +cd /srv/pharmq-novnc +python3 app.py +``` + +### 문제: VNC 화면이 검은색 + +```bash +# VM 상태 확인 +qm status 201 +qm status 202 + +# VNC 포트 확인 +nc -zv localhost 5988 +nc -zv localhost 5989 + +# Websockify 재시작 +systemctl restart pharmq-websockify-vnc1.service +systemctl restart pharmq-websockify-vnc2.service +``` + +### 문제: Gateway에서 502 에러 + +```bash +# 약국 서버 헬스체크 +curl http://localhost:6000/health + +# Tailscale 연결 확인 +tailscale status + +# Flask App 재시작 +systemctl restart pharmq-vnc-app.service +``` + +### 문제: 포트 충돌 + +```bash +# 포트 사용 중인 프로세스 확인 +ss -tlnp | grep 6000 +ss -tlnp | grep 6085 +ss -tlnp | grep 6086 + +# 프로세스 종료 +kill +``` + +## 📁 디렉토리 구조 + +``` +/srv/pharmq-novnc/ +├── app.py # Flask 애플리케이션 +├── config.json # 설정 파일 +├── requirements.txt # Python 패키지 목록 +├── venv/ # Python 가상환경 +├── static/ # 정적 파일 (CSS, JS) +├── templates/ # HTML 템플릿 +├── systemd/ # systemd 서비스 파일 +│ ├── pharmq-vnc-app.service +│ ├── pharmq-websockify-vnc1.service +│ └── pharmq-websockify-vnc2.service +└── scripts/ + ├── check-status.sh # 상태 확인 스크립트 + └── restart-all.sh # 전체 재시작 스크립트 +``` + +## 🔗 관련 문서 + +- **pharmq-novnc 리포지토리**: https://git.0bin.in/thug0bin/pharmq-novnc +- **Gateway 통합 문서**: /srv/docs/VNCoverVPN.md +- **Frontend 통합 가이드**: pharmq_on CloudBillingService 컴포넌트 + +## 📞 지원 + +설치 중 문제 발생 시: + +1. 스크립트 로그 저장: + ```bash + script /tmp/install-log.txt + curl -fsSL https://git.0bin.in/.../pharmq-novnc-setup.sh | bash + exit + ``` + +2. 서비스 로그 수집: + ```bash + journalctl -u pharmq-vnc-app.service -n 100 > /tmp/vnc-app.log + journalctl -u pharmq-websockify-vnc1.service -n 100 > /tmp/vnc1.log + ``` + +3. PharmQ 개발팀에 문의 + +## 🎯 setupScripts.ts 통합 + +프론트엔드 [setupScripts.ts](pharmq_on/src/constants/setupScripts.ts)에 추가: + +```typescript +{ + id: 'pharmq-novnc-setup', + title: '5단계: PharmQ noVNC 설치', + emoji: '🖥️', + description: 'VM VNC 화면을 웹 브라우저로 제공 (대화형 설치)', + command: 'curl -fsSL https://git.0bin.in/thug0bin/pve9-repo-fix/raw/branch/main/VNC/pharmq-novnc-setup.sh | bash', + category: 'core', + step: 5, + details: { + prerequisite: '⚠️ 1단계(Repository Fix) + 2단계(VPN 등록) 완료 필수', + problemDescription: [ + 'VM VNC 화면에 직접 접근하기 어려움', + '중앙 관리자가 약국 PC 화면을 원격으로 확인 필요', + 'VNC 프로토콜을 웹 브라우저에서 사용 불가' + ], + features: [ + 'VM 자동 감지 및 선택', + 'noVNC over WebSocket 설치', + 'Proxmox API 통합 (마우스 리셋)', + 'systemd 서비스 자동 등록', + '방화벽 설정 (Tailscale VPN 전용)', + 'Gateway 연동 (https://gateway.pharmq.kr)' + ], + verification: [ + '설치 완료 후 표시되는 URL 확인', + 'curl http://localhost:6000/health', + 'https://gateway.pharmq.kr/api/novnc/P0014/vnc1 접속' + ], + warnings: [ + '1단계 + 2단계 완료 후 실행', + 'Proxmox VE 환경 필수', + 'Root 권한 필요', + '실행 중인 VM이 있어야 함' + ] + } +} +``` + +--- + +**버전**: 1.0 +**작성일**: 2025-11-21 +**작성자**: PharmQ Development Team diff --git a/VNC/pharmq-novnc-setup.sh b/VNC/pharmq-novnc-setup.sh new file mode 100755 index 0000000..eb69822 --- /dev/null +++ b/VNC/pharmq-novnc-setup.sh @@ -0,0 +1,678 @@ +#!/bin/bash + +# PharmQ noVNC Setup Script +# Proxmox Host에 noVNC over WebSocket 자동 설치 +# 사용법: curl -fsSL https://git.0bin.in/thug0bin/pve9-repo-fix/raw/branch/main/VNC/pharmq-novnc-setup.sh | bash + +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 " PharmQ noVNC Setup Script v1.0" + echo "═══════════════════════════════════════════════════════════════════" + echo -e "${NC}" + echo "이 스크립트는 Proxmox Host에 noVNC over WebSocket을 자동으로 설치합니다." + echo "각 약국의 VM VNC 화면을 웹 브라우저로 제공합니다." + echo "" +} + +# Proxmox 버전 확인 +check_proxmox_version() { + msg_info "Proxmox VE 버전 확인 중..." + + if ! command -v pveversion > /dev/null 2>&1; then + msg_warn "pveversion 명령을 찾을 수 없습니다. Proxmox 환경이 아닐 수 있습니다." + read -p "계속 진행하시겠습니까? [y/N]: " continue_anyway /dev/null | head -n1 | grep -oP '\d+\.\d+' | head -n1 | cut -d'.' -f1) + + if [ -z "$pve_version" ]; then + msg_warn "Proxmox VE 버전을 확인할 수 없습니다. 계속 진행합니다." + return 0 + fi + + if ! [[ "$pve_version" =~ ^[0-9]+$ ]]; then + msg_warn "Proxmox VE 버전 형식이 올바르지 않습니다 ($pve_version). 계속 진행합니다." + return 0 + fi + + msg_ok "Proxmox VE $pve_version.x 버전 확인됨" +} + +# 루트 권한 확인 +check_root() { + if [ "$EUID" -ne 0 ]; then + msg_error "이 스크립트는 root 권한으로 실행해야 합니다. sudo를 사용하세요." + fi +} + +# VM 정보 가져오기 +get_vm_list() { + msg_info "실행 중인 VM 목록 가져오는 중..." + + if ! command -v qm > /dev/null 2>&1; then + msg_error "qm 명령어를 찾을 수 없습니다. Proxmox VE 환경이 아닙니다." + fi + + # 실행 중인 VM 목록 + VM_LIST=$(qm list 2>/dev/null | tail -n +2 | awk '{print $1}' | sort -n) + + if [ -z "$VM_LIST" ]; then + msg_warn "실행 중인 VM이 없습니다." + return 1 + fi + + msg_ok "VM 목록 가져오기 완료" + return 0 +} + +# VNC 포트 가져오기 +get_vnc_port() { + local vmid=$1 + local vnc_port=$(qm config "$vmid" 2>/dev/null | grep -oP 'vnc.*?:59\d+' | grep -oP '59\d+' | head -n1) + echo "$vnc_port" +} + +# VM 선택 및 설정 +configure_vms() { + echo -e "${CYAN}VM 설정을 시작합니다:${NC}" + echo "" + + get_vm_list || msg_error "VM을 찾을 수 없습니다." + + echo "실행 중인 VM 목록:" + echo "" + + declare -A VM_INFO + local idx=1 + + for vmid in $VM_LIST; do + local vm_name=$(qm config "$vmid" 2>/dev/null | grep "^name:" | awk '{print $2}' || echo "VM-$vmid") + local vnc_port=$(get_vnc_port "$vmid") + + if [ -n "$vnc_port" ]; then + echo " $idx) VM $vmid - $vm_name (VNC: $vnc_port)" + VM_INFO[$idx]="$vmid:$vm_name:$vnc_port" + ((idx++)) + fi + done + + if [ ${#VM_INFO[@]} -eq 0 ]; then + msg_error "VNC가 활성화된 VM이 없습니다." + fi + + echo "" + echo "noVNC로 제공할 VM을 최대 2개까지 선택하세요." + echo "" + + # VM1 선택 + while true; do + read -p "VM1 선택 (번호 입력): " vm1_choice /dev/null 2>&1; then + msg_error "인터넷 연결을 확인할 수 없습니다. 네트워크 설정을 확인해주세요." + fi + + msg_ok "네트워크 연결 확인됨" +} + +# 필수 패키지 설치 +install_packages() { + msg_info "필수 패키지 설치 중..." + + msg_info " - 패키지 목록 업데이트 중..." + if ! apt update > /dev/null 2>&1; then + msg_error "패키지 목록 업데이트에 실패했습니다." + fi + + local packages="python3 python3-venv python3-pip git curl websockify" + + for package in $packages; do + if dpkg -l | grep -q "^ii $package "; then + msg_ok " $package 이미 설치됨" + continue + fi + + msg_info " - $package 설치 중..." + if apt install -y "$package" > /dev/null 2>&1; then + msg_ok " $package 설치 완료" + else + msg_error "$package 설치에 실패했습니다." + fi + done + + msg_ok "모든 패키지 설치 완료" +} + +# pharmq-novnc 다운로드 및 설치 +install_pharmq_novnc() { + msg_info "pharmq-novnc 애플리케이션 설치 중..." + + local INSTALL_DIR="/srv/pharmq-novnc" + local REPO_URL="https://git.0bin.in/thug0bin/pharmq-novnc.git" + + # 기존 설치 확인 + if [ -d "$INSTALL_DIR" ]; then + msg_warn "기존 설치 디렉토리가 발견되었습니다: $INSTALL_DIR" + read -p "기존 설치를 덮어쓰시겠습니까? [y/N]: " overwrite /dev/null 2>&1; then + msg_ok "다운로드 완료" + else + msg_error "리포지토리 다운로드에 실패했습니다." + fi + + # Python 가상환경 생성 + msg_info "Python 가상환경 생성 중..." + cd "$INSTALL_DIR" + python3 -m venv venv + source venv/bin/activate + pip install --upgrade pip > /dev/null 2>&1 + pip install -r requirements.txt > /dev/null 2>&1 + deactivate + msg_ok "Python 가상환경 설정 완료" +} + +# config.json 생성 +create_config() { + msg_info "설정 파일 생성 중..." + + local INSTALL_DIR="/srv/pharmq-novnc" + local CONFIG_FILE="$INSTALL_DIR/config.json" + + if [ "$VM2_ENABLED" = true ]; then + cat > "$CONFIG_FILE" << EOF +{ + "pharmacy_id": "$PHARMACY_CODE", + "pharmacy_name": "$PHARMACY_NAME", + + "vnc_host": "$VNC_HOST", + + "proxmox": { + "host": "$VNC_HOST", + "port": 8006, + "username": "$PVE_USER", + "password": "$PVE_PASSWORD", + "verify_ssl": false + }, + + "vms": [ + { + "id": $VM1_ID, + "name": "$VM1_NAME", + "vnc_port": $VM1_VNC_PORT, + "websockify_port": $WS_PORT1 + }, + { + "id": $VM2_ID, + "name": "$VM2_NAME", + "vnc_port": $VM2_VNC_PORT, + "websockify_port": $WS_PORT2 + } + ], + + "flask": { + "host": "0.0.0.0", + "port": $FLASK_PORT + }, + + "notes": "vnc_host는 Proxmox VNC 서버 주소입니다. Flask는 Ubuntu VM에서 실행되며 Proxmox API를 통해 원격 VM을 제어합니다." +} +EOF + else + cat > "$CONFIG_FILE" << EOF +{ + "pharmacy_id": "$PHARMACY_CODE", + "pharmacy_name": "$PHARMACY_NAME", + + "vnc_host": "$VNC_HOST", + + "proxmox": { + "host": "$VNC_HOST", + "port": 8006, + "username": "$PVE_USER", + "password": "$PVE_PASSWORD", + "verify_ssl": false + }, + + "vms": [ + { + "id": $VM1_ID, + "name": "$VM1_NAME", + "vnc_port": $VM1_VNC_PORT, + "websockify_port": $WS_PORT1 + } + ], + + "flask": { + "host": "0.0.0.0", + "port": $FLASK_PORT + }, + + "notes": "vnc_host는 Proxmox VNC 서버 주소입니다. Flask는 Ubuntu VM에서 실행되며 Proxmox API를 통해 원격 VM을 제어합니다." +} +EOF + fi + + msg_ok "설정 파일 생성 완료: $CONFIG_FILE" +} + +# systemd 서비스 설치 +setup_systemd_services() { + msg_info "systemd 서비스 설치 중..." + + local INSTALL_DIR="/srv/pharmq-novnc" + + # 서비스 파일 복사 + cp "$INSTALL_DIR/systemd/"*.service /etc/systemd/system/ + + # systemd 리로드 + systemctl daemon-reload + + msg_ok "systemd 서비스 등록 완료" +} + +# 서비스 시작 +start_services() { + msg_info "서비스 시작 중..." + + local services=("pharmq-websockify-vnc1" "pharmq-vnc-app") + + if [ "$VM2_ENABLED" = true ]; then + services+=("pharmq-websockify-vnc2") + fi + + for service in "${services[@]}"; do + msg_info " - $service.service 시작 중..." + systemctl enable "$service.service" > /dev/null 2>&1 + systemctl restart "$service.service" + + sleep 2 + + if systemctl is-active "$service.service" > /dev/null 2>&1; then + msg_ok " $service: 실행 중" + else + msg_warn " $service: 시작 실패" + msg_info " 로그 확인: journalctl -xeu $service.service" + fi + done + + msg_ok "모든 서비스 시작 완료" +} + +# 방화벽 설정 (선택사항) +configure_firewall() { + echo "" + echo -e "${CYAN}방화벽 설정 (선택사항)${NC}" + echo "" + echo "Tailscale VPN으로만 접근하도록 방화벽을 설정하시겠습니까?" + echo "이 설정은 외부에서의 직접 접근을 차단하고 VPN을 통한 접근만 허용합니다." + echo "" + read -p "방화벽 설정을 진행하시겠습니까? [y/N]: " setup_fw /dev/null 2>&1; then + msg_info "ufw 설치 중..." + apt install -y ufw > /dev/null 2>&1 + fi + + # Tailscale 인터페이스 확인 + if ip link show tailscale0 > /dev/null 2>&1; then + ufw allow in on tailscale0 to any port $FLASK_PORT,$WS_PORT1,$WS_PORT2 proto tcp + ufw deny $FLASK_PORT/tcp + ufw deny $WS_PORT1/tcp + ufw deny $WS_PORT2/tcp + + msg_ok "방화벽 설정 완료 (Tailscale VPN만 허용)" + else + msg_warn "Tailscale 인터페이스를 찾을 수 없습니다. 방화벽 설정을 건너뜁니다." + fi + ;; + *) + msg_info "방화벽 설정을 건너뜁니다." + ;; + esac +} + +# 설치 테스트 +test_installation() { + msg_info "설치 테스트 중..." + + # 포트 리스닝 확인 + sleep 3 + + if ss -tlnp | grep -q ":$FLASK_PORT "; then + msg_ok "Flask 앱이 포트 $FLASK_PORT에서 실행 중입니다." + else + msg_warn "Flask 앱이 포트 $FLASK_PORT에서 실행되지 않습니다." + fi + + if ss -tlnp | grep -q ":$WS_PORT1 "; then + msg_ok "WebSocket 1이 포트 $WS_PORT1에서 실행 중입니다." + else + msg_warn "WebSocket 1이 포트 $WS_PORT1에서 실행되지 않습니다." + fi + + if [ "$VM2_ENABLED" = true ]; then + if ss -tlnp | grep -q ":$WS_PORT2 "; then + msg_ok "WebSocket 2가 포트 $WS_PORT2에서 실행 중입니다." + else + msg_warn "WebSocket 2가 포트 $WS_PORT2에서 실행되지 않습니다." + fi + fi + + # 헬스체크 + if curl -s -f "http://localhost:$FLASK_PORT/health" > /dev/null 2>&1; then + msg_ok "헬스체크 성공" + else + msg_warn "헬스체크 실패" + fi +} + +# 완료 메시지 +print_completion() { + echo "" + echo -e "${GREEN}═══════════════════════════════════════════════════════════════════${NC}" + echo -e "${GREEN} 설치가 완료되었습니다!${NC}" + echo -e "${GREEN}═══════════════════════════════════════════════════════════════════${NC}" + echo "" + echo -e "${CYAN}설정 요약:${NC}" + echo " 약국 코드: $PHARMACY_CODE" + echo " 약국 이름: $PHARMACY_NAME" + echo " 설치 경로: /srv/pharmq-novnc" + echo "" + echo -e "${CYAN}VM 설정:${NC}" + echo " VM1: $VM1_ID - $VM1_NAME" + echo " - VNC 포트: $VM1_VNC_PORT" + echo " - WebSocket 포트: $WS_PORT1" + if [ "$VM2_ENABLED" = true ]; then + echo " VM2: $VM2_ID - $VM2_NAME" + echo " - VNC 포트: $VM2_VNC_PORT" + echo " - WebSocket 포트: $WS_PORT2" + fi + echo "" + echo -e "${CYAN}접속 URL:${NC}" + echo " 로컬 헬스체크: http://localhost:$FLASK_PORT/health" + echo " VM1 noVNC: http://localhost:$FLASK_PORT/" + if [ "$VM2_ENABLED" = true ]; then + echo " VM2 noVNC: http://localhost:$FLASK_PORT/vnc2" + fi + echo "" + echo -e "${CYAN}Gateway를 통한 접속 (외부):${NC}" + echo " https://gateway.pharmq.kr/api/novnc/$PHARMACY_CODE/vnc1" + if [ "$VM2_ENABLED" = true ]; then + echo " https://gateway.pharmq.kr/api/novnc/$PHARMACY_CODE/vnc2" + fi + echo "" + echo -e "${CYAN}관리 명령어:${NC}" + echo " 상태 확인: /srv/pharmq-novnc/scripts/check-status.sh" + echo " 전체 재시작: systemctl restart pharmq-websockify-vnc1 pharmq-vnc-app" + if [ "$VM2_ENABLED" = true ]; then + echo " systemctl restart pharmq-websockify-vnc2" + fi + echo " 로그 확인: journalctl -u pharmq-vnc-app.service -f" + echo "" + echo -e "${YELLOW}다음 단계:${NC}" + echo " 1. 헬스체크 테스트: curl http://localhost:$FLASK_PORT/health" + echo " 2. Gateway에서 접속 테스트" + echo " 3. 브라우저에서 noVNC 화면 확인" + echo "" +} + +# 메인 함수 +main() { + print_header + + # 사전 검사 + check_root + check_proxmox_version + + # 기존 설치 확인 + if [ -f "/srv/pharmq-novnc/config.json" ] && \ + systemctl is-active --quiet pharmq-vnc-app.service; then + echo "" + echo -e "${GREEN}==========================================" + echo "✅ PharmQ noVNC가 이미 설치되어 있습니다!" + echo -e "==========================================${NC}" + echo "" + + CURRENT_PHARMACY_CODE=$(python3 -c "import json; print(json.load(open('/srv/pharmq-novnc/config.json'))['pharmacy_id'])" 2>/dev/null || echo "") + CURRENT_PHARMACY_NAME=$(python3 -c "import json; print(json.load(open('/srv/pharmq-novnc/config.json'))['pharmacy_name'])" 2>/dev/null || echo "") + + echo -e "${CYAN}현재 설정:${NC}" + echo " 약국 코드: ${CURRENT_PHARMACY_CODE:-'설정되지 않음'}" + echo " 약국 이름: ${CURRENT_PHARMACY_NAME:-'설정되지 않음'}" + echo "" + echo "다음 중 선택하세요:" + echo " 1) 상태 확인" + echo " 2) 재설치 (기존 설정 백업 후 새로 설치)" + echo " 3) 종료" + echo "" + echo -n "선택 [1/2/3]: " + read -r choice