# WebSocket 프록시 트러블슈팅 가이드 ## 개요 PAAI 처방감지 시스템에서 WebSocket(wss://)을 Nginx Proxy Manager(NPM)를 통해 프록시하는 과정에서 발생한 문제들과 해결 방법을 정리한 문서입니다. **환경:** - Nginx Proxy Manager (NPM): Docker 컨테이너, CT 150 (192.168.0.105) - WebSocket 서버: trigger_server.py (192.168.0.14:8765) - 프론트엔드: https://mile.0bin.in/pmr/ - Proxmox VE: 192.168.0.119 --- ## 문제 1: WebSocket 404 오류 ### 증상 ``` WebSocket connection to 'wss://mile.0bin.in/ws' failed ``` nginx 액세스 로그에 `/ws` 요청이 404로 응답됨. ### 원인 NPM에서 `/ws` 경로에 대한 프록시 설정이 없었음. ### 해결 방법 **NPM 웹 UI에서 Advanced 설정 추가:** 1. NPM 관리자 접속 2. **Proxy Hosts** → **mile.0bin.in** → **Edit** 3. **Advanced** 탭 클릭 4. 아래 내용 입력: ```nginx location /ws { proxy_pass http://192.168.0.14:8765; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_read_timeout 86400; } ``` 5. **Save** 클릭 ### ⚠️ 주의사항 **절대 conf 파일 직접 수정하지 말 것!** NPM은 설정을 SQLite DB에 저장하고, 컨테이너 재시작 시 DB에서 conf 파일을 재생성합니다. `/data/nginx/proxy_host/167.conf` 같은 파일을 직접 수정해도 재시작 시 덮어씌워집니다. **반드시 NPM 웹 UI의 Advanced 탭을 사용하세요.** --- ## 문제 2: duplicate location 오류 ### 증상 ``` nginx: [emerg] duplicate location "/ws" in /data/nginx/custom/server_proxy.conf:1 nginx: configuration file /etc/nginx/nginx.conf test failed ``` 모든 프록시가 작동하지 않음! ### 원인 `/data/nginx/custom/server_proxy.conf`에 `/ws` location을 추가했는데, NPM Advanced 설정에서도 `/ws`를 추가하여 중복 발생. ### 해결 방법 중복 파일 삭제: ```bash # Proxmox에서 실행 pct exec 150 -- docker exec npm rm /data/nginx/custom/server_proxy.conf pct exec 150 -- docker exec npm nginx -t pct exec 150 -- docker exec npm nginx -s reload ``` ### 예방책 - `/data/nginx/custom/` 폴더는 건드리지 않기 - 모든 커스텀 설정은 **NPM 웹 UI Advanced 탭**에서만 추가 --- ## 문제 3: HTTP/2와 WebSocket 충돌 ### 증상 ``` curl: (92) HTTP/2 stream 1 was not closed cleanly: PROTOCOL_ERROR (err 1) ``` nginx 프록시를 통한 WebSocket 핸드셰이크 실패. ### 원인 - NPM이 HTTPS에서 HTTP/2를 사용 - 기존 HTTP/2는 WebSocket을 지원하지 않음 (RFC 8441 이후 지원) - nginx 1.25.1+ 필요 ### 해결 방법 **방법 1: 내부 HTTP 접속 (권장, 간단)** ``` http://192.168.0.14:7001/pmr/ ``` HTTP → ws:// 직접 연결로 HTTP/2 문제 회피 **방법 2: 프론트엔드에서 분기 처리** ```javascript const TRIGGER_WS_URL = location.protocol === 'https:' ? `wss://${location.host}/ws` // 외부: NPM 프록시 : `ws://${location.hostname}:8765`; // 내부: 직접 연결 ``` **방법 3: 별도 WebSocket 전용 서브도메인** - ws.mile.0bin.in 생성 - HTTP/2 비활성화 설정 --- ## 문제 4: nginx 설정 반영 안 됨 ### 증상 conf 파일에 설정이 있지만 `nginx -T`에서 확인 안 됨. ### 진단 방법 ```bash # 1. conf 파일 확인 pct exec 150 -- docker exec npm cat /data/nginx/proxy_host/167.conf | grep 8765 # 2. nginx 로드된 설정 확인 pct exec 150 -- docker exec npm nginx -T 2>&1 | grep 8765 # 3. 결과 비교 # 파일에는 있는데 nginx -T에 없으면 → reload 필요 또는 문법 오류 ``` ### 해결 방법 ```bash # 문법 체크 pct exec 150 -- docker exec npm nginx -t # 문제 없으면 reload pct exec 150 -- docker exec npm nginx -s reload # 그래도 안 되면 컨테이너 재시작 pct exec 150 -- docker restart npm ``` --- ## 유용한 진단 명령어 ### NPM 상태 확인 ```bash # 컨테이너 상태 pct exec 150 -- docker ps | grep npm # nginx 설정 테스트 pct exec 150 -- docker exec npm nginx -t # nginx reload pct exec 150 -- docker exec npm nginx -s reload # 컨테이너 재시작 pct exec 150 -- docker restart npm ``` ### 로그 확인 ```bash # 특정 호스트 액세스 로그 pct exec 150 -- docker exec npm tail -50 /data/logs/proxy-host-167_access.log # 에러 로그 pct exec 150 -- docker exec npm tail -20 /data/logs/proxy-host-167_error.log # /ws 요청만 필터 pct exec 150 -- docker exec npm tail -100 /data/logs/proxy-host-167_access.log | grep ws ``` ### WebSocket 연결 테스트 ```bash # 직접 연결 테스트 (CT 150에서) curl -v --max-time 5 \ -H "Connection: Upgrade" \ -H "Upgrade: websocket" \ -H "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==" \ -H "Sec-WebSocket-Version: 13" \ http://192.168.0.14:8765 # 성공 시: HTTP/1.1 101 Switching Protocols ``` ### 프록시 호스트 번호 찾기 ```bash # 도메인으로 설정 파일 찾기 pct exec 150 -- docker exec npm grep -r "mile.0bin" /data/nginx/proxy_host/ # → /data/nginx/proxy_host/167.conf ``` --- ## 최종 작동 구성 ### 네트워크 구조 ``` [브라우저] │ │ HTTPS (외부) 또는 HTTP (내부) ▼ [NPM - 192.168.0.105:443/80] │ ├─ /pmr/* → http://192.168.0.14:7001 (Flask) │ └─ /ws → http://192.168.0.14:8765 (WebSocket) [Flask 서버 - 192.168.0.14:7001] │ └─ PMR 웹 앱 [Trigger 서버 - 192.168.0.14:8765] │ └─ WebSocket 처방 감지 알림 ``` ### 프론트엔드 WebSocket 연결 코드 ```javascript // pmr.html const TRIGGER_WS_URL = location.protocol === 'https:' ? `wss://${location.host}/ws` // 외부: NPM 프록시 : `ws://${location.hostname}:8765`; // 내부: 직접 연결 ``` ### NPM Advanced 설정 (mile.0bin.in) ```nginx location /ws { proxy_pass http://192.168.0.14:8765; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_read_timeout 86400; } ``` --- ## 체크리스트 WebSocket 프록시 설정 시 확인 사항: - [ ] WebSocket 서버(trigger_server.py) 실행 중인가? - [ ] 8765 포트 리스닝 중인가? (`netstat -ano | findstr :8765`) - [ ] NPM Advanced에 /ws location 설정했는가? - [ ] `/data/nginx/custom/` 폴더에 중복 설정 없는가? - [ ] `nginx -t` 통과하는가? - [ ] nginx reload 했는가? - [ ] 브라우저 캐시 비웠는가? (Ctrl+Shift+R) --- ## 교훈 1. **NPM 설정은 반드시 웹 UI로** - conf 파일 직접 수정 금지 2. **duplicate location 주의** - custom 폴더와 Advanced 설정 중복 확인 3. **HTTP/2 + WebSocket = 문제** - 내부 HTTP 접속 또는 별도 서브도메인 사용 4. **변경 후 항상 테스트** - `nginx -t` 습관화 5. **문제 생기면 로그 먼저** - access_log, error_log 확인 --- *작성일: 2026-03-05* *작성: 용림 (Clawdbot)*