Adds translated docs for Spanish, Korean, Polish, Portuguese, Ukrainian, and Chinese Covers install, quickstart, themes, troubleshooting, tunnels, and reverse proxy guides Updates docs workflow, sidebar, and contributor documentation
348 lines
10 KiB
Plaintext
348 lines
10 KiB
Plaintext
---
|
|
title: 리버스 프록시
|
|
description: Nginx, Nginx Proxy Manager 또는 다른 리버스 프록시 뒤에서 OpenChamber를 올바르게 구성하세요.
|
|
---
|
|
|
|
# 리버스 프록시
|
|
|
|
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
|
|
|
|
<details>
|
|
<summary>예시 구성 보기</summary>
|
|
|
|
```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;
|
|
}
|
|
```
|
|
|
|
</details>
|
|
|
|
## 예시: Nginx Proxy Manager
|
|
|
|
<details>
|
|
<summary>Advanced 탭 예시 보기</summary>
|
|
|
|
```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;
|
|
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;
|
|
}
|
|
```
|
|
|
|
</details>
|
|
|
|
이 호스트에 대해 Nginx Proxy Manager에서 `Websockets Support`도 활성화하세요.
|
|
|
|
## 흔한 실패 징후
|
|
|
|
### 페이지는 로드되지만 메시지 전송이 실패함
|
|
|
|
- 프록시에서 WebSocket이 활성화되지 않음
|
|
- `/api/event/ws` 또는 `/api/global/event/ws`가 올바르게 전달되지 않음
|
|
|
|
### 알림 또는 실시간 상태가 업데이트되지 않음
|
|
|
|
- SSE 경로 중 하나가 버퍼링되거나 캐시됨
|
|
- `X-Accel-Buffering "no"`가 누락됨
|
|
|
|
### 파일 업로드가 실패함
|
|
|
|
- `client_max_body_size`가 너무 작음
|
|
|
|
### 로컬에서는 모두 작동하지만 프록시 뒤에서만 깨짐
|
|
|
|
- 프록시가 실시간 트래픽을 압축하고 버퍼링함
|
|
- 프록시에 WebSocket 지원이 없음
|
|
|
|
## 예시: Caddy
|
|
|
|
<details>
|
|
<summary>예시 구성 보기</summary>
|
|
|
|
```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
|
|
}
|
|
}
|
|
```
|
|
|
|
</details>
|
|
|
|
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 문서를 확인하세요.
|
|
|
|
## 관련 항목
|
|
|
|
- [터널](/ko/tunnels/)
|
|
- [문제 해결](/ko/troubleshooting/)
|