Caddy 완벽 가이드 — 자동 HTTPS 웹 서버, Nginx보다 설정 10배 간단

Caddy 완벽 가이드 — 자동 HTTPS 웹 서버, Nginx보다 설정 10배 간단

이 글의 핵심

Caddy는 "자동 HTTPS를 기본값으로" 한 Go 기반 웹 서버입니다. Nginx가 수십 줄의 설정으로 SSL·proxy_pass를 구성하는 것을 Caddy는 2-3줄로 끝냅니다. Let's Encrypt 통합·자동 갱신·HTTP/2·HTTP/3(QUIC)·단일 바이너리 배포로 2020년대 웹 서버의 새 표준으로 자리잡았습니다. 2026년 현재 Cloudflare·GitLab·HashiCorp가 내부 인프라에 도입했습니다.

설치

바이너리 다운로드

# Linux
curl -OL https://caddyserver.com/api/download?os=linux
chmod +x caddy
sudo mv caddy /usr/local/bin/

# macOS
brew install caddy

# Windows
scoop install caddy

Docker

docker run -d -p 80:80 -p 443:443 \
  -v $PWD/Caddyfile:/etc/caddy/Caddyfile \
  -v caddy_data:/data \
  caddy:latest

첫 Caddyfile

# Caddyfile
example.com {
    respond "Hello, World!"
}
caddy run
# 또는
caddy start  # 백그라운드
  • example.com에 자동 HTTPS 활성화
  • Let’s Encrypt 인증서 자동 발급

정적 파일 서버

example.com {
    root * /var/www/html
    file_server
}

/var/www/html 디렉터리를 https://example.com으로 서빙.

리버스 프록시

api.example.com {
    reverse_proxy localhost:8000
}

FastAPI·Express·Go 서버를 api.example.com으로 프록시.

로드 밸런싱

api.example.com {
    reverse_proxy localhost:8000 localhost:8001 localhost:8002 {
        lb_policy round_robin
        health_uri /health
        health_interval 10s
    }
}
  • lb_policy: round_robin, least_conn, ip_hash
  • health_uri: 헬스체크 endpoint

PHP (FastCGI)

example.com {
    root * /var/www/html
    php_fastcgi unix//run/php/php8.2-fpm.sock
    file_server
}

WordPress·Laravel 배포에 사용.

SPA (React·Vue)

example.com {
    root * /var/www/dist
    try_files {path} /index.html
    file_server
}

모든 라우트를 index.html로 fallback.

리다이렉트

www.example.com {
    redir https://example.com{uri} permanent
}

example.com {
    # ...
}

www → 비-www 리다이렉트.

HTTP → HTTPS 강제

Caddy는 기본적으로 HTTP를 HTTPS로 자동 리다이렉트. 명시적으로:

http://example.com {
    redir https://example.com{uri} permanent
}

https://example.com {
    # ...
}

환경변수

{
    email [email protected]  # Let's Encrypt 이메일
}

example.com {
    reverse_proxy {$BACKEND_HOST}:{$BACKEND_PORT}
}
export BACKEND_HOST=localhost
export BACKEND_PORT=8000
caddy run

서브 경로 프록시

example.com {
    handle_path /api/* {
        reverse_proxy localhost:8000
    }
    
    handle {
        root * /var/www/html
        file_server
    }
}
  • /api/*localhost:8000
  • 나머지 → 정적 파일

WebSocket

example.com {
    reverse_proxy /ws localhost:8000 {
        header_up Upgrade {http.request.header.Upgrade}
        header_up Connection {http.request.header.Connection}
    }
}

WebSocket 자동 인식 + 프록시.

gRPC

grpc.example.com {
    reverse_proxy h2c://localhost:50051
}

HTTP/2 기반 gRPC 프록시.

압축

example.com {
    encode gzip zstd
    file_server
}

자동 Brotli·gzip·zstd 압축.

보안 헤더

example.com {
    header {
        Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
        X-Content-Type-Options "nosniff"
        X-Frame-Options "DENY"
        X-XSS-Protection "1; mode=block"
        Referrer-Policy "no-referrer-when-downgrade"
    }
    
    file_server
}

Rate Limiting (플러그인)

# xcaddy로 플러그인 빌드
xcaddy build --with github.com/mholt/caddy-ratelimit
example.com {
    rate_limit {
        zone dynamic {
            key {remote_host}
            events 100
            window 1m
        }
    }
    
    reverse_proxy localhost:8000
}

IP당 분당 100 요청 제한.

Cloudflare DNS Challenge

xcaddy build --with github.com/caddy-dns/cloudflare
{
    email [email protected]
    acme_dns cloudflare {env.CLOUDFLARE_API_TOKEN}
}

example.com {
    tls {
        dns cloudflare {env.CLOUDFLARE_API_TOKEN}
    }
    
    reverse_proxy localhost:8000
}

포트 80·443 안 열어도 인증서 발급 가능.

Docker Compose

version: '3.8'
services:
  caddy:
    image: caddy:latest
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
      - "443:443/udp"  # HTTP/3
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      - caddy_data:/data
      - caddy_config:/config
  
  app:
    image: myapp:latest
    expose:
      - "8000"

volumes:
  caddy_data:
  caddy_config:
# Caddyfile
example.com {
    reverse_proxy app:8000
}

멀티 도메인

example.com {
    reverse_proxy localhost:8000
}

blog.example.com {
    reverse_proxy localhost:8001
}

api.example.com {
    reverse_proxy localhost:8002
}

각 도메인마다 자동 HTTPS.

로그

example.com {
    log {
        output file /var/log/caddy/access.log {
            roll_size 100mb
            roll_keep 5
            roll_keep_for 720h
        }
        format json
    }
    
    reverse_proxy localhost:8000
}

JSON 형식 로그 + 로테이션.

systemd 서비스

sudo caddy stop
sudo systemctl enable --now caddy

# 설정 변경 후
sudo systemctl reload caddy
# /etc/systemd/system/caddy.service
[Unit]
Description=Caddy
After=network.target

[Service]
Type=notify
User=caddy
Group=caddy
ExecStart=/usr/local/bin/caddy run --config /etc/caddy/Caddyfile
ExecReload=/usr/local/bin/caddy reload --config /etc/caddy/Caddyfile
Restart=on-failure
RestartSec=5s

[Install]
WantedBy=multi-user.target

Kubernetes Ingress

helm repo add caddy https://caddyserver.github.io/ingress
helm install caddy caddy/caddy-ingress-controller
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: example
spec:
  ingressClassName: caddy
  rules:
  - host: example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: myapp
            port:
              number: 8000
  tls:
  - hosts:
    - example.com

자동 Let’s Encrypt 인증서.

HTTP/3 (QUIC)

{
    servers {
        protocol {
            experimental_http3
        }
    }
}

example.com {
    reverse_proxy localhost:8000
}

UDP 443 포트 열어야 함.

트러블슈팅

Let’s Encrypt 인증서 발급 실패

  • 포트 80·443 방화벽 확인
  • DNS A 레코드 전파 대기
  • caddy run --watch 로그 확인

리버스 프록시 502 Bad Gateway

  • 백엔드 서버 작동 확인 (curl localhost:8000)
  • reverse_proxy localhost:8000 host 정확히

인증서 갱신 안 됨

  • /data/caddy/certificates 권한 확인
  • caddy trust (로컬 개발)

Docker에서 자동 HTTPS 안 됨

  • 호스트 네트워크 모드 또는 443 포워딩 확인
  • 도메인이 실제 공인 IP 가리켜야

체크리스트

  • Caddy 설치 (caddy version 확인)
  • 도메인 DNS A 레코드 설정
  • Caddyfile 작성 (리버스 프록시 or 파일 서버)
  • caddy run 실행
  • HTTPS 자동 인증서 확인
  • systemd 서비스 등록
  • 로그·모니터링 설정
  • HTTP/3 활성화 (선택)

마무리

Caddy는 “HTTPS는 선택이 아니라 기본값”이라는 철학을 실현한 웹 서버입니다. Nginx·Apache가 20년간 지배하던 웹 서버 생태계에 “설정 파일 간소화·자동 인증서”라는 혁신을 가져왔고, 2026년 현재 스타트업·인디 해커·DevOps 엔지니어들이 가장 빠르게 채택하는 도구입니다. Go 단일 바이너리 덕분에 Docker·Kubernetes·edge 환경 배포도 간단하고, Let’s Encrypt 통합으로 SSL 관리 부담이 제로입니다. Nginx 설정이 복잡하다고 느껴진다면, 지금 바로 Caddy로 전환을 시도해보세요.

관련 글

  • Nginx 완벽 가이드
  • Docker 완벽 가이드
  • Cloudflare 완벽 가이드
  • Traefik 가이드