generated from ttipo/project-base
chore(docker): 메일 엔진·네트워크 분리·같은 주소 배포와 Node 24 고정 #1
@@ -34,6 +34,9 @@ map $http_referer $log_referer {
|
||||
# 새 메일 확인(GET /api/mail-state — 화면이 보이는 동안 탭마다 1분에 한 번)은 성공(2xx·304)하면 접근 로그를 남기지 않는다 —
|
||||
# 로깅 규칙 "반복되는 정상 흐름(헬스체크, 폴링)은 로그를 남기지 않는다". 실패(401·5xx 등, 오류용 이름 있는 location 포함)는 남긴다.
|
||||
# 0 이면 server 단계 access_log 의 if= 가 그 줄을 쓰지 않는다. $uri 는 쿼리를 뺀 경로다 (이 요청은 내부 이동이 없다)
|
||||
# 실시간 알림(GET /api/mail-events, SSE)은 성공도 남긴다 — 줄은 연결이 끝날 때 하나(브라우저마다 대략 1시간에 한 번 — 1분 확인의 수십분의 1)이고
|
||||
# rt= 가 연결이 이어진 시간이다. 스트림이 시작된 뒤에는 어떻게 끝나도(서버의 end · 탭 닫기 · 백엔드가 중간에 끊김) 상태가 200 이라,
|
||||
# 200 을 빼면 일찍 끊기는 연결의 흔적까지 사라진다 (2026-10-28 확인). 연결 전 실패(401·429·503·502 등)는 물론 남는다.
|
||||
map "$request_method:$uri:$status" $log_access {
|
||||
"~^GET:/api/mail-state:(?:2[0-9][0-9]|304)$" 0;
|
||||
default 1;
|
||||
@@ -228,6 +231,32 @@ server {
|
||||
proxy_read_timeout 90s;
|
||||
proxy_pass $backend_upstream;
|
||||
}
|
||||
|
||||
# 실시간 알림(GET /api/mail-events, 계약 2절 "실시간 알림") — SSE(text/event-stream). 브라우저마다 연결 하나가 액세스 토큰이 끝날 때까지
|
||||
# (최대 1시간 — 그 30초 전에 서버가 end 를 보내고 닫는다) 열려 있고, 서버가 25초마다 ping 을 보낸다. 아래 동작은 2026-10-28 가짜 백엔드로 확인했다.
|
||||
# - 버퍼링을 끈다: 켜 두면 머리글을 첫 이벤트가 올 때까지 붙잡고, 백엔드가 청크 없이 연결을 닫아 끝내는 응답을 보내면 끝날 때까지 전부 붙잡는다.
|
||||
# 백엔드가 보내는 X-Accel-Buffering: no 로도 꺼지지만 그 머리글에 기대지 않는다. 캐시는 지금 어디에도 없다 — 나중에 /api 에 생겨도 이 경로는 빼 둔다.
|
||||
# - 압축을 끈다: gzip_types 에 text/event-stream 이 없어 지금도 압축하지 않지만, 목록을 넓혀도 이 경로는 압축하지 않게
|
||||
# (백엔드가 Cache-Control: no-transform 으로 바꾸지 말라고 해도 nginx 의 gzip 은 압축한다).
|
||||
# - 읽기 시간 제한 90s(다른 90s 경로와 같은 값)는 응답 전체가 아니라 백엔드에서 "두 번 읽는 사이"의 시간이다 — 연결이 1시간 이어져도
|
||||
# 25초마다 오는 ping 이 매번 새로 세게 한다. 서버 ping 25초 · 화면 감시 75초보다 길어 정상 연결은 끊지 않는다 (ping 이 멈추면 화면이 먼저 끊는다).
|
||||
# 머리글을 기다릴 때도 같은 값이라, 백엔드가 머리글을 보내지 않으면 90초에 504 로 끊는다 (@api_unavailable 의 JSON SYS_001).
|
||||
# ⚠️ 서버의 ping 간격(계약 2절)을 바꾸면 이 값도 함께 본다 — ping 간격보다 넉넉히 길어야 한다.
|
||||
# 클라이언트 쪽 쓰기 제한(send_timeout 60s)은 쓰기가 막혔을 때만 세므로 그대로 둔다.
|
||||
# - X-Accel-Buffering 을 넘긴다: nginx 는 이 머리글을 기본으로 지우는데, 외부 리버스 프록시가 nginx 계열이면 이것을 보고 그쪽도 이 응답만
|
||||
# 버퍼링을 끈다 — 기본 설정의 nginx 가 머리글을 첫 이벤트까지 붙잡지 않고 바로 보낸다 (docker 스킬 "외부 리버스 프록시 요구사항").
|
||||
# 브라우저는 이 머리글을 쓰지 않는다.
|
||||
# 머리글(proxy_set_header — 여기 쓰지 않는다) · 오류 응답(@api_unavailable 등) · 접근 로그는 위 /api 와 server 단계 것을 그대로 물려받는다.
|
||||
# 열린 연결 하나가 nginx 연결 둘(클라이언트 쪽 · 백엔드 쪽)을 1시간까지 잡는다 — 수용량은 이미지 기본 nginx.conf 를 따른다
|
||||
# (워커마다 worker_connections 1024, 워커 수 auto).
|
||||
location ^~ /api/mail-events {
|
||||
proxy_buffering off;
|
||||
proxy_cache off;
|
||||
gzip off;
|
||||
proxy_read_timeout 90s;
|
||||
proxy_pass_header X-Accel-Buffering;
|
||||
proxy_pass $backend_upstream;
|
||||
}
|
||||
}
|
||||
|
||||
# /api 의 nginx 오류 응답 — message 는 비운다 (문구는 클라이언트가 code 로 사전에서 찾는다, 레지스트리와 겹치지 않게).
|
||||
|
||||
Reference in New Issue
Block a user