headscale-tailscale-replace.../farmq-admin/VNC_Implementation_Technical_Documentation.md
시골약사 fb00b0a5fd Add multi-host Proxmox support with SSL certificate handling
- Added support for multiple Proxmox hosts (pve7.0bin.in:443, Healthport PVE:8006)
- Enhanced VM management APIs to accept host parameter
- Fixed WebSocket URL generation bug (dynamic port handling)
- Added comprehensive SSL certificate trust help system
- Implemented host selection dropdown in UI
- Added VNC connection failure detection and automatic SSL help redirection
- Updated session management to store host_key information
- Enhanced error handling for different Proxmox configurations

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-13 00:03:25 +09:00

6.8 KiB

VNC 웹소켓 구현 기술 문서

Proxmox API를 이용한 noVNC 통합 가이드

📋 개요

이 문서는 Proxmox VE API를 활용하여 웹 브라우저에서 직접 가상머신에 VNC 접속할 수 있는 시스템의 기술적 구현 내용을 설명합니다. Flask 백엔드와 noVNC 클라이언트를 통해 브라우저에서 직접 VM 콘솔에 접근할 수 있도록 구현되었습니다.

🏗️ 시스템 아키텍처

[웹 브라우저] 
    ↓ HTTPS
[NPM 리버스 프록시] 
    ↓ HTTP
[Flask 애플리케이션]
    ↓ HTTPS API
[Proxmox VE 서버]
    ↓ WebSocket (WSS)
[VM VNC 서버]

🔧 핵심 구성요소

1. Proxmox API 클라이언트 (utils/proxmox_client.py)

주요 기능:

  • Proxmox VE API 인증 및 세션 관리
  • VNC 티켓 생성 및 WebSocket URL 생성
  • VM 상태 관리 (시작/정지/상태확인)

핵심 구현:

def get_vnc_ticket(self, node: str, vmid: int) -> Optional[Dict]:
    """VNC 접속 티켓 생성"""
    data = {
        'websocket': '1',
        'generate-password': '1'  # 자동 패스워드 생성
    }
    response = self.session.post(
        f"{self.base_url}/nodes/{node}/qemu/{vmid}/vncproxy",
        data=data,
        timeout=10
    )
    
    if response.status_code == 200:
        vnc_data = response.json()['data']
        encoded_ticket = quote_plus(vnc_data['ticket'])
        vnc_data['websocket_url'] = f"wss://{self.host}:443/api2/json/nodes/{node}/qemu/{vmid}/vncwebsocket?port={vnc_data['port']}&vncticket={encoded_ticket}"
        return vnc_data

인증 방식:

  • 세션 쿠키 방식 (PVEAuthCookie)
  • CSRF 토큰 헤더 (CSRFPreventionToken)
  • API 토큰 방식 지원

2. Flask 웹 애플리케이션 (app.py)

주요 엔드포인트:

  • /vnc/<int:vm_id>: VNC 클라이언트 페이지 렌더링
  • API 엔드포인트들을 통한 VM 관리

로깅 시스템:

def setup_logging():
    if not os.path.exists('logs'):
        os.makedirs('logs')
    
    file_handler = RotatingFileHandler(
        'logs/farmq-admin.log', 
        maxBytes=10*1024*1024, 
        backupCount=5
    )

3. noVNC 클라이언트 (templates/vnc_simple.html)

핵심 기능:

  • WebSocket을 통한 VNC 프로토콜 처리
  • 자동 리사이징 및 스케일링
  • HTML 엔티티 디코딩 (패스워드 처리)

WebSocket 연결 코드:

function connectVNC() {
    const rfb = new RFB(document.getElementById('screen'), websocketUrl, {
        credentials: { 
            password: decodeHtmlEntities('{{ vnc_data.password }}') 
        }
    });
    
    rfb.addEventListener("connect", () => {
        console.log("VNC 연결 성공");
        resizeScreen();
    });
    
    rfb.addEventListener("disconnect", (e) => {
        console.log(`VNC 연결 종료: ${e.detail.clean ? '정상' : '비정상'}`);
    });
}

HTML 엔티티 디코딩:

function decodeHtmlEntities(text) {
    const textarea = document.createElement('textarea');
    textarea.innerHTML = text;
    return textarea.value;
}

🔐 보안 및 인증

VNC 인증 플로우

  1. 티켓 요청: Flask → Proxmox API (/vncproxy)
  2. 티켓 생성: Proxmox가 일회용 VNC 티켓 및 패스워드 생성
  3. WebSocket 연결: 브라우저 → Proxmox VNC WebSocket
  4. VNC 인증: 생성된 패스워드로 VNC 서버 인증

보안 설정

# SSL 검증 무시 (내부 네트워크)
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
self.session.verify = False

# WebSocket URL에 티켓 인코딩
encoded_ticket = quote_plus(vnc_data['ticket'])

🌐 네트워크 구성

NPM (Nginx Proxy Manager) 설정

  • 외부 도메인: https://pve7.0bin.in
  • 내부 주소: https://192.168.0.5:8006
  • WebSocket 지원: Upgrade 헤더 프록시 필요

WebSocket 프록시 요구사항

# WebSocket 업그레이드 헤더
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;

성능 최적화

Canvas 자동 리사이징

function resizeScreen() {
    const canvas = document.querySelector('#screen canvas');
    if (canvas) {
        const container = document.getElementById('screen');
        const scaleX = container.clientWidth / canvas.width;
        const scaleY = container.clientHeight / canvas.height;
        const scale = Math.min(scaleX, scaleY, 1);
        
        canvas.style.transform = `scale(${scale})`;
        canvas.style.transformOrigin = 'top left';
    }
}

연결 상태 관리

  • 자동 재연결 로직
  • 연결 품질 모니터링
  • 에러 처리 및 사용자 피드백

🐛 문제 해결 가이드

일반적인 문제들

1. WebSocket 1006 에러 (비정상 연결 종료)

  • 원인: NPM 프록시 WebSocket 설정 부족
  • 해결: WebSocket 업그레이드 헤더 설정 확인

2. VNC 인증 실패 (HTTP 401)

  • 원인: 잘못된 티켓 또는 패스워드
  • 해결: generate-password: 1 설정 확인

3. 빈 화면 또는 검은 화면

  • 원인: Canvas 리사이징 문제
  • 해결: resizeScreen() 함수 호출 확인

4. HTML 엔티티 문제

  • 원인: 패스워드의 특수문자 인코딩
  • 해결: decodeHtmlEntities() 함수 적용

디버깅 도구

1. 서버 사이드 테스트

cd /srv/headscale-setup/farmq-admin
python test_vnc_websocket.py

2. 로그 확인

tail -f logs/farmq-admin.log

3. 브라우저 개발자 도구

  • Network 탭: WebSocket 연결 상태 확인
  • Console 탭: JavaScript 에러 확인

📊 모니터링 및 로깅

로그 레벨

  • INFO: 정상 동작 로그
  • WARNING: 경고사항
  • ERROR: 오류 발생
  • DEBUG: 상세 디버깅 정보

중요 로그 포인트

  • VNC 티켓 생성 성공/실패
  • WebSocket 연결 시도
  • VNC 인증 결과
  • 연결 종료 사유

🔄 배포 및 유지보수

배포 체크리스트

  • Proxmox API 연결 테스트
  • Flask 애플리케이션 시작 확인
  • NPM 프록시 설정 검증
  • WebSocket 연결 테스트
  • VNC 클라이언트 동작 확인

백업 및 복구

# Git 커밋 상태 확인
git log --oneline -10

# 안정된 버전으로 롤백
git reset --hard 1dc09101cc7afdf09ca3b8cbbc4f95e21bb5746f

📚 참고 자료

🏷️ 버전 정보

  • 프로젝트: FarmQ Admin VNC Integration
  • 마지막 업데이트: 2024년
  • 안정 버전: commit 1dc09101cc7afdf09ca3b8cbbc4f95e21bb5746f
  • Python: 3.x
  • Flask: 최신 안정 버전
  • noVNC: 최신 버전