WebSocket 1006 오류로 인해 브라우저에서 VNC 연결 실패 - 서버 환경에서는 연결 가능하나 브라우저 보안 정책으로 차단 - 역방향 프록시 솔루션 문서화 완료 - 추후 nginx 프록시 구현 필요 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
230 lines
8.1 KiB
Markdown
230 lines
8.1 KiB
Markdown
# 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 역방향 프록시를 통해 이 문제를 근본적으로 해결할 수 있으며, 이는 가장 실용적이고 안정적인 솔루션입니다. |