SSD Nodes Learn 🎉 VPS $5.50/월부터
가이드 Matt Connor작성자 Matt Connor · 업데이트됨 2026-08-13

Nginx vs Caddy vs Traefik 리버스 프록시 선택 가이드

하나의 VPS와 공인 IP에서 여러 앱을 운영할 때 적합한 리버스 프록시를 비교합니다. TLS 인증서 자동화, Docker 컨테이너 라우팅, 설정 복잡도 및 WebSocket 지원 여부를 기준으로 프로젝트에 가장 효율적인 도구를 선택하는 방법을 정리했습니다.

Nginx 대 Caddy 대 Traefik: 요약

Nginx, Caddy, Traefik은 모두 리버스 프록시로서 동일한 역할을 수행합니다. 443 포트에서 대기하다가 각 요청의 호스트 이름을 읽어 VPS의 올바른 서비스로 전달합니다. 이 세 가지 도구 중 무엇을 사용하든 하나의 공인 IP 주소 뒤에 4개의 자체 호스팅 앱을 배치할 수 있으며, 모두 충분히 빠르기 때문에 성능 병목은 프록시가 아닌 애플리케이션 자체에서 발생하게 됩니다. 차이점은 TLS(Transport Layer Security) 인증서를 획득하는 방식과 새로운 앱을 추가할 때 필요한 설정의 복잡도에 있습니다. 또 다른 차이점은 일반적인 튜토리얼에서 다루지 않는 고급 기능이 필요해지는 시점에 드러납니다.

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로 갱신 경로가 정상 작동하는지 검증합니다. 단계별 절차는 Ubuntu 24.04 Nginx에서 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.com127.0.0.1:8080의 서비스로, files.example.com127.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.com

nginx -t를 실행하여 syntax is oktest is successful을 출력하는 것은 모든 리로드 전에 수행해야 할 점검 사항입니다. 두 번째 앱은 호스트 이름과 포트만 변경된 동일한 블록입니다. proxy_set_header 라인은 장식이 아닙니다. proxy_pass이 주소를 지정할 때 Nginx는 기본적으로 Host: 127.0.0.1:8080를 업스트림으로 전송하므로, Host 헤더를 기반으로 절대 URL을 생성하는 앱은 사용자를 localhost로 보내게 됩니다.

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_proxyX-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)을 통해 라우팅을 수행합니다.

    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는 컨테이너 내부 포트이며, 게시된(published) 포트가 아닙니다. Traefik은 공유 Docker 네트워크를 통해 컨테이너에 도달하기 때문입니다. 앱에는 ports: 라인이 전혀 필요 없으며, 이것이 진정한 장점입니다. 오직 Traefik만 포트를 게시합니다. 공유 네트워크와 리다이렉트 미들웨어를 포함한 전체 빌드 구성은 Traefik과 Docker Compose로 여러 앱 라우팅하기에서 확인할 수 있습니다.

추가 애플리케이션마다 설정 비용은 얼마나 드는가?

ChartNon-blank config lines for the same two-app routing job
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을 수정하는 편이 작업량이 더 적습니다.

웹소켓과 스트리밍: 무엇이, 왜 깨지는가

Nginx는 추가 설정이 필요한 대상입니다. 웹소켓 연결은 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분 동안 트래픽이 없는 웹소켓은 프록시에 의해 강제로 종료됩니다. 또한 서버 전송 이벤트(SSE)는 응답이 버퍼에 머물러 있어 페이지가 응답을 기다리는 동안 지연되거나 한꺼번에 몰려서 도착합니다. 이를 해결하려면 해당 location 블록에 proxy_buffering off; 설정을 적용해야 합니다.

Caddy는 별도의 지시어 없이도 자동으로 업그레이드를 수행하고 양방향 터널로 연결을 전환합니다. 또한 응답이 text/event-stream이거나 길이를 알 수 없는 경우 즉시 데이터를 전송(flush)하므로 스트리밍이 별도의 설정 없이도 정상 작동합니다. Traefik 역시 업그레이드 요청을 그대로 통과시키며, buffering 미들웨어를 직접 추가하지 않는 한 응답을 버퍼링하지 않습니다. 채팅, 웹 터미널, 로그 테일링, 실시간 대시보드 등을 서비스한다면, 이러한 차이가 설정 및 디버깅 작업량에 큰 영향을 미칩니다.

웹소켓과 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;
    }
}

mapserver 내부가 아닌 http 컨텍스트에 위치해야 하므로, /etc/nginx/conf.d/ 경로 아래 별도의 파일로 관리하십시오. proxy_buffering 설정은 일반적인 응답 시 Nginx가 백엔드 워커를 조기에 해제할 수 있도록 돕는 역할을 하므로, 스트리밍이 필요한 location 블록에서만 off로 설정하십시오. 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 재작성(rewrite)을 수행하는 곳이 두 곳으로 늘어납니다. 어느 쪽에서 TLS를 종료할지 결정한 뒤, 다른 하나는 루프백(loopback)에 바인딩된 일반 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 내부에서 확인하면 항상 성공하므로, 반드시 외부 장비에서 테스트하십시오.

curl --max-time 5 http://your.server.address:8080

Connection refused 또는 타임아웃이 발생해야 정상입니다. HTTP 응답이 돌아온다면 프록시를 거치지 않고 애플리케이션에 직접 접근할 수 있다는 뜻이며, 앞서 설정한 모든 구성은 무용지물입니다.

어떤 프록시를 선택해야 할까요?

정적 사이트 위주에 애플리케이션을 한두 개 운영한다면: Caddy. 자동 HTTPS 기능은 가장 번거로운 반복 작업을 제거해 줍니다. 설정 파일은 한 화면에 들어올 정도로 짧으며, 정적 사이트 설정은 동일한 사이트 블록 내에서 root 한 줄과 file_server 한 줄이면 충분합니다. 단점은 문제가 발생했을 때 참고할 수 있는 복사-붙여넣기용 해결책이 다른 도구보다 적다는 점입니다.

계속 서비스를 추가하는 docker-compose 기반 홈랩이라면: Traefik. 서비스가 3개를 넘어가면 중앙 설정 파일을 수정하는 것보다 레이블(label)을 사용하는 것이 훨씬 효율적이며, 서비스를 삭제하면 라우팅 설정도 함께 제거됩니다. 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 뒤에서는 불안정하게 보일 수 있습니다.