# VNC WebSocket 연결 문제 및 프록시 솔루션 ## 🚨 현재 문제 상황 ### WebSocket 1006 연결 실패 원인 ``` WebSocket connection to 'wss://pve7.0bin.in/api2/json/nodes/pve7/qemu/102/vncwebsocket...' failed: Failed when connecting: Connection closed (code: 1006) ``` **WebSocket Error Code 1006**는 "Abnormal Closure"를 의미하며, 연결이 설정되기도 전에 종료되었음을 나타냅니다. ## 🔍 근본 원인 분석 ### 1. 브라우저 보안 정책 (Mixed Content) - **현재 상황**: HTTPS 웹사이트 (`pqadmin.0bin.in`)에서 자체 서명 인증서를 사용하는 WebSocket 연결 시도 - **브라우저 제한**: Chrome, Firefox 등 모던 브라우저는 HTTPS 페이지에서 신뢰할 수 없는 SSL 인증서로의 WebSocket 연결을 자동 차단 - **에러 발생**: 브라우저가 연결 시도 자체를 거부하여 1006 에러 발생 ### 2. SSL/TLS 인증서 신뢰 문제 ```bash # Proxmox 서버의 자체 서명 인증서 Subject: CN=Proxmox Virtual Environment Issuer: PVE Cluster Manager CA ``` - **자체 서명 인증서**: `pve7.0bin.in`이 공인 CA가 아닌 자체 서명 인증서 사용 - **브라우저 불신**: 사용자가 명시적으로 인증서를 신뢰하지 않으면 WebSocket 연결 거부 ### 3. CORS (Cross-Origin Resource Sharing) 정책 - **Origin 불일치**: `pqadmin.0bin.in`에서 `pve7.0bin.in`으로의 크로스 오리진 WebSocket 연결 - **Preflight 검사**: 브라우저가 연결 전 OPTIONS 요청을 보내지만 Proxmox가 적절한 CORS 헤더를 반환하지 않을 가능성 ## 💡 해결책 1: 역방향 프록시 (Reverse Proxy) ### 구현 방식: nginx를 통한 WebSocket 프록시 ```nginx # /etc/nginx/sites-available/pqadmin-vnc server { listen 443 ssl; server_name pqadmin.0bin.in; ssl_certificate /path/to/ssl/cert.pem; ssl_certificate_key /path/to/ssl/key.pem; # VNC WebSocket 프록시 location /vnc-proxy/ { # WebSocket 업그레이드 헤더 proxy_pass https://pve7.0bin.in/api2/json/nodes/pve7/qemu/; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $proxy_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # SSL 검증 비활성화 (자체 서명 인증서 때문) proxy_ssl_verify off; proxy_ssl_server_name on; # 타임아웃 설정 proxy_connect_timeout 60s; proxy_send_timeout 60s; proxy_read_timeout 60s; } } ``` ### 장점 - ✅ **같은 도메인**: `pqladmin.0bin.in/vnc-proxy/`로 WebSocket 연결하여 CORS 문제 해결 - ✅ **신뢰할 수 있는 SSL**: nginx가 공인 인증서를 사용하여 브라우저 신뢰 확보 - ✅ **투명한 프록시**: 클라이언트는 Proxmox 직접 연결과 동일하게 작동 ### 구현 단계 ```bash # 1. nginx 설정 파일 생성 sudo nano /etc/nginx/sites-available/pqadmin-vnc # 2. 심볼릭 링크 생성 sudo ln -s /etc/nginx/sites-available/pqadmin-vnc /etc/nginx/sites-enabled/ # 3. nginx 설정 테스트 sudo nginx -t # 4. nginx 재시작 sudo systemctl reload nginx ``` ### 클라이언트 코드 수정 ```javascript // 기존: 직접 Proxmox 연결 // const websocketUrl = 'wss://pve7.0bin.in/api2/json/nodes/pve7/qemu/102/vncwebsocket?...' // 변경: nginx 프록시를 통한 연결 const websocketUrl = 'wss://pqladmin.0bin.in/vnc-proxy/102/vncwebsocket?...' ``` ## 💡 해결책 2: WebSocket 프록시 서버 ### 구현 방식: Node.js/Python WebSocket 중계 서버 ```python # vnc_websocket_proxy.py import asyncio import websockets import ssl import json from urllib.parse import parse_qs class VNCWebSocketProxy: def __init__(self): self.proxmox_host = "pve7.0bin.in" self.proxmox_port = 443 async def proxy_websocket(self, websocket, path): # 클라이언트 요청 파싱 query_params = parse_qs(path.split('?', 1)[1] if '?' in path else '') vmid = query_params.get('vmid', [''])[0] ticket = query_params.get('vncticket', [''])[0] # Proxmox WebSocket URL 생성 proxmox_url = f"wss://{self.proxmox_host}:{self.proxmox_port}/api2/json/nodes/pve7/qemu/{vmid}/vncwebsocket?port=5900&vncticket={ticket}" # SSL 컨텍스트 (자체 서명 인증서 허용) ssl_context = ssl.create_default_context() ssl_context.check_hostname = False ssl_context.verify_mode = ssl.CERT_NONE try: # Proxmox WebSocket 연결 async with websockets.connect(proxmox_url, ssl=ssl_context) as proxmox_ws: # 양방향 데이터 중계 await asyncio.gather( self.forward_messages(websocket, proxmox_ws), self.forward_messages(proxmox_ws, websocket) ) except Exception as e: await websocket.send(json.dumps({"error": f"Proxmox connection failed: {str(e)}"})) async def forward_messages(self, source, destination): try: async for message in source: await destination.send(message) except websockets.exceptions.ConnectionClosed: pass # 프록시 서버 시작 if __name__ == "__main__": proxy = VNCWebSocketProxy() start_server = websockets.serve(proxy.proxy_websocket, "0.0.0.0", 8765) asyncio.get_event_loop().run_until_complete(start_server) asyncio.get_event_loop().run_forever() ``` ### 장점 - ✅ **완전한 제어**: WebSocket 연결 과정을 완전히 제어 가능 - ✅ **에러 처리**: 연결 실패 시 상세한 에러 메시지 제공 - ✅ **로깅**: 모든 WebSocket 트래픽 로깅 및 디버깅 가능 - ✅ **인증 확장**: 추가적인 인증 로직 구현 가능 ### 구현 단계 ```bash # 1. 의존성 설치 pip install websockets asyncio # 2. 프록시 서버 실행 python vnc_websocket_proxy.py # 3. systemd 서비스 등록 sudo systemctl enable vnc-websocket-proxy.service ``` ### 클라이언트 코드 수정 ```javascript // WebSocket 프록시 서버로 연결 const websocketUrl = 'ws://localhost:8765/vnc-proxy?vmid=102&vncticket=' + encodeURIComponent(ticket); ``` ## 📊 솔루션 비교 | 기준 | 역방향 프록시 (nginx) | WebSocket 프록시 서버 | |------|----------------------|---------------------| | **구현 복잡도** | 🟡 중간 | 🔴 높음 | | **성능** | 🟢 우수 | 🟡 양호 | | **유지보수** | 🟢 쉬움 | 🟡 보통 | | **확장성** | 🟡 제한적 | 🟢 우수 | | **디버깅** | 🟡 제한적 | 🟢 우수 | | **보안** | 🟢 안전 | 🟡 주의 필요 | | **리소스 사용량** | 🟢 낮음 | 🟡 보통 | ## 🎯 추천 솔루션 ### 단기 해결책: 역방향 프록시 (nginx) 1. **빠른 구현**: 기존 nginx 설정에 location 블록만 추가 2. **안정성**: nginx의 검증된 WebSocket 프록시 기능 활용 3. **보안**: 공인 SSL 인증서로 브라우저 신뢰 확보 ### 장기 해결책: 하이브리드 접근 1. **nginx 프록시**: 기본적인 WebSocket 중계 2. **커스텀 미들웨어**: 인증, 로깅, 모니터링 기능 추가 3. **로드 밸런싱**: 다중 Proxmox 호스트 지원 ## 🚀 구현 우선순위 ### Phase 1: nginx 역방향 프록시 구현 ```bash # 1. nginx 설정 파일 작성 # 2. SSL 인증서 설정 # 3. WebSocket 프록시 규칙 추가 # 4. 클라이언트 URL 변경 ``` ### Phase 2: 에러 처리 및 모니터링 강화 ```bash # 1. 연결 실패 시 재시도 로직 # 2. WebSocket 상태 모니터링 # 3. 로그 수집 및 분석 ``` ### Phase 3: 다중 호스트 지원 ```bash # 1. 동적 백엔드 라우팅 # 2. 헬스체크 구현 # 3. 로드 밸런싱 설정 ``` --- **결론**: WebSocket 1006 에러는 브라우저 보안 정책과 인증서 신뢰 문제가 주요 원인입니다. nginx 역방향 프록시를 통해 이 문제를 근본적으로 해결할 수 있으며, 이는 가장 실용적이고 안정적인 솔루션입니다.