컨텐츠로 건너뛰기

리버스 프록시

Nginx, Nginx Proxy Manager, Caddy, Cloudflare 또는 다른 리버스 프록시 뒤에서 OpenChamber를 실행한다면 이 페이지를 사용하세요.

프록시를 두기 전에

  1. 먼저 OpenChamber가 직접 작동하는지 확인하세요.
  2. 같은 네트워크에서 http://<server-ip>:3000 또는 사용자 지정 포트를 여세요.
  3. 직접 연결이 작동한 후에만 리버스 프록시를 추가하세요.

프록시가 지원해야 하는 것

  • 실시간 메시지 전송을 위한 WebSocket:
    • /api/event/ws
    • /api/global/event/ws
    • /api/terminal/ws
  • 버퍼링 없는 SSE:
    • /api/event
    • /api/global/event
    • /api/notifications/stream
    • /api/openchamber/events
    • /api/terminal/:sessionId/stream
  • 첨부 파일 및 파일 작업을 위한 대용량 요청 본문
  • 실시간 스트림과 터미널 세션을 위한 긴 읽기 타임아웃

중요한 규칙

  • WebSocket 프록시를 활성화하세요.
  • SSE 경로에서 버퍼링을 비활성화하세요.
  • OpenChamber가 이미 응답을 압축한다면 프록시에서 gzip을 비활성화하세요.
  • 압축은 한 계층에서만 켜두세요.
  • Host, X-Forwarded-For, X-Forwarded-Proto 같은 일반 프록시 헤더를 전달하세요.
  • 사용자가 파일을 업로드한다면 본문 크기 제한을 늘리세요.

빠른 체크리스트

  • LAN에서 OpenChamber에 직접 접근 가능
  • 프록시에서 WebSocket 활성화
  • SSE 경로의 버퍼링 꺼짐
  • 프록시 호스트에서 gzip off, 또는 다른 방식으로 프록시 압축 비활성화
  • 첨부 파일에 충분히 큰 client_max_body_size
  • 스트림에 충분히 긴 proxy_read_timeout

예시: Nginx

예시 구성 보기
client_max_body_size 50M;
client_body_buffer_size 50M;
proxy_request_buffering off;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $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;
proxy_set_header X-Forwarded-Host $host;
gzip off;
location = /api/terminal/ws {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
location = /api/global/event/ws {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
location = /api/event/ws {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
location ~ ^/api/(event|global/event|notifications/stream|openchamber/events)$ {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Accept "text/event-stream";
proxy_set_header Cache-Control "no-cache";
proxy_buffering off;
proxy_cache off;
gzip off;
add_header X-Accel-Buffering "no" always;
add_header Cache-Control "no-cache, no-transform" always;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
location ~ ^/api/terminal/.+/stream$ {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Accept "text/event-stream";
proxy_set_header Cache-Control "no-cache";
proxy_buffering off;
proxy_cache off;
gzip off;
add_header X-Accel-Buffering "no" always;
add_header Cache-Control "no-cache, no-transform" always;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
location /api {
proxy_pass http://127.0.0.1:3000;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
location / {
proxy_pass http://127.0.0.1:3000;
}

예시: Nginx Proxy Manager

Advanced 탭 예시 보기
client_max_body_size 50M;
client_body_buffer_size 50M;
proxy_request_buffering off;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $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;
proxy_set_header X-Forwarded-Host $host;
gzip off;
location = /api/terminal/ws {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
proxy_connect_timeout 30s;
}
location = /api/global/event/ws {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
proxy_connect_timeout 30s;
}
location = /api/event/ws {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
proxy_connect_timeout 30s;
}
location = /api/event {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Accept "text/event-stream";
proxy_set_header Cache-Control "no-cache";
proxy_buffering off;
proxy_cache off;
gzip off;
add_header X-Accel-Buffering "no" always;
add_header Cache-Control "no-cache, no-transform" always;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
proxy_connect_timeout 30s;
}
location = /api/global/event {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Accept "text/event-stream";
proxy_set_header Cache-Control "no-cache";
proxy_buffering off;
proxy_cache off;
gzip off;
add_header X-Accel-Buffering "no" always;
add_header Cache-Control "no-cache, no-transform" always;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
proxy_connect_timeout 30s;
}
location = /api/notifications/stream {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Accept "text/event-stream";
proxy_set_header Cache-Control "no-cache";
proxy_buffering off;
proxy_cache off;
gzip off;
add_header X-Accel-Buffering "no" always;
add_header Cache-Control "no-cache, no-transform" always;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
proxy_connect_timeout 30s;
}
location = /api/openchamber/events {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Accept "text/event-stream";
proxy_set_header Cache-Control "no-cache";
proxy_buffering off;
proxy_cache off;
gzip off;
add_header X-Accel-Buffering "no" always;
add_header Cache-Control "no-cache, no-transform" always;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
proxy_connect_timeout 30s;
}
location ~ ^/api/terminal/.+/stream$ {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Accept "text/event-stream";
proxy_set_header Cache-Control "no-cache";
proxy_buffering off;
proxy_cache off;
gzip off;
add_header X-Accel-Buffering "no" always;
add_header Cache-Control "no-cache, no-transform" always;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
proxy_connect_timeout 30s;
}
location /api {
proxy_pass http://127.0.0.1:3000;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
proxy_connect_timeout 30s;
}
location / {
proxy_pass http://127.0.0.1:3000;
}

이 호스트에 대해 Nginx Proxy Manager에서 Websockets Support도 활성화하세요.

흔한 실패 징후

페이지는 로드되지만 메시지 전송이 실패함

  • 프록시에서 WebSocket이 활성화되지 않음
  • /api/event/ws 또는 /api/global/event/ws가 올바르게 전달되지 않음

알림 또는 실시간 상태가 업데이트되지 않음

  • SSE 경로 중 하나가 버퍼링되거나 캐시됨
  • X-Accel-Buffering "no"가 누락됨

파일 업로드가 실패함

  • client_max_body_size가 너무 작음

로컬에서는 모두 작동하지만 프록시 뒤에서만 깨짐

  • 프록시가 실시간 트래픽을 압축하고 버퍼링함
  • 프록시에 WebSocket 지원이 없음

예시: Caddy

예시 구성 보기
reverse_proxy 127.0.0.1:3000 {
# WebSocket support is automatic in Caddy
# Flush SSE responses immediately
flush_interval -1
# Pass through Host and proxy headers
header_up Host {host}
header_up X-Real-IP {remote_host}
header_up X-Forwarded-For {remote_host}
header_up X-Forwarded-Proto {scheme}
# Increase timeouts for long-lived streams
transport http {
read_timeout 3600s
write_timeout 3600s
}
}

Caddy는 WebSocket 업그레이드를 자동으로 처리합니다 — 추가 구성이 필요 없습니다. flush_interval -1 지시어는 SSE 청크가 버퍼링 없이 즉시 전달되도록 보장합니다.

CDN 및 이중 압축 경고

리버스 프록시 앞에 CDN(예: Cloudflare)을 두는 경우 이중 압축에 유의하세요:

  • OpenChamber는 HTTP 응답을 gzip으로 압축합니다(임계값 1KB).
  • Cloudflare와 다른 CDN도 기본적으로 응답을 압축합니다.
  • 이로 인해 이중 압축된 응답이나 잘못된 Content-Encoding 헤더가 발생할 수 있습니다.

이를 피하려면 계층에서 압축을 비활성화하세요:

  • Cloudflare: Rules → Compression → disable(또는 “Passthrough” 모드 사용).
  • Nginx: gzip off(위 예시에 이미 표시됨).
  • Caddy: 업스트림이 이미 압축된 콘텐츠를 보내면 Caddy는 기본적으로 다시 압축하지 않습니다.

SSE 스트리밍 경로는 OpenChamber에서 압축에서 제외되지만, CDN이 여전히 버퍼링할 수 있습니다. SSE 경로에서 버퍼링을 비활성화하는 방법은 CDN 문서를 확인하세요.

관련 항목