Nginx vs Caddy vs Traefik 리버스 프록시 선택 가이드
Nginx, Caddy, Traefik의 TLS 인증서 자동화, Docker 라우팅, 설정 복잡도를 비교합니다. 단일 VPS에서 여러 앱을 운영할 때 각 프록시의 장단점과 프로젝트 환경에 맞는 최적의 선택 기준을 정리했습니다.
Nginx 대 Caddy 대 Traefik: 요약
Nginx, Caddy, Traefik은 모두 리버스 프록시로서 동일한 역할을 수행합니다. 443 포트에서 대기하다가 각 요청의 호스트 이름을 읽어 VPS의 올바른 서비스로 전달합니다. 이 세 가지 중 무엇을 선택하든 하나의 공인 IP 주소 뒤에 4개의 자가 호스팅 앱을 배치할 수 있으며, 모두 충분히 빠르기 때문에 성능 병목은 프록시가 아닌 애플리케이션 자체에서 발생할 것입니다. 차이점은 TLS(전송 계층 보안) 인증서를 획득하는 방식과 새로운 앱을 추가할 때 필요한 설정의 복잡도에 있습니다. 또 다른 차이점은 일반적인 튜토리얼에서 다루지 않는 기능을 사용해야 할 때 드러납니다.
HTTPS 처리를 자동으로 수행하고 일반적인 웹 앱을 운영한다면 Caddy를 선택하십시오. 모든 서비스가 Docker Compose로 실행되고 몇 주마다 새로운 서비스를 추가한다면 Traefik을 선택하십시오. 이미 Nginx를 사용 중이거나 응답 캐싱, 클라이언트 인증서, 원시 TCP 포워딩이 필요하거나, 다시 작성하기 어려운 대규모 기존 설정이 있다면 Nginx를 선택하십시오.
각 도구는 어떻게 TLS 인증서를 발급받습니까?
대부분의 사용자에게 이 기준이 선택의 핵심이므로 여기서부터 시작합니다. 세 도구 모두 결과적으로 동일한 인증 기관에서 같은 인증서를 가져오지만, 그 과정은 서로 다릅니다.
Caddy는 호스트 이름을 지정하면 자동으로 인증서를 요청합니다. 사이트 주소로 app.example.com를 작성하면 Caddy는 ACME(automatic certificate management environment)를 통해 Let's Encrypt에 인증서를 요청합니다. 실패 시 ZeroSSL로 대체하며, 80번 포트에서 HTTP를 HTTPS로 리다이렉트하고 스스로 갱신합니다. 별도의 도구나 갱신 확인용 타이머가 필요하지 않습니다. 인증서는 caddy 사용자의 데이터 디렉터리인 /var/lib/caddy/.local/share/caddy(패키지 설치 시)에 저장되므로, 백업 경로에 이 경로를 추가하거나 재구축 후 새로 발급받아야 합니다. 공개되지 않은 호스트 이름의 경우 tls internal를 사용하면 Caddy 자체 로컬 인증 기관에서 서명합니다. 이는 Ubuntu에서 자체 서명 인증서 생성하기와 동일한 결과를 얻으면서 갱신까지 자동으로 처리됩니다.
Nginx에는 내장 ACME 클라이언트가 없습니다. Certbot이 인증서를 획득하며, --nginx 플러그인이 서버 블록을 다시 작성하여 443번 포트 리스너와 리다이렉트를 추가합니다. 갱신은 패키지 설치 시 생성되는 systemd 타이머를 통해 실행되므로, 두 개의 구성 요소와 두 가지 확인 지점이 존재합니다. systemctl list-timers | grep certbot으로 타이머 존재 여부를 확인하고, sudo certbot renew --dry-run로 갱신 경로가 정상인지 검증합니다. 단계별 절차는 Nginx와 함께하는 Ubuntu 24.04의 Certbot에 나와 있으며, 나열하기 힘들 정도로 많은 서브도메인이 있을 때는 동일한 도구로 DNS-01 챌린지를 통한 와일드카드 인증서를 발급받을 수 있습니다.
Traefik은 자체 ACME 클라이언트를 포함하고 있습니다. 정적 설정에서 인증서 리졸버를 하나 구성하면 모든 라우터가 이를 사용할 수 있습니다. 계정 키와 인증서를 포함한 모든 상태는 단일 acme.json 파일에 저장됩니다. Traefik은 소유자 외에 다른 사용자가 해당 파일을 읽을 수 있으면 사용을 거부하며, 리졸버를 중단하기 전에 다음과 같은 메시지를 출력합니다.
The ACME resolver "le" is skipped from the resolvers list because: unable to get ACME account: permissions 660 for /letsencrypt/acme.json are too open, please use 600디렉터리를 마운트하고 Traefik이 직접 파일을 생성하게 하십시오. touch로 파일을 먼저 생성하면 사용자의 umask를 상속받게 되는데, 이것이 대부분의 사용자가 해당 오류를 겪는 원인입니다.
세 도구 모두에 공통으로 적용되는 사항이 하나 있습니다. HTTP-01 챌린지를 수행하려면 인증 기관이 서버에 다시 연결해야 하므로 인터넷에서 80번 포트에 접근할 수 있어야 합니다. 443번 포트만 열려 있으면 DNS 오류처럼 보이는 방식으로 발급이 실패합니다.
세 가지 설정으로 구현하는 동일한 두 앱 라우팅 작업
작업 내용: app.example.com은 127.0.0.1:8080의 서비스로, files.example.com는 127.0.0.1:8081의 서비스로 연결하며, 둘 다 HTTPS를 사용합니다. 각 프록시의 전체 설정은 다음과 같으며, 이를 통해 장황함의 차이를 주장하는 대신 직접 확인할 수 있습니다.
Nginx
# /etc/nginx/sites-available/app.example.com
server {
listen 80;
server_name app.example.com;
location / {
proxy_pass http://127.0.0.1:8080;
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;
}
}그런 다음 링크를 생성하고, 테스트하고, 리로드한 뒤 인증서를 추가합니다.
sudo ln -s /etc/nginx/sites-available/app.example.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
sudo certbot --nginx -d app.example.comnginx -t를 실행하여 syntax is ok와 test is successful을 출력하는 것은 모든 리로드 전에 수행해야 할 확인 작업입니다. 두 번째 앱은 호스트 이름과 포트만 변경된 동일한 블록입니다. proxy_set_header 줄은 장식이 아닙니다. proxy_pass이 주소를 지정할 때 Nginx는 기본적으로 Host: 127.0.0.1:8080를 업스트림으로 전송하므로, Host 헤더를 기반으로 절대 URL을 생성하는 앱은 사용자를 localhost로 보낼 것입니다. 이 네 가지 헤더 각각의 용도와 proxy_pass의 후행 슬래시가 앱이 수신하는 경로를 어떻게 조용히 변경하는지에 대해서는 Nginx 서버 블록에 대한 이 가이드에서 지시어별로 자세히 다룹니다.
Caddy
app.example.com {
reverse_proxy 127.0.0.1:8080
}
files.example.com {
reverse_proxy 127.0.0.1:8081
}sudo caddy validate --config /etc/caddy/Caddyfile
sudo systemctl reload caddy이것이 파일의 전부입니다. reverse_proxy은 X-Forwarded-For, X-Forwarded-Proto, X-Forwarded-Host를 스스로 설정하며, 기본적으로 클라이언트가 해당 헤더에 보낸 내용을 무시하므로 요청이 백엔드에 출처를 속일 수 없습니다. 인증서, 80번 포트 리다이렉트, 갱신은 모두 두 사이트 주소로부터 자동으로 처리됩니다. 파일 내에 이를 요구하는 다른 설정은 없습니다.
Traefik
Traefik은 라우팅을 수행하기 전에 정적 설정이 필요합니다. 2026년 8월 기준 최신 이미지 태그를 사용한 Compose 서비스 설정은 다음과 같습니다.
services:
traefik:
image: traefik:v3.7
command:
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--certificatesresolvers.le.acme.email=you@example.com"
- "--certificatesresolvers.le.acme.storage=/letsencrypt/acme.json"
- "--certificatesresolvers.le.acme.httpchallenge.entrypoint=web"
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./letsencrypt:/letsencrypt각 애플리케이션은 자체 compose 파일의 레이블을 통해 고유한 라우팅을 수행합니다.
labels:
- "traefik.enable=true"
- "traefik.http.routers.app.rule=Host(`app.example.com`)"
- "traefik.http.routers.app.entrypoints=websecure"
- "traefik.http.routers.app.tls.certresolver=le"
- "traefik.http.services.app.loadbalancer.server.port=8080"loadbalancer.server.port는 컨테이너 내부 포트이며, 게시된 포트가 아닙니다. Traefik이 공유 Docker 네트워크를 통해 컨테이너에 도달하기 때문입니다. 앱에는 ports: 줄이 전혀 필요 없으며, 이것이 진정한 장점입니다. 오직 Traefik만 외부로 게시됩니다. 공유 네트워크와 리다이렉트 미들웨어를 포함한 전체 빌드 과정은 Traefik과 Docker Compose를 이용한 다중 앱 라우팅에서 확인할 수 있습니다.
추가 애플리케이션마다 어느 정도의 설정 비용이 발생합니까?
The data behind this chart
[
{
"tool": "Nginx",
"proxy_setup_lines": 0,
"lines_per_app": 11
},
{
"tool": "Caddy",
"proxy_setup_lines": 0,
"lines_per_app": 3
},
{
"tool": "Traefik",
"proxy_setup_lines": 17,
"lines_per_app": 5
}
]위 블록을 기준으로 계산합니다. Nginx 서버 블록은 공백을 제외하고 11 줄이며, 호스트 이름마다 이를 다시 작성해야 합니다. Caddy 사이트 블록은 3 줄입니다. Traefik은 단일 요청을 처리하기 전에 17 줄의 정적 설정을 요구하며, 그 이후에는 앱당 5 줄의 레이블이 필요합니다.
승자가 아닌 트레이드오프를 읽어야 합니다. Traefik은 첫 번째 앱을 추가하기 전까지는 비용이 가장 많이 들지만, 그 이후에는 앱당 비용이 가장 적게 들며, 두 총합은 약 세 번째 사이트 지점에서 만납니다. 그 이하의 규모에서는 정적 설정이 불필요한 오버헤드가 됩니다. 그 이상의 규모에서는 라우팅 설정이 서비스와 함께 위치하므로 레이블 방식이 훨씬 효율적입니다. 서비스를 삭제하면 라우팅 설정도 함께 사라지는데, 이는 중앙 집중식 설정 파일이 가진 단점인 '수개월 전에 삭제된 앱의 오래된 서버 블록' 문제를 방지합니다.
줄 수만 따지면 Nginx가 유리해 보일 수 있습니다. 하지만 각 블록마다 심볼릭 링크, nginx -t, 리로드, certbot 실행이 필요합니다. 반면 Caddy는 리로드 한 번이면 충분하며, Traefik은 별도의 명령조차 필요하지 않습니다. 세 가지 방식 모두 활성 연결을 끊지 않고 리로드할 수 있습니다. 차이점은 새벽 1시에 기억해야 할 개별 단계의 수입니다.
컨테이너 정보를 파악하는 도구는 무엇입니까?
Traefik은 Docker 소켓을 감시하며 컨테이너가 시작되거나 중지될 때 컨테이너 레이블을 기반으로 라우터를 생성합니다. 이 문서에서 다루는 다른 도구들은 이러한 기능을 제공하지 않습니다. Nginx와 Caddy는 새로운 컨테이너가 나타날 때마다 설정을 수정하고 다시 불러와야 하며, 프록시가 접근할 수 있는 주소(루프백에 게시된 포트 또는 프록시가 연결된 공유 Docker 네트워크)가 필요합니다.
이 기능에는 대가가 따르며, 이를 명확히 인지해야 합니다. Traefik은 /var/run/docker.sock을 읽습니다. 해당 소켓에 접근할 수 있는 사용자는 호스트 파일 시스템이 마운트된 컨테이너를 시작할 수 있으며, 이는 곧 호스트의 root 권한을 획득하는 것과 같습니다. 읽기 전용으로 마운트하면 위험을 줄일 수는 있지만 완전히 제거할 수는 없습니다. 위협 모델에서 이 문제가 중요하다면, Traefik이 필요한 컨테이너 목록 엔드포인트만 노출하도록 중간에 소켓 프록시를 배치하십시오.
Caddy도 커뮤니티 플러그인을 통해 레이블 기반의 서비스 탐색을 수행할 수 있습니다. 하지만 Caddy 플러그인은 바이너리에 포함되어 컴파일되므로, xcaddy를 사용하여 커스텀 바이너리나 커스텀 이미지를 직접 빌드해야 하며, 이후 해당 빌드와 업데이트는 사용자가 직접 관리해야 합니다. 서비스가 3~4개 정도라면 Caddyfile을 수정하는 편이 작업량이 더 적습니다.
Websocket과 스트리밍: 무엇이, 왜 중단되는가
Nginx는 추가 설정이 필요합니다. Websocket 연결은 Upgrade: websocket을 포함한 HTTP 요청으로 시작되는데, Nginx는 명시적으로 지시하지 않으면 hop-by-hop 헤더를 업스트림으로 전달하지 않기 때문입니다.
# /etc/nginx/conf.d/upgrade-map.conf
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}그다음, location 블록 내부에 다음 세 줄을 반드시 포함해야 합니다.
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;이 설정을 누락하면 브라우저 콘솔에는 WebSocket connection to 'wss://app.example.com/ws' failed가 출력되고, 백엔드 로그에는 일반적인 GET 요청만 기록됩니다. map이 존재하는 이유는 하드코딩된 Connection: upgrade가 close라고 명시해야 할 일반 요청을 포함한 모든 요청에 전송되기 때문입니다.
Nginx의 기본 설정 중 두 가지가 더 문제가 됩니다. proxy_read_timeout은 60초로 설정되어 있으며 업그레이드 이후 터널에도 적용되므로, 1분 동안 트래픽이 없는 Websocket은 프록시에 의해 종료됩니다. 또한, 해당 location에 proxy_buffering off;을 설정하지 않으면 서버 전송 이벤트(SSE)가 늦게 도착하거나 한꺼번에 몰려서 들어옵니다. 이는 페이지가 응답을 기다리는 동안 Nginx가 응답을 버퍼에 보관하기 때문입니다.
Caddy는 별도의 지시어 없이도 업그레이드를 수행하고 연결을 양방향 터널로 전환합니다. 또한 응답이 text/event-stream이거나 길이를 알 수 없는 경우 즉시 플러시(flush)하므로 스트리밍이 별도의 설정 없이도 작동합니다. Traefik은 업그레이드를 그대로 통과시키며, 사용자가 직접 buffering 미들웨어를 추가하지 않는 한 응답을 버퍼링하지 않습니다. 채팅, 웹 터미널, 로그 테일링, 실시간 대시보드 등을 서비스한다면, 작성하고 디버깅해야 할 설정의 양에서 큰 차이가 발생합니다.
Websocket과 SSE를 포함한 전체 Nginx 서버 블록
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 80;
server_name app.example.com;
client_max_body_size 64m;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
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 Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_read_timeout 3600s;
proxy_buffering off;
}
}map은 server 내부가 아니라 http 컨텍스트에 위치해야 하므로, /etc/nginx/conf.d/ 아래 별도의 파일로 유지하십시오. 버퍼링은 일반적인 응답에서 Nginx가 백엔드 워커를 조기에 해제할 수 있게 해주므로, proxy_buffering는 스트리밍이 발생하는 location에서만 끄십시오. Certbot을 실행하면 이 블록을 다시 작성하므로, 실행 후 파일을 다시 확인하십시오.
흔치 않은 요구 사항이 발생하면 어떻게 해야 합니까?
이 지점에서 Nginx는 추가적인 설정이 필요합니다.
- 클라이언트 인증서: mTLS(mutual TLS)라고도 하며, 클라이언트도 인증서를 제시해야 합니다. Nginx는 서버 블록 내에
ssl_client_certificate /etc/ssl/ca.pem;와ssl_verify_client on;이 필요합니다. Caddy는tls내부에client_auth블록을 사용합니다. Traefik 레이블로는 이를 표현할 수 없으므로, 파일 프로바이더에서 TLS 옵션을 정의하고traefik.http.routers.app.tls.options=mtls@file를 사용하여 라우터에 지정해야 합니다. 모든 설정을 레이블로 처리하는 방식은 이 기능을 사용하는 순간 예외가 발생합니다. - 대용량 업로드: Nginx는 기본적으로 요청 본문 크기를 1 MB로 제한합니다. 더 큰 파일을 업로드하면
413 Request Entity Too Large오류가 발생하며, 오류 로그에는client intended to send too large body가 기록됩니다. 이때client_max_body_size값을 높여야 합니다. Caddy와 Traefik은 기본적으로 본문 크기 제한이 없으므로, 요청이 애플리케이션까지 전달되어 애플리케이션 자체 설정에 따라 제한 여부가 결정됩니다. - 응답 캐싱: Nginx는 성숙한
proxy_cache기능을 제공합니다. Caddy는 플러그인을 컴파일하여 추가해야 합니다. Traefik 오픈 소스 빌드에는 HTTP 캐시 기능이 전혀 없으며, 이는 모든 프록시가 캐싱을 지원할 것이라 예상하는 사용자들에게 놀라운 점입니다. - Raw TCP 또는 UDP: 데이터베이스 포트나 게임 서버를 위한 설정입니다. Nginx는
stream모듈을 사용합니다. Traefik은 자체 엔트리포인트에서 TCP 및 UDP 라우터를 지원합니다. Caddy는 별도의 플러그인이 필요하므로 커스텀 빌드가 요구됩니다. - 프록시 뒤에 이미 존재하는 웹 서버: 서비스가 일반적인 PHP 애플리케이션인 경우, Ubuntu 24.04의 LAMP 스택에는 이미 Apache가 포함되어 있습니다. 이 앞에 프록시를 배치하면 헤더 설정과 URL 재작성을 수행하는 곳이 두 곳으로 늘어납니다. 어느 쪽에서 TLS를 종료할지 결정한 뒤, 나머지 하나는 루프백에 바인딩된 일반 HTTP 상태로 유지하십시오.
이 선택에 따르는 방화벽 함정
리버스 프록시를 사용하는 목적은 80번과 443번 포트만 개방하는 것입니다. 하지만 Docker는 이를 조용히 무력화합니다. -p 8080:80를 사용하여 포트를 게시하면 nat 테이블에 DNAT 규칙이 작성됩니다. 이 규칙은 ufw가 관리하는 INPUT 규칙보다 먼저 평가되므로, ufw deny 8080은 이를 차단하지 못합니다. 결과적으로 귀하가 공들여 설정한 프록시 옆에 애플리케이션이 그대로 인터넷에 노출됩니다. 게시된 포트를 127.0.0.1:8080:80을 사용하여 루프백 주소에 바인딩하거나, ports:을 완전히 제거하고 위에서 언급한 Traefik 예시처럼 Docker 네트워크를 통해 프록시가 컨테이너에 접근하도록 구성하십시오. 이 메커니즘과 해결 방법은 Docker 게시 포트가 ufw를 우회하는 이유에서 확인할 수 있습니다.
VPS 내부에서 확인하면 항상 성공하므로, 반드시 VPS가 아닌 다른 기기에서 테스트하십시오:
curl --max-time 5 http://your.server.address:8080원하는 결과는 Connection refused 또는 타임아웃입니다. HTTP 응답이 돌아온다면 프록시를 거치지 않고도 애플리케이션에 접근할 수 있다는 뜻이며, 위에서 설정한 모든 구성은 무용지물입니다.
어떤 프록시를 선택해야 할까요?
대부분 정적 사이트이며 앱을 한두 개 운영하는 경우: Caddy. 자동 HTTPS 기능은 가장 번거로운 반복 작업을 제거해 줍니다. 설정 파일은 한 화면에 들어올 정도로 짧으며, 정적 사이트는 동일한 사이트 블록 내에 root 한 줄과 file_server 한 줄이면 충분합니다. 단점은 문제가 발생했을 때 참고할 수 있는 복사-붙여넣기용 해결책이 다른 도구보다 적다는 점입니다.
계속 서비스를 추가하는 docker-compose 기반 홈랩: Traefik. 서비스가 3개를 넘어가면 중앙 설정 파일을 수정하는 것보다 레이블(labels)을 사용하는 것이 훨씬 효율적이며, 서비스를 삭제하면 경로 설정도 함께 제거됩니다. 처음 설정할 때는 entrypoints, routers, services, middlewares와 같은 새로운 용어를 익혀야 하므로 오후 한나절 정도 시간을 할애하십시오. 레이블에 오타가 있으면 보통 앱이 실행되지 않는 것이 아니라 Traefik에서 404 오류가 발생하므로, 앱이 고장 났다고 판단하기 전에 docker logs traefik에서 구문 분석 오류를 먼저 확인하십시오.
기존 Nginx 설정이 있거나 위 목록의 요구 사항이 있는 경우: Nginx. 응답 캐싱과 클라이언트 인증서에 대한 해결책이 이미 마련되어 있으며, 거의 모든 타사 가이드가 Nginx를 기준으로 작성되어 있습니다. 단점은 인증서와 웹소켓 지원을 직접 설정해야 한다는 점입니다.
어떤 것을 선택하든 한 가지 규칙은 동일합니다. 공용 인터페이스에서 수신 대기하는 프로세스는 단 하나여야 하며, 나머지 모든 서비스는 루프백(loopback)이나 사설 Docker 네트워크에서 수신 대기해야 합니다.
FAQ
단일 VPS에서 Docker 애플리케이션 몇 개를 운영할 때 어떤 리버스 프록시가 가장 좋은가요?
가끔씩 서비스를 추가하는 3~4개 정도의 환경이라면 Traefik이 유리합니다. 각 애플리케이션이 자체 라우팅 레이블을 포함하므로 중앙 설정 파일을 수정할 필요가 없기 때문입니다. 서비스가 안정적이고 단순히 HTTPS 설정 문제를 해결하고 싶다면 학습 곡선이 낮고 오류 발생 가능성이 적은 Caddy를 추천합니다. Nginx는 이미 익숙하거나 응답 캐싱, 일반 TCP 리스너 등 다른 도구에는 없는 기능이 필요할 때 선택하십시오.
Caddy는 정말로 인증서 설정이 전혀 필요 없나요?
일반적인 경우에는 그렇습니다. 공용 호스트 이름을 사이트 주소로 지정하는 것이 설정의 전부입니다. Caddy는 ACME를 통해 인증서를 요청하고, 80번 포트에서 리다이렉트를 처리하며, 만료 전에 자동으로 갱신합니다. 다만 두 가지 조건이 충족되어야 합니다. HTTP-01 챌린지를 위해 80번 포트가 인터넷에서 접근 가능해야 하며, 인증 기관이 이름을 확인하고 연결을 시도하므로 호스트 이름의 DNS A 또는 AAAA 레코드가 이미 해당 VPS를 가리키고 있어야 합니다.
같은 VPS에서 Nginx와 Traefik을 동시에 실행할 수 있나요?
같은 포트에서는 불가능합니다. 먼저 실행된 프록시가 포트를 점유하므로 나중에 실행되는 프록시는 바인딩에 실패합니다. Nginx는 bind() to 0.0.0.0:443 failed (98: Address already in use) 오류를 발생시키며, Traefik도 유사한 바인딩 오류를 로그에 남기고 종료됩니다. 하나의 프록시만 80번과 443번 포트를 사용하게 하고, 나머지 서비스는 그 뒤에 배치하십시오. 마이그레이션 중이라면 호스트 이름을 하나씩 옮기십시오. 마지막 사이트가 이전될 때까지 전면 프록시가 루프백 포트의 기존 프록시로 요청을 전달하게 하면 됩니다.
Nginx 뒤에서 웹소켓 연결이 60초마다 끊기는 이유는 무엇인가요?
proxy_read_timeout의 기본값은 60초이며, 업그레이드가 완료된 터널에도 이 설정이 적용됩니다. 따라서 1분 동안 트래픽이 없으면 애플리케이션이 아닌 프록시가 연결을 종료합니다. 해당 location 블록에서 proxy_read_timeout 3600s; 값을 높이거나, 애플리케이션에서 30초마다 핑 프레임을 보내도록 설정하십시오. Caddy와 Traefik은 1분 타이머로 유휴 업그레이드 연결을 종료하지 않으므로, 동일한 애플리케이션이라도 Nginx 뒤에서는 불안정하게 보일 수 있습니다.