develicit
← 글 목록으로

개인 블로그를 AWS에 자체 호스팅한 이유

·읽는 시간 10분

블로그를 만들 때 가장 먼저 부딪히는 질문은 어디에 띄울 것인가다. 대부분의 Next.js 블로그는 Vercel로 흘러간다. git push 한 번이면 배포되고, 미리보기 환경까지 자동으로 붙으니 편하기 때문이다.

하지만 이 블로그는 빌드 타임에 전부 정적 파일로 떨어지는 사이트(output: 'export')다. 서버 사이드 렌더링도, 엣지 함수도 필요 없다. 그렇다면 굳이 PaaS의 추상화 비용을 낼 이유가 있을까? 정적 사이트라면 AWS S3 + CloudFront로 직접 운영하는 편이

  • 저렴하고 — 작은 블로그는 월 1달러 미만
  • 빠르고 — 전 세계 CloudFront 엣지에서 캐시 서빙
  • 락인이 덜하고 — Vercel 종속은 줄이고 Lambda@Edge·보안 헤더·캐시 정책을 직접 제어 (단 CloudFront·OAC·Route 53 등 AWS 의존은 생긴다)

이 글은 그 선택의 배경과, 흔히 오해받는 "트래픽이 늘면 결국 AWS가 더 비싸지지 않나?"라는 질문을 비용 모델로 직접 따져본 기록이다.

아키텍처 한눈에 보기

먼저 어떤 조각들이 어떻게 맞물리는지부터 보자.

컴포넌트역할
S3정적 자산 저장. 퍼블릭 접근 차단, OAC로만 접근
CloudFrontHTTPS, 압축, 보안 헤더, 글로벌 CDN
ACMTLS 인증서 (CloudFront용은 us-east-1 필수)
Route 53DNS, apex(루트 도메인) alias
GitHub ActionsOIDC 기반 keyless 배포

방문자 요청은 DNS → CloudFront 엣지 → OAC 서명을 거쳐 비공개 S3에 도달한다. 조회수 같은 동적 요소만 별도의 Cloudflare Worker로 분리했다. (Workers/KV 무료 한도는 10만 req/day·KV write 1천/day로, 소규모 블로그엔 충분하지만 고트래픽에서 PV마다 조회수 POST를 찍으면 한도·비용을 고려해야 한다.)

클라이언트
방문자 브라우저
develicit.com 요청
DNS
Route 53
호스트존 · apex A/AAAA alias → CloudFront
엣지 / CDN
CloudFront 배포
글로벌 엣지 캐시
ACM TLS 인증서 (us-east-1)HTTP/2 · HTTP/3Brotli · Gzip 압축보안 헤더 정책 (HSTS 등)SPA 404 → index 매핑
엣지 / CDN
OAC (SigV4 서명)
이 배포만 S3 접근 — 버킷 정책으로 강제
오리진 (비공개)
S3 버킷
Block Public Access · next export(out/) 정적 자산
조회수 카운터 (사이드카)
Cloudflare Worker
POST /views/:slug
Workers KV
slug별 카운트 영구 저장

캐시 히트 시 AWS 엣지에서 서빙되고(캐시 미스·HTML 재검증은 S3 origin까지 간다), 동적 조회수만 Cloudflare Worker+KV로 분리 — origin(S3)은 외부에 직접 노출되지 않는다.

Fig 1. 요청 경로 아키텍처 — DNS → 엣지(CloudFront) → OAC 서명 → 비공개 S3. 조회수만 별도 Cloudflare Worker로 분리.

설계에서 핵심이 되는 결정 세 가지:

  • S3는 절대 퍼블릭으로 열지 않는다. Block Public Access를 켜 두고, CloudFront의 OAC(Origin Access Control) 가 SigV4로 서명한 요청만 버킷 정책으로 허용한다. 버킷 URL이 유출돼도 직접 접근이 안 된다.
  • TLS 인증서(ACM)는 us-east-1에 둔다. CloudFront가 글로벌 서비스라 인증서를 버지니아 북부 리전에서만 읽어가기 때문이다. 사이트 자체는 어느 리전에 있어도 무관하다.
  • apex 도메인은 alias 레코드로 건다. develicit.com 같은 루트 도메인은 CNAME을 못 쓰므로, Route 53의 alias(A/AAAA)로 CloudFront 배포를 직접 가리킨다.

배포: git push 한 번으로

인프라가 정적이라고 배포까지 수동일 필요는 없다. main에 푸시하면 GitHub Actions가 OIDC로 단기 자격증명을 발급받아 빌드 → S3 동기화 → CloudFront 무효화까지 한 번에 처리한다.

1git push → main

GitHub Actions deploy 워크플로 트리거

2OIDC 인증

GitHub OIDC 토큰 → STS AssumeRoleWithWebIdentity → 단기 자격증명

keyless (no secrets)
3빌드

pnpm install --frozen-lockfile → next export(out/) + Pagefind 색인

4S3 동기화

_next/ 는 immutable(1년 캐시), 나머지는 max-age=0 + --delete

2단계 캐시 정책
5CloudFront 무효화

create-invalidation --paths "/*" 로 엣지 캐시 갱신

장기 보관 액세스 키가 GitHub에 존재하지 않는다 — OIDC로 매 실행마다 단기 STS 자격증명을 발급받아 역할을 위임받는다.

Fig 2. 배포 파이프라인 — git push 한 번이 OIDC keyless 인증 → 빌드 → S3 동기화 → 캐시 무효화까지 자동으로 이어진다.

여기서 두 가지가 핵심이다.

  • Keyless 배포. 장기 보관용 AWS 액세스 키를 GitHub Secrets에 넣지 않는다. 대신 GitHub의 OIDC 토큰으로 AssumeRoleWithWebIdentity를 호출해 매 실행마다 만료되는 단기 자격증명을 받는다. 키 유출 위험 자체가 사라진다.
  • 2단계 캐시 정책. 해시가 박힌 _next/ 자산은 immutable로 1년 캐시하고, HTML 등 나머지는 max-age=0으로 매번 재검증한다. 새 글은 즉시 반영되면서도 정적 자산은 엣지에서 최대한 오래 산다.

비용 분석

월 고정비 (저트래픽)

작은 개인 블로그(월 1만 PV ≈ 약 5GB 전송) 기준에서는 CloudFront 전송·요청과 S3 요청이 대부분 상시 무료 티어(CloudFront 월 1TB 전송 + 1천만 요청) 안에 들어온다. 따라서 실질 고정비는 사실상 하나로 수렴한다.

  • CloudFront: ~$0 (무료 티어 내)
  • S3: ~$0.05 (스토리지 + 약간의 요청)
  • Route 53: $0.50 (호스트존, 트래픽 무관 고정)
  • ACM: 무료

대략 월 $0.5–1. 사실상 Route 53 호스트존 비용이 전부다. Vercel Pro($20)와 비교하면 약 20배 차이다. (다만 개인·비상업 블로그라면 Vercel Hobby가 무료이고 월 100GB 전송이 포함되므로, $20 비교는 Pro가 필요한 경우에 한한다.)

AWS 자체 호스팅~$0.7/mo
Route 53 (호스트존) $0.5S3 $0.1CloudFront (무료 티어 내) $0.1
Vercel Pro$20/mo

트래픽이 적은 개인 블로그에서는 약 18배 차이. 트래픽이 늘면 어떻게 되는지는 아래 Fig 4에서 구체적으로 따져본다.

Fig 3. 월 비용 비교 (월 1만 PV 기준) — 전송·요청이 무료 티어 안이라 실질 고정비는 Route 53 호스트존이 거의 전부다.

트래픽이 늘면 손익분기가 뒤집힐까?

흔히 "트래픽이 폭증하면 결국 AWS가 더 비싸진다"고 생각하지만, 정적 사이트에서는 달러 기준 손익분기가 사실상 존재하지 않는다. 이유는 두 가지다.

  • 둘 다 월 1TB 전송이 무료다. CloudFront는 월 1TB까지 무료, Vercel Pro도 1TB가 포함된다. PV당 평균 전송량을 0.5MB로 잡으면 1TB는 약 200만 PV/월에 해당한다. 이 구간까지는 트래픽이 늘어도 AWS는 사실상 고정($1 수준), Vercel은 $20 고정이다.
  • 초과분 단가도 AWS가 더 싸다. 무료 티어를 넘기면 CloudFront는 GB당 $0.085(US/EU), Vercel은 $0.15 수준이다. 즉 고트래픽 구간에서도 마진 단가가 낮아 역전되지 않는다.

무료 티어 구간 — 월 ~200만 PV 이하

CloudFront·Vercel 모두 월 1TB 전송 포함. 이 구간에선 트래픽이 늘어도 AWS는 사실상 고정.

1만 PV~5 GB
AWS 자체 호스팅
$0.7/월
Vercel Pro
$20/월
100만 PV~0.5 TB
AWS 자체 호스팅
$0.7/월
Vercel Pro
$20/월
200만 PV~1 TB (한도)
AWS 자체 호스팅
$0.7/월
Vercel Pro
$20/월

무료 티어 초과 구간 — 전송 단가 비교

초과분 단가가 AWS가 더 낮다 ($0.085/GB < $0.15/GB) → 고트래픽에서도 역전되지 않음.

500만 PV~2.5 TB
AWS 자체 호스팅
$130/월
Vercel Pro
$250/월
1000만 PV~5 TB
AWS 자체 호스팅
$350/월
Vercel Pro
$630/월

정적 사이트에서는 모든 구간에서 AWS가 더 싸다. 월 $20은 ‘더 낮은 청구서'가 아니라 미리보기 배포·빌드·이미지 최적화 같은 DX를 사는 값이다.

단 두 경우엔 AWS도 빠르게 비싸진다 — (1) 인도·남미·일부 APAC 등 고가 엣지 리전(US/EU $0.085 대비 약 $0.11~0.12/GB), (2) 페이지 payload가 수 MB로 무거워 PV당 전송량이 급증할 때. 캐시·이미지 최적화로 PV당 전송을 낮추는 게 곧 비용 관리다.

가정: PV당 평균 egress 0.5MB, CloudFront US/EU $0.085/GB (월 1TB 무료), Vercel Pro 1TB 포함 후 $0.15/GB, Route 53 $0.5 고정. 전송 비용만 모델링했으며, 매우 높은 PV에서는 요청 수 과금(CloudFront 1천만 요청 초과분, Vercel Edge Requests $0.002/1K)도 더해진다. 실제 비용은 페이지 무게·리전·캐시 적중률에 따라 달라진다.

Fig 4. 트래픽에 따른 비용 — 두 플랫폼 모두 월 ~1TB 전송이 무료라 손익분기는 ‘달러'가 아니라 ‘운영 노력'에서 갈린다.

결론적으로 정적 블로그에서 월 $20은 더 낮은 청구서가 아니라 미리보기 배포·빌드·이미지 최적화 같은 DX(개발 편의) 를 사는 값이다. 진짜 손익분기는 "내 시간을 얼마나 쓸 것인가" 쪽에 있다. 다만 (1) 인도·남미 등 고가 엣지 리전, (2) 페이지 payload가 수 MB로 무거운 경우엔 PV당 전송량이 급증해 AWS 전송 비용도 빠르게 오르므로, 캐시 적중률과 이미지 최적화로 PV당 전송을 낮추는 것이 곧 비용 관리다.

트레이드오프

물론 공짜 점심은 없다. 직접 운영의 비용은 이 아니라 으로 치른다.

  • 초기 설정이 더 복잡하다. S3·CloudFront·OAC·ACM·Route 53를 손으로 엮는 대신 Terraform으로 코드화했지만, 그만큼 Terraform 학습 곡선이 든다.
  • 미리보기 환경을 직접 만들어야 한다. Vercel의 PR별 프리뷰 URL 같은 건 기본 제공되지 않는다. 필요하면 별도 버킷/배포를 구성해야 한다.
  • 이미지 최적화도 직접 한다. next/image의 런타임 최적화 대신 빌드 타임 최적화나 CloudFront + Lambda@Edge를 직접 붙여야 한다.

대신 한 번 만들어 두면 손이 거의 안 간다. 인프라가 Terraform 코드로 박제되니 재현 가능성이 100%이고, 무엇이 어떻게 동작하는지 전부 내 눈에 보인다.

마무리

정리하면, 정적 사이트이고 · (무료 Hobby로는 부족해) Vercel Pro가 필요하며 · US/EU 위주 트래픽 · 직접 운영할 의지가 있다는 조건이라면 AWS 자체 호스팅이 비용·속도에서 우위다. 반대로 무료 Hobby로 충분하거나, SSR/ISR이 필요하거나, 인프라에 시간을 쓰고 싶지 않거나, 팀 단위 미리보기 협업이 중요하다면 Vercel이 충분히 합리적인 선택이다.

나는 "내 블로그가 어떻게 서빙되는지 한 줄까지 이해하고 싶다"는 쪽이라 AWS를 골랐다. 그리고 그 선택이 매달 청구서로 후회를 남기지 않는다는 점이, 이 글을 쓰게 된 이유다.


댓글