시리즈를 시작하며
Next.js 앱을 npm run start로 띄우면 localhost:3000에서 잘 돌아갑니다. 그런데 막상 서버에 배포하려고 하면 이런 질문들이 쏟아집니다.
- 80/443 포트로 들어온 요청을 어떻게 3000번 포트로 넘기지?
- HTTPS 인증서는 어디에 붙이지?
- 앱을 두 대 띄우면 요청은 누가 나눠주지?
- 정적 파일까지 Node가 서빙해야 하나?
이 질문들의 답이 바로 웹 서버 / 리버스 프록시입니다. 이 시리즈에서는 이 분야의 두 대표 주자인 Nginx와 Caddy를 기초부터 심화까지 다루고, 마지막 편에서 둘을 비교합니다.
시리즈 목차
| 편 | 제목 | 핵심 키워드 |
|---|---|---|
| 1 | 웹 서버와 리버스 프록시 개념 (이 글) | 정방향/역방향 프록시, TLS, L4/L7 |
| 2 | Nginx 기초 | 아키텍처, 설정 구조, 정적 파일 |
| 3 | Nginx 중급 | location 매칭, 리버스 프록시, 로드 밸런싱, HTTPS |
| 4 | Nginx 심화 | 캐싱, Rate Limit, 보안, 튜닝, stream |
| 5 | Caddy 기초 | Caddyfile, 자동 HTTPS, 리버스 프록시 |
| 6 | Caddy 심화 | 매처, 스니펫, 헬스 체크, Admin API, 플러그인 |
| 7 | 실전: 같은 아키텍처를 두 서버로 | Docker Compose, Next.js + API + WebSocket |
| 8 | Nginx vs Caddy 장단점 비교 | 선택 가이드 |
1. 웹 서버(Web Server)란
가장 좁은 의미의 웹 서버는 HTTP 요청을 받아 파일을 돌려주는 프로그램입니다.
브라우저 ──GET /index.html──▶ 웹 서버 ──읽기──▶ /var/www/index.html
◀────200 OK + HTML────여기에 시간이 지나며 역할이 붙었습니다.
- 정적 파일 서빙: HTML, CSS, JS, 이미지
- TLS 종료(Termination): HTTPS 암호화/복호화 담당
- 압축: gzip, brotli, zstd
- 리버스 프록시: 뒤에 있는 애플리케이션 서버로 요청 전달
- 로드 밸런싱: 여러 애플리케이션 서버에 요청 분산
- 캐싱, 접근 제어, Rate Limit 등
Nginx와 Caddy는 모두 이 역할 전부를 수행할 수 있는 "만능 프런트 서버"입니다.
2. 프록시: 정방향 vs 역방향
"프록시(Proxy)"는 대리인입니다. 누구를 대리하느냐에 따라 이름이 갈립니다.
정방향 프록시 (Forward Proxy)
클라이언트를 대리합니다. 회사 내부망에서 외부 인터넷으로 나갈 때 거치는 프록시가 대표적입니다. 외부 서버 입장에서는 실제 클라이언트가 누군지 모르고 프록시만 보입니다.
[직원 PC] ──▶ [포워드 프록시] ──▶ 인터넷(google.com 등)역방향 프록시 (Reverse Proxy)
서버를 대리합니다. 클라이언트는 프록시가 진짜 서버인 줄 알고, 실제 애플리케이션 서버는 프록시 뒤에 숨어 있습니다.
┌──▶ Next.js (localhost:3000)
[브라우저] ──▶ [리버스 프록시] ─┼──▶ API 서버 (localhost:8080)
(443 포트) └──▶ 정적 파일 (/var/www)Nginx와 Caddy를 쓰는 이유의 90%가 이 리버스 프록시입니다. 리버스 프록시를 두면 이런 이점이 생깁니다.
- 단일 진입점: 외부에는 443만 열고, 내부 서비스들은 닫아둘 수 있습니다.
- TLS 일원화: 인증서를 각 앱이 아니라 프록시 한 곳에서 관리합니다.
- 경로/도메인 기반 라우팅:
/api는 백엔드로, 나머지는 프런트로. - 무중단 배포와 확장: 뒤의 서버를 늘리거나 교체해도 클라이언트는 모릅니다.
- 보안 계층: 요청 크기 제한, Rate Limit, 헤더 정리 등을 앞단에서 처리합니다.
3. TLS와 HTTPS 한 장 요약
HTTPS는 HTTP 위에 TLS 암호화를 얹은 것입니다. 웹 서버가 HTTPS를 제공하려면 인증서(certificate)와 개인 키(private key)가 필요합니다.
- 인증서 발급 기관(CA): Let's Encrypt, ZeroSSL 같은 무료 CA가 보편화됐습니다.
- ACME 프로토콜: 인증서 발급·갱신을 자동화하는 표준 프로토콜(RFC 8555)입니다.
- 챌린지(Challenge): "이 도메인이 정말 당신 것인가"를 증명하는 방법입니다.
HTTP-01: 80 포트로 특정 파일을 응답할 수 있는지 확인TLS-ALPN-01: 443 포트에서 특수 TLS 핸드셰이크로 확인DNS-01: DNS TXT 레코드를 생성할 수 있는지 확인 (와일드카드 인증서는 이것만 가능)
여기서 두 서버의 철학이 크게 갈립니다.
- Nginx: 전통적으로 인증서는 "외부에서(certbot 등) 받아와서 경로를 지정하는 것"이었습니다. (최근 공식 ACME 모듈이 나왔습니다. 3편에서 다룹니다.)
- Caddy: 도메인만 적으면 알아서 발급·갱신·리다이렉트까지 해줍니다. 이게 Caddy의 가장 큰 정체성입니다.
4. L4 프록시와 L7 프록시
OSI 계층 기준으로 어디까지 보고 판단하느냐의 차이입니다.
| 구분 | L4 (전송 계층) | L7 (애플리케이션 계층) |
|---|---|---|
| 보는 정보 | IP, 포트 (TCP/UDP) | URL, 헤더, 쿠키, 메서드 |
| 할 수 있는 일 | 포트 포워딩, TCP 로드 밸런싱 | 경로 라우팅, 헤더 조작, 캐싱 |
| 예시 | DB 커넥션 분산, SSH 프록시 | /api → 백엔드 |
| Nginx | stream 모듈 | http 모듈 |
| Caddy | layer4 플러그인 | 기본 기능 |
대부분의 웹 서비스에서는 L7을 씁니다. L4는 DB나 MQTT 같은 비HTTP 서비스를 프록시할 때 등장합니다.
5. 로드 밸런싱 기본 알고리즘
여러 대의 백엔드(업스트림)에 요청을 나눠주는 방식입니다.
| 알고리즘 | 설명 | 적합한 상황 |
|---|---|---|
| Round Robin | 순서대로 돌아가며 | 서버 성능이 균일할 때 |
| Weighted | 가중치 비율대로 | 서버 사양이 다를 때 |
| Least Connections | 현재 연결이 가장 적은 서버로 | 요청 처리 시간이 들쭉날쭉할 때 |
| IP Hash | 클라이언트 IP로 서버 고정 | 세션을 서버 메모리에 저장할 때 |
| Random | 무작위 (+ "두 개 뽑아 덜 바쁜 쪽") | 대규모 분산 환경 |
또 하나 중요한 개념이 헬스 체크입니다.
- 패시브(Passive) 헬스 체크: 실제 요청이 실패하면 그 서버를 잠시 빼는 방식
- 액티브(Active) 헬스 체크: 프록시가 주기적으로
/health같은 엔드포인트를 찔러보는 방식
이 차이는 나중에 Nginx(오픈소스는 패시브만)와 Caddy(둘 다 내장)를 비교할 때 중요한 포인트가 됩니다.
6. Nginx와 Caddy 첫인상
| Nginx | Caddy | |
|---|---|---|
| 첫 공개 | 2004년 (Igor Sysoev) | 2015년 (Matt Holt) |
| 언어 | C | Go |
| 설정 파일 | nginx.conf (블록 + 지시어) | Caddyfile 또는 JSON |
| HTTPS | 수동 설정이 기본 (ACME 모듈 신규 도입) | 자동 HTTPS가 기본 |
| 확장 | C 모듈 (동적 모듈 가능) | Go 플러그인 (커스텀 빌드) |
| 라이선스 | BSD 2-Clause | Apache 2.0 |
| 상용 버전 | NGINX Plus (F5) | 없음 (스폰서십 모델) |
같은 일을 하는 설정을 미리 맛보기로 비교해 보겠습니다. example.com으로 들어온 HTTPS 요청을 localhost:3000으로 넘기기입니다.
Nginx (인증서는 이미 발급되어 있다고 가정)
server {
listen 80;
server_name example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
http2 on;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:3000;
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;
}
}Caddy (인증서 발급·갱신·HTTP→HTTPS 리다이렉트 포함)
example.com {
reverse_proxy localhost:3000
}세 줄입니다. 그렇다고 "Caddy가 무조건 낫다"는 결론은 성급합니다. Nginx의 장황함은 곧 명시성과 세밀한 제어이기도 하고, 20년간 쌓인 레퍼런스와 생태계는 무시할 수 없는 자산입니다. 이 트레이드오프를 시리즈 전체에 걸쳐 살펴보겠습니다.
정리
- 웹 서버는 정적 파일 서빙에서 출발해 TLS, 프록시, 로드 밸런싱까지 담당하는 "프런트 서버"가 되었다.
- 리버스 프록시는 서버를 대리하며, 단일 진입점·TLS 일원화·라우팅·확장성을 준다.
- HTTPS 인증서 자동화(ACME)를 대하는 태도가 Nginx와 Caddy의 가장 큰 철학 차이다.
- L4/L7, 로드 밸런싱 알고리즘, 패시브/액티브 헬스 체크 개념은 이후 편에서 계속 등장한다.
다음 편에서는 Nginx를 설치하고, 마스터/워커 구조와 설정 파일의 문법부터 차근차근 살펴봅니다.