pharmacy-pos-qr-system/docs/WEBSOCKET_PROXY_TROUBLESHOOTING.md
thug0bin cb90d4a7a6 fix: 처방목록 조회 기준을 발행일에서 조제일로 변경
문제:
- PMR 처방 목록이 PassDay(처방전 발행일) 기준으로 조회되어
  발행일과 조제일이 다른 처방(예: 3일 전 발행, 오늘 조제)이
  오늘 목록에 표시되지 않는 버그

해결:
- PS_MAIN 테이블 조회 시 PassDay 대신 Indate(조제일) 기준으로 변경
- issue_date(발행일), dispense_date(조제일) 필드 추가로 구분 명확화

추가 변경:
- WebSocket 연결/해제 시 토스트 알림 추가
- WebSocket 프록시 트러블슈팅 문서 추가 (NPM 설정 가이드)
2026-03-05 10:56:24 +09:00

279 lines
6.9 KiB
Markdown

# 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)*