Caddy 웹서버의 자동 HTTPS 및 리버스 프록시 아키텍처를 추상적으로 묘사한 모던 그래픽 일러스트
|

도대체 Caddy가 뭐길래 Nginx를 대체할까? Caddy 웹서버 핵심 개념부터 실전 사용법까지 완벽 정리

Caddy 웹서버란 무엇인가

웹 애플리케이션(React, Node.js, Django 등)을 다 만들고 나면 배포 단계에서 흔히 막히는 지점이 나옵니다. 도메인을 연결하고 HTTPS를 적용하려면 기존에는 Nginx를 설치하고, Let’s Encrypt를 연동하고, Certbot으로 인증서를 발급받아 주기적으로 갱신해 주는 파이프라인을 직접 구축해야 했습니다.

Caddy는 이 과정을 텍스트 파일 몇 줄로 줄여주는, Go 언어로 작성된 웹 서버입니다. Caddy 공식 홈페이지에 설명된 대로 설정의 복잡함을 낮추면서 성능과 편의성을 함께 챙긴 덕분에, 2026년 현재 Nginx의 대안으로 자주 언급됩니다. 이 글은 SSL 설정과 Nginx 설정 때문에 애먹던 개발자를 대상으로, Caddy가 정확히 어떤 원리로 작동하고 실무에서 Nginx 대신 어떻게 쓰는지를 공식 문서 링크와 함께 정리한 것입니다. 핵심만 먼저 말하면, Caddy는 별도의 수동 설정 없이 파일 한 줄만으로 SSL 인증서 발급, 리버스 프록시, 정적 파일 서빙을 처리하는 자동 HTTPS 지원 웹 서버입니다.

Caddy가 해결하는 문제

인프라 지식이 많지 않은 개발자에게는 ‘웹 서버’, ‘리버스 프록시’ 같은 용어가 추상적으로 느껴지기 쉽습니다. Caddy가 실제로 하는 일을 세 가지로 나눠 설명하겠습니다.

웹 서버 역할: 요청을 받아 파일을 돌려준다

사용자가 브라우저 주소창에 https://example.com을 입력하면, 그 요청을 서버에서 가장 먼저 받는 것이 Caddy입니다. 사용자가 요청한 경로를 확인해 서버 디스크에 있는 웹 페이지 파일(HTML, CSS, 이미지 등)을 찾아 브라우저로 돌려줍니다.

자동 HTTPS: 인증서를 스스로 발급하고 갱신한다

오늘날 대부분의 웹사이트에서 HTTPS(보안 연결)는 선택이 아니라 필수입니다. Caddy는 Caddy 공식 문서: Automatic HTTPS에 나온 대로 Let’s Encrypt 또는 ZeroSSL과 백그라운드에서 통신해 무료 SSL 인증서를 스스로 발급받고 3개월마다 갱신합니다. 인증서 만료일마다 갱신 명령어를 치거나 크론탭(crontab) 스크립트를 짤 필요가 없습니다.

리버스 프록시 역할: 외부 포트와 내부 포트를 연결한다

백엔드를 개발하면 보통 Node.js는 3000번, Python Django는 8000번 같은 내부 포트에서 프로그램이 돌아갑니다. 하지만 외부 사용자는 80번(HTTP)이나 443번(HTTPS) 포트로만 접속할 수 있습니다. Caddy는 443번 포트로 들어온 요청을 서버 내부의 3000번이나 8000번 포트로 전달해 주는 역할을 합니다.

Caddy와 Nginx 비교

인프라 분야에서 오래 쓰여 온 Nginx와, 비교적 최근 주목받는 Caddy의 차이를 표로 정리했습니다.

비교 항목 Nginx Caddy 웹서버
HTTPS (SSL) 설정 Certbot 등 외부 도구 설치 및 갱신 주기(cron) 수동 세팅 필요 완전 자동화 (설정 없이 기본 탑재)
설정 파일 난이도 구조가 다소 복잡하고 문법이 길어 가독성이 낮음 (약 수십 줄 필요) Caddyfile 형식으로 단 몇 줄이면 세팅 종료
서버 아키텍처 다양한 모듈과 런타임 라이브러리 의존성 존재 의존성 없는 단일 Go 정적 바이너리 파일
HTTP/3 지원 별도 컴파일 및 패치가 필요하거나 설정이 까다로움 기본적으로 활성화되어 제공

Caddy 설치 및 기본 명령어

Caddy는 다양한 운영체제와 배포 방식을 지원합니다. 세부 사항은 Caddy 공식 설치 가이드에서 확인할 수 있으며, 여기서는 Debian/Ubuntu Linux 계열 서버를 기준으로 설명합니다.

설치 패키지 추가 및 다운로드

안정적인 최신 패키지를 받기 위해 Caddy 공식 리포지토리를 시스템에 등록하고 패키지를 설치합니다.

sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl

curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | 
  sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg

curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | 
  sudo tee /etc/apt/sources.list.d/caddy-stable.list

sudo apt update
sudo apt install caddy

서비스 구동 및 제어 명령어

설치가 끝나면 Caddy 서비스가 시스템 데몬(systemd)으로 자동 등록됩니다. Caddy Getting Started 가이드를 참고하면, CLI를 통해 가동 상태를 쉽게 제어할 수 있습니다.

sudo systemctl start caddy

sudo systemctl status caddy

caddy reload --config /etc/caddy/Caddyfile

자주 쓰는 Caddyfile 패턴 세 가지

Caddy는 /etc/caddy/Caddyfile 설정 파일을 수정해 원하는 인프라 구성을 만듭니다. 더 많은 활용 예시는 Caddyfile 공통 패턴 문서에서 확인할 수 있습니다.

1) 리버스 프록시(Reverse Proxy) 패턴

외부 사용자가 example.com 도메인으로 들어오면, 컴퓨터 내부 8080번 포트에서 돌고 있는 백엔드 앱으로 연결하는 구성입니다. 리버스 프록시 퀵스타트 가이드의 기본 형식을 따르고 있습니다. 이 2줄만 적으면 도메인 연결과 SSL(HTTPS) 인증서 발급이 동시에 처리됩니다.

example.com {
    reverse_proxy localhost:8080
}

2) 정적 파일 서빙(Static File Server) 패턴

회사 랜딩 페이지나 React 빌드 결과물(index.html, JS, 이미지 등)을 다이렉트로 호스팅할 때 사용하는 방법입니다.

static.example.com {
    # 정적 파일이 위치한 디렉토리 경로 지정
    root * /var/www/html

    # zstd 및 gzip 압축 인코딩 전송 활성화
    encode zstd gzip

    # 정적 파일 서버 기동
    file_server
}

3) SPA(Single Page Application) 배포 및 API 분기 패턴

React, Vue 등의 프론트엔드 라우팅 구조와 API 통신 경로를 단일 도메인에서 나눠 배포할 때 사용하는 구성입니다.

app.example.com {
    # 1. API 요청(/api/*)은 백엔드 포트로 전달
    handle /api/* {
        reverse_proxy localhost:8080
    }

    # 2. 그 외 모든 일반 요청은 프론트엔드 정적 파일 대응
    handle {
        root * /var/www/frontend

        # 파일이 없을 경우 index.html로 넘겨 브라우저가 라우팅을 맡도록 함 (SPA 대응)
        try_files {path} /index.html
        file_server
    }
}

프로덕션 운영을 위한 보안 조치와 로깅

Caddy가 많은 부분을 자동으로 처리해 주더라도, 서비스를 실제로 운영하는 단계에서는 보안성과 가시성을 위해 다음 설정을 챙겨야 합니다.

공통 보안 헤더 설정(스니펫 기법)

반복되는 보안 설정을 스니펫으로 묶어 여러 가상 호스트에 주입해 줍니다. 클릭재킹 방지 및 원치 않는 MIME 타입 분석 회피를 설정합니다.

(security-headers) {
    header {
        # HSTS 강제 적용 (1년간 HTTPS 유지)
        Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"

        # 브라우저 오동작 및 악성 스크립트 실행 차단 (nosniff)
        X-Content-Type-Options nosniff

        # Clickjacking 방지 (동일 도메인에서만 iframe 허용)
        X-Frame-Options SAMEORIGIN

        # HTTP 헤더에서 Caddy 서버 정보 숨기기
        -Server
    }
}

api.example.com {
    import security-headers
    reverse_proxy localhost:8080
}

구조화된 접속 로그 남기기

비정상적인 트래픽을 추적하고 웹로그를 분석하기 위해 JSON 형식의 구조화된 로그 파일을 주기적으로 자동 분할(Rotation)하여 저장하는 설정입니다. 세부 속성은 log 지시어 명세 문서글로벌 옵션 설정을 참고했습니다.

example.com {
    # 로그 파일 설정 지시어
    log {
        # 로그 저장소 지정 및 로테이션 설정
        output file /var/log/caddy/access.log {
            roll_size 50MiB      # 파일 크기 50MB 도달 시 새로운 파일 분할
            roll_keep 10         # 백업 파일은 최대 10개까지만 보관
            roll_keep_for 720h   # 30일(720시간)이 지난 로그는 자동 폐기
        }
        format json
    }

    # reverse_proxy 지시어 공식 가이드: https://caddyserver.com/docs/caddyfile/directives/reverse_proxy
    reverse_proxy localhost:8080
}

추가적으로, 프로덕션 환경에서 트래픽 제한(Rate Limiting)이 필요할 경우 공식 빌드에는 포함되어 있지 않으므로 mholt/caddy-ratelimit GitHub 저장소의 서드파티 플러그인을 빌드에 포함해 이용하는 것을 추천합니다.

정리

Caddy는 소규모 토이 프로젝트에서만 쓰는 서버가 아닙니다. 자동 HTTPS, 사람이 읽기 쉬운 설정 문법(Caddyfile), 의존성이 거의 없는 단일 바이너리 구조를 갖추고 있어 대규모 프로덕션 환경과 클라우드 네이티브 환경에서도 실제 선택지로 쓰입니다.

  • SSL 발급 과정을 직접 관리하지 않아도 됩니다: 사이드 프로젝트나 신규 서비스를 준비 중이라면 Nginx와 Certbot 조합 대신 Caddy를 설치해 보세요. 도메인 세팅과 HTTPS 구동을 몇 분 안에 끝낼 수 있습니다.
  • 설정 파일 유지보수가 쉬워집니다: Nginx의 복잡한 config 문법을 찾아보느라 시간을 쓰는 대신, 사람이 읽기 쉬운 몇 줄의 Caddyfile로 인프라를 관리할 수 있습니다.

지금 운영 중이거나 준비 중인 웹 서비스 인프라에 Caddy를 도입하면, 설정에 드는 시간을 상당히 줄일 수 있습니다.

참고 자료 및 출처

관련 글