왜 다들 Cloudflare로 갈까: 무료 플랜의 바닥부터 DB, 폰트, CLI, CDN까지 7가지 팁

왜 다들 Cloudflare로 갈까: 무료 플랜의 바닥부터 DB, 폰트, CLI, CDN까지 7가지 팁

바이브코더가 Cloudflare로 가는 가장 큰 이유는 무료 플랜에 "바닥"이 있기 때문입니다. Workers 무료 플랜은 하루 10만 요청을 넘으면 요금을 붙이는 대신 요청을 오류(Error 1027)로 막습니다. 자고 일어났더니 청구서가 와 있는 일이 구조적으로 생기지 않습니다. 코드는 Workers, 파일은 R2에 두면 서버 리전을 고를 필요도 없고, 유료로 올려도 월 5달러에 요청 1,000만 건이 들어 있습니다. 다만 공식 문서를 끝까지 읽으면 단서가 붙습니다. R2는 무료 한도를 넘으면 과금되고, 월 5달러 유료 플랜에는 2026년 10월 현재 지출 상한이 없습니다. 2026년 10월 6일에는 AI와 함께 짠 알람 코드가 2주 가까이 무한 루프를 돌아 10,811달러를 낸 개발자가 나왔습니다. 이 글은 영상이 권한 7가지 팁을 공식 문서로 다시 확인하고, Cloudflare가 안 맞는 경우와 한국에서 실제로 어느 데이터센터가 응답하는지까지 정리합니다.

이 글은 2026년 10월 4일에 올라온 유튜브 영상 왜 다들 클라우드플레어로 갈까(메이커 에반)를 계기로 썼습니다. 같은 채널의 AWS 비용 이야기는 서버를 이제 AWS에 올리지 않는 이유에서, 리전과 왕복 횟수, 이미지 무게는 바이브코딩 배포가 느린 진짜 이유에서 다뤘으므로, 이 글은 Cloudflare 스택 자체에 집중합니다. 영상의 숫자는 Cloudflare, Neon, GitHub, GitGuardian, Palo Alto Networks의 원문으로 확인했고, 대부분 맞았지만 몇 가지는 낡았거나 단서가 필요했습니다. 필자가 운영하는 어비스 홈페이지(aviss.kr)도 Cloudflare 뒤에 있습니다.

핵심 요약

  • 무료 플랜에는 바닥이 있습니다. Workers 무료는 하루 10만 요청(한국 시간 오전 9시 리셋), D1 무료는 하루 쓰기 10만 행, Hyperdrive 무료는 하루 10만 쿼리이고, 넘으면 전부 과금 대신 오류로 멈춥니다. Neon 무료도 컴퓨트를 다 쓰면 다음 달까지 멈춥니다.
  • 월 5달러를 내는 순간 바닥이 사라집니다. Workers 유료 플랜과 R2 초과분은 쓴 만큼 과금되고, 예산 알림은 "정보용"이라 사용을 멈추지 않으며 다음 날 옵니다. 2026년 10월 6일에는 Durable Objects 알람 루프로 10,811.41달러가 청구된 사례가 나왔고, Cloudflare는 하드 캡을 2026년 4분기에 조기 제공하겠다고 밝혔습니다.
  • DB는 커질 서비스라면 Postgres가 낫습니다. D1은 DB 하나가 쿼리를 한 번에 하나씩 처리하고(1ms 쿼리면 초당 약 1,000개), 크기는 DB당 10GB에서 더 늘릴 수 없습니다. Neon Postgres를 Hyperdrive로 붙이고 Smart Placement를 켜는 조합이 커뮤니티의 기본 추천입니다.
  • 에이전트가 wrangler를 절반쯤 씁니다. Cloudflare에 따르면 9월 28일 발표 직전 주에 wrangler 사용의 48%가 에이전트였고, 9월 28일에는 에이전트용 새 CLI cf가 나왔습니다. CLI를 깔면 배포, 시크릿, 로그, DB 조회를 에이전트가 직접 합니다.
  • 한국에서는 응답 위치를 확인해야 합니다. 필자 측정에서 Cloudflare 자체 사이트와 *.pages.dev 주소는 서울(ICN)에서 17~19ms에 응답했지만, aviss.kr과 hono.dev 두 커스텀 도메인은 로스앤젤레스(LAX)에서 약 141ms에 응답했습니다.
  • 키는 5분이면 털립니다. 2025년 한 해 공개 GitHub 커밋에 새로 들어간 시크릿은 2,865만 건이었고, Unit 42의 실험에서 공개된 AWS 키는 5분 안에 악용됐습니다.

목차

왜 다들 Cloudflare로 가나요?

작은 서비스를 처음 올리는 사람에게 Cloudflare는 "고를 것이 적고, 실수해도 청구서가 오지 않는" 곳입니다. Workers는 코드를 Cloudflare의 전 세계 데이터센터에서 실행하는 서비스라 서울 사용자는 서울 근처에서, 뉴욕 사용자는 뉴욕 근처에서 코드가 돕니다. 서버 사양이나 리전을 고르는 단계가 없습니다. R2는 이미지와 영상 같은 파일을 두는 저장소이고, 밖으로 내보내는 전송 요금(egress)이 없습니다. 영상 화자는 이 둘만으로 "바이브 코더 99%는 충분하다"고 말합니다.

실제로 옮긴 사람들의 이유도 비슷합니다. 한 국내 블로거는 Vercel 무료 플랜이 월 단위 한도라 다 쓰면 다음 결제 주기까지 기능이 멈추는 것을 겪고, 하루 10만 건이 매일 다시 채워지는 Workers로 API 14개를 하루 만에 옮겼다고 적었습니다(네이버 블로그, 2026-08-30). 해외 커뮤니티에서도 9월 r/vibecoding의 "바이브코딩 스택" 글에 "백엔드는 Cloudflare Workers, DB는 Neon을 Hyperdrive로"라는 답이 가장 위에 올랐고, 다른 사람은 "Claude가 무료 구성으로 권한 것과 거의 같다"고 덧붙였습니다(r/vibecoding, 2026-09-17).

에이전트 쪽 숫자도 있습니다. Cloudflare는 2026년 3월에 wrangler(Cloudflare CLI) 사용의 4분의 1을 에이전트가 했고, 9월 28일 발표 직전 주에는 48%까지 올랐다고 밝혔습니다(Cloudflare Blog, 2026-09-28). 사람이 대시보드를 클릭하는 대신 Claude Code나 Codex가 명령어로 배포하는 흐름이 이미 절반입니다. AWS가 왜 이 흐름과 안 맞는지는 서버를 이제 AWS에 올리지 않는 이유에 정리했습니다.

팁 1. 코드는 Workers, 파일은 R2: 한도를 넘으면 무엇이 일어나나

영상이 꼽은 Cloudflare의 최대 장점은 가격보다 "한도를 넘었을 때의 동작"입니다. Workers 무료 플랜은 하루 10만 요청까지이고, UTC 자정(한국 시간 오전 9시)에 다시 채워집니다. 넘으면 Cloudflare가 Error 1027을 돌려주고, 설정에 따라서는 Worker를 건너뛰고 원래 요청을 그대로 통과시키게(fail open) 할 수도 있습니다(Cloudflare Workers limits, 2026-10-08). 돈은 나가지 않지만, 대신 다음 리셋까지 최대 하루 동안 Worker가 멈출 수 있습니다. 봇 트래픽 하나로 한도를 다 쓸 수도 있으므로, 같은 응답은 캐시하고 Cloudflare의 봇 차단을 켜 두는 편이 좋습니다.

유료 플랜(Workers Paid)은 계정당 월 최소 5달러이고, 요청 1,000만 건과 CPU 시간 3,000만 ms가 들어 있습니다. 넘으면 요청 100만 건당 0.30달러, CPU 100만 ms당 0.02달러가 붙고, 데이터 전송 요금은 따로 없습니다. 이미지나 자바스크립트 같은 정적 파일 요청은 "무료이고 무제한"이라 이 숫자에 들어가지 않습니다(Cloudflare Workers pricing, 2026-10-02). 영상의 숫자는 모두 공식 문서와 같았습니다.

R2는 GB당 월 0.015달러이고 매달 10GB 저장, 쓰기 계열 요청(Class A) 100만 건, 읽기 계열 요청(Class B) 1,000만 건이 무료입니다. 어떤 저장 등급이든 egress 요금은 없습니다(Cloudflare R2 pricing, 2026-10-01). 여기까지가 영상이 말한 "작은 서비스는 이 안에서 거의 다 끝난다"의 근거입니다.

그런데 서비스마다 한도를 넘었을 때의 동작은 같지 않습니다. 공식 문서를 한 줄씩 대조하면 다음과 같습니다.

서비스와 플랜 무료로 들어 있는 양 넘으면
Workers 무료 하루 요청 10만 건 Error 1027로 막힘. 과금 없음
D1 무료 하루 읽기 500만 행, 쓰기 10만 행, 저장 총 5GB 읽기와 쓰기는 리셋 전까지 쿼리 오류, 저장은 데이터를 지울 때까지 새로 쓰기 불가
Hyperdrive 무료 하루 쿼리 10만 건(캐시 적중 포함) 오류
Images 변환 무료 월 고유 변환 5,000건 새 변환은 9422 오류, 과금 없음
Neon 무료 프로젝트당 월 100 CU-시간, 저장 1GB 다음 청구 주기까지 컴퓨트 정지
R2 월 10GB, Class A 100만, Class B 1,000만 넘은 만큼 과금
Workers 유료(월 5달러) 요청 1,000만, CPU 3,000만 ms 넘은 만큼 과금, 상한 없음

출처: Workers limits, D1 pricing, Hyperdrive pricing, Images pricing, Neon plans, R2 get started (2026-10-09 확인).

R2는 무료 한도가 있어도 Workers 무료처럼 멈추는 구조가 아닙니다. 시작하려면 R2 구독 결제 절차를 거쳐야 하고, 문서는 "쓴 만큼 매달 청구한다"고 씁니다. 그래서 R2를 켠 순간 결제 수단이 연결되고, 무료 한도를 넘는 사용량은 그대로 청구서로 갑니다.

월 5달러를 내면 바닥이 사라진다

Workers 유료 플랜에는 2026년 10월 9일 현재 지출 상한(hard cap)이 없습니다. Cloudflare는 2026년 7월부터 예산 알림이 없는 종량제 계정에 10달러짜리 알림을 자동으로 만들어 줍니다. 그러나 문서는 "예산 알림은 정보용일 뿐이며 사용을 멈추거나 제한하지 않는다"고 못 박고, 사용량을 하루 한 번 집계하기 때문에 알림은 기준을 넘은 다음 날에 온다고 씁니다(Cloudflare Budget alerts; Changelog, 2026-07-20).

알림이 정보용일 뿐이라는 것이 얼마나 비쌀 수 있는지 보여 준 사례가 2026년 10월 6일에 나왔습니다. 한 중국어권 개발자는 X에 프로젝트 하나의 Durable Object 알람이 무한 루프를 돌아 6조 번 읽고 쓰는 바람에 약 1만 달러가 청구됐다며 "바이브 코딩이 나를 망쳤다"고 썼습니다. 이틀 뒤에는 10,811.41달러를 전액 냈고, 감면 요청에는 봇 답변만 돌아왔으며, 모든 프로젝트를 직접 운영하는 VPS로 옮기겠다고 밝혔습니다(@shmily7, 2026-10-06; 후속 글, 2026-10-08). 이 사건을 정리한 글에 따르면 문제의 예약 코드는 8월 31일 Codex가 작성했고, 9월 3일 Claude의 도움을 받은 수정이 이어졌으며, 9월 23일에 오작동이 시작됐습니다. 당사자가 알린 것은 10월 6일이니 2주 가까이 루프가 돈 셈이고, 10월 8일 기준 최종 환불 여부는 정해지지 않았습니다(aiidelist, 2026-10-08). 기본 예산 알림이 이 계정에 켜져 있었는지는 공개되지 않았습니다. 키를 도둑맞은 것도, 트래픽이 몰린 것도 아니었습니다. 에이전트와 함께 짠 반복 코드 하나가 아무도 모르는 사이에 돌았습니다.

이런 일이 한 번뿐이었던 것도 아닙니다. 2026년 Cloudflare 커뮤니티와 해커뉴스에 올라온 과금 사례 8건을 모은 dev.to 글(작성자가 AI 보조로 썼다고 밝힌 모음 글)을 보면 7건이 D1, 1건이 Durable Objects였고, 그 1건은 해커뉴스에 올라온 글로, 사용자가 0명인 서비스에서 알람이 스스로를 다시 예약하는 루프로 8일 동안 약 34,895달러가 나온 경우였습니다(dev.to, 2026-09-23). 공통점은 요청 수가 아니라 저장소 연산이 쌓였다는 점입니다. 한 개발자는 초당 5,000건의 봇 요청이 한 시간 동안 Worker에 몰리면 요청과 CPU 요금은 7.20달러뿐이지만, 요청마다 KV에 한 번 쓰면 90달러, R2에 한 번 쓰면 81달러, D1에 한 행 쓰면 18달러가 된다고 2026년 9월 정가로 계산했습니다(gfuse.dev, 2026-09-16).

Cloudflare도 이 문제를 압니다. 10월 2일 공식 블로그에서 "하드 지출 상한을 지금 시제품으로 만들고 있고, 2026년 4분기에 조기 제공할 예정"이라고 밝혔습니다(Cloudflare Blog, 2026-10-02). r/CloudFlare에는 "하드 캡이 나오기 전까지는 Cloudflare에 한 푼도 내지 않겠다"는 글이 올라왔습니다(r/CloudFlare, 2026-10-04). 공교롭게도 AWS는 9월 16일부터 새 가입 경험에 프로젝트별 월 지출 상한(20달러부터)을 넣었고, 상한에 닿으면 프로젝트를 일시 정지합니다. 다만 신규 고객에게 차례로 여는 중입니다(AWS News Blog, 2026-09-16).

그러니 영상의 "한도를 넘으면 멈춘다"는 무료 플랜에서만 맞는 말입니다. 유료로 올린 뒤에는 다음 세 가지를 해 둡니다.

  1. 호출당 CPU 한도를 겁니다. Cloudflare 요금 문서는 "실수로 생기는 폭주 청구나 지갑 고갈 공격을 막으려면 호출당 쓸 수 있는 CPU 시간 상한을 설정하라"고 권합니다. 설정 파일의 limits.cpu_ms나 대시보드의 CPU Limits에서 정합니다. 다만 이 한도가 막는 것은 CPU 요금뿐입니다. Durable Objects, KV, D1 행 쓰기, R2 쓰기처럼 위 사례에서 돈이 나간 저장소 연산은 막지 못합니다.
  2. 예산 알림 기준을 낮추고 매일 사용량을 봅니다. 알림은 다음 날 오므로 기준을 월 예산의 일부로 잡아야 의미가 있습니다. 에이전트에게 하루 한 번 사용량 화면을 읽고 보고하게 시킬 수도 있습니다.
  3. 예약과 재시도 코드는 사람이 읽습니다. Durable Objects 알람, 큐 재시도, 크론처럼 스스로 다시 부르는 코드는 종료 조건이 없으면 무한히 돕니다. 저장소 연산 요금을 막는 장치는 지금으로서는 이것뿐이므로, AI에게 맡긴 코드라도 "언제 멈추는가"와 "요청 하나가 몇 번 쓰는가"는 사람이 확인합니다.

팁 2. DB는 D1으로 시작해도 되지만, 커질 서비스는 Postgres

D1은 설정할 것이 거의 없는 좋은 DB지만, 구조상 커지는 서비스에는 천장이 있습니다. D1은 Cloudflare가 관리하는 SQLite이고 Workers에 바로 붙습니다. 영상 화자가 Postgres를 권한 이유는 세 가지이고, 세 가지 모두 공식 문서에 그대로 있습니다.

  • 크기. DB 하나의 최대 크기는 유료 10GB, 무료 500MB이고, 문서는 "10GB 한도는 더 늘릴 수 없다"고 씁니다(D1 limits, 2026-04-21).
  • 처리 방식. 같은 문서는 "D1 데이터베이스 하나는 본질적으로 단일 스레드이며 쿼리를 한 번에 하나씩 처리한다"고 설명하고, 평균 1ms 쿼리면 초당 약 1,000개, 100ms 쿼리면 초당 10개라고 예를 듭니다. 대기열이 차면 "overloaded" 오류가 납니다.
  • 확장 기능. D1이 지원하는 SQLite 확장은 전문 검색(FTS5), JSON, 수학 함수입니다(D1 SQL statements). 벡터 검색은 Vectorize라는 별도 제품을 붙여야 합니다. Postgres는 pgvector 확장 하나로 같은 DB 안에서 됩니다.

D1이 맞는 서비스도 분명합니다. 한 국내 비개발자는 GitHub Pages로 화면을 띄우고 Worker가 로그인을 확인한 뒤 D1에 저장하는 결혼 준비 체크리스트 앱을 만들었습니다(네이버 블로그, 2026-09-09). 둘이 쓰는 앱이면 이것으로 충분합니다. 반대로 한 현업 백엔드 개발자는 Workers와 D1을 검토하다 쓰기는 한 곳으로 모이므로 "마스터 DB가 미국에 있다면 한국 유저가 댓글 달 때마다 미국 큐에 줄을 서야" 한다며, 쓰기가 많은 커뮤니티형은 Postgres 계열로, 조회 위주는 Workers와 D1로 나눠야 한다고 정리했습니다(네이버 블로그, 2026-07-01). 해외 커뮤니티의 반응은 더 거칩니다. 9월 r/CloudFlare의 아키텍처 질문에는 "D1은 악명 높게 불안정하다, Postgres로 바꾸라"는 답이 달렸습니다(r/CloudFlare, 2026-09-19). 판단 기준은 단순합니다. 데이터가 수 GB를 넘거나, 쓰기가 몰리거나, 벡터 검색이 필요하면 처음부터 Postgres로 갑니다. SQLite에서 Postgres로 옮기려면 스키마와 쿼리를 다시 손봐야 하고, 데이터가 쌓인 뒤의 이전은 처음에 고르는 것보다 훨씬 어렵습니다.

Neon과 Hyperdrive, Smart Placement

Postgres를 쓴다면 영상은 서버리스 Postgres인 Neon을 권합니다. 요청이 없으면 5분 뒤에 컴퓨트가 꺼지고, 요청이 오면 수백 ms 안에 다시 켜지며, 켜져 있던 시간만큼만 돈을 냅니다. 무료 플랜은 프로젝트당 저장 1GB와 월 100 CU-시간이고, 가장 작은 0.25 CU 사양이면 한 달에 400시간을 켜 둘 수 있습니다. 컴퓨트를 다 쓰면 다음 청구 주기까지 멈추고, 유료 플랜은 월 최소 요금 없이 쓴 만큼만 냅니다(Neon plans; Neon scale to zero, 2026-10-09 확인). 영상의 숫자와 모두 같습니다.

Workers에서 Neon에 붙을 때는 Hyperdrive를 같이 씁니다. Postgres는 연결을 맺을 때 TCP, TLS, 인증으로 왕복이 여러 번 생기는데, Hyperdrive는 DB 근처에 연결을 미리 열어 두고 재사용하며 자주 부르는 읽기 쿼리는 캐시에 둡니다. 무료 플랜에서도 하루 10만 쿼리까지 쓸 수 있습니다(How Hyperdrive works, 2026-07-05). Cloudflare의 Neon 연결 안내는 Neon 쪽 커넥션 풀링 체크를 끄고 직접 연결 문자열을 쓰라고 합니다. 풀링은 Hyperdrive가 하기 때문입니다(Hyperdrive, Neon). 한 가지 주의할 점은 캐시입니다. 앞의 r/CloudFlare 답변자는 Hyperdrive 캐시가 쓰기 직후에 이전 데이터를 돌려줄 수 있다고 경고했고, 공식 문서도 같은 내용을 적어 둡니다. Hyperdrive는 쓰기가 일어나도 캐시를 비우지 않아 기본 60초 동안 이전 결과를 줄 수 있습니다. 문서는 로그인, 세션, 권한, 결제 상태, 쓰기 직후 읽기처럼 최신 값이 필요한 읽기는 --caching-disabled로 만든 두 번째 Hyperdrive 설정을 따로 바인딩해 그쪽으로 보내라고 권합니다(Hyperdrive query caching).

Hyperdrive가 없을 때와 있을 때의 비교 도식. 왼쪽은 Worker가 최대 300ms 떨어진 지역 DB와 TCP, TLS, 인증을 위해 여러 번 왕복한 뒤에야 쿼리를 보낸다. 오른쪽은 Worker가 같은 지역의 Hyperdrive와 5~30ms 안에 연결하고, Hyperdrive는 DB와 이미 열어 둔 연결로 쿼리를 보내며 결과를 캐시할 수 있다
왼쪽은 Worker가 DB와 직접 연결을 맺는 경우, 오른쪽은 Hyperdrive가 미리 열어 둔 연결을 쓰는 경우입니다. 사용자가 기다리는 시간에서 연결 수립 왕복이 사라집니다. 출처: Cloudflare Docs, How Hyperdrive works

남는 문제는 거리입니다. Neon의 아시아 리전은 싱가포르와 시드니뿐이고 서울과 도쿄는 없습니다(Neon regions). 한 국내 개발자는 서울에서 Neon 싱가포르까지 왕복 70~90ms를 쟀습니다(velog y0ngha, 2026-10-06). 영상 화자의 계산대로 왕복 70ms짜리 쿼리를 열 번 부르는 페이지라면 이것만으로 0.7초가 쌓입니다. 이때 켜는 것이 Smart Placement입니다. Cloudflare 문서는 "Worker가 DB나 API 같은 백엔드에 여러 번 요청한다면 사용자보다 백엔드 가까이에서 실행하는 편이 빠를 수 있다"며, 켜 두면 트래픽을 분석해 Worker를 알맞은 곳에 둔다고 설명합니다. 분석에 최대 15분이 걸리고, HTTP 요청을 처리하는 fetch 핸들러에만 적용됩니다(Workers Placement, 2026-04-23). 사용자에서 Worker까지는 한 번, Worker에서 DB까지는 여러 번이라는 구조는 바이브코딩 배포가 느린 진짜 이유에서 Vercel 함수 리전으로 설명한 것과 같습니다.

두 개의 도식. 위쪽은 Smart Placement를 끈 경우로, 시드니 사용자가 시드니의 Worker에 요청하고 Worker는 프랑크푸르트의 DB와 여러 번 왕복한다. 아래쪽은 켠 경우로, 시드니 사용자의 요청이 프랑크푸르트의 Worker로 한 번 가고 Worker는 같은 프랑크푸르트의 DB와 가까이서 여러 번 왕복한다
위는 Smart Placement를 끈 경우, 아래는 켠 경우입니다. 먼 왕복을 여러 번 하던 구간이 한 번으로 줄어듭니다. Neon 싱가포르를 쓰는 한국 서비스라면 시드니 대신 서울, 프랑크푸르트 대신 싱가포르로 읽으면 됩니다. 출처: Cloudflare Docs, Placement

설정은 파일 하나에 모입니다. 아래는 Workers, Hyperdrive, R2, Smart Placement를 함께 쓰는 wrangler.jsonc의 예입니다.

{
  "name": "my-app",
  "main": "src/index.ts",
  "compatibility_date": "2026-10-01",
  // DB와 여러 번 왕복한다면 Worker를 DB 가까이에 둔다
  "placement": { "mode": "smart" },
  // 유료 플랜에서만 적용된다. 호출 한 번이 쓸 수 있는 CPU 시간 상한(ms)
  "limits": { "cpu_ms": 1000 },
  // `wrangler hyperdrive create`로 받은 id. 연결 문자열은 Neon의 직접 연결(풀링 끔)
  "hyperdrive": [{ "binding": "HYPERDRIVE", "id": "<HYPERDRIVE_ID>" }],
  "r2_buckets": [{ "binding": "FILES", "bucket_name": "my-app-files" }]
}

영상의 화자가 AI에게 한 줄로 주문하라고 한 문장도 이 구성입니다. "Workers로 만들고, DB는 Neon Postgres에 Hyperdrive로 붙이고, 파일은 R2에 저장해 줘." 한국 사용자 위주라면 Supabase 서울 리전도 같은 방식으로 Hyperdrive에 붙일 수 있습니다. 이때는 Supabase의 풀링 주소가 아니라 직접 연결 주소를 쓰라는 것이 Cloudflare의 안내입니다(Hyperdrive, Supabase).

팁 3. 이미지와 섬네일은 화면 크기에 맞춘다

AI에게 이미지 업로드를 만들어 달라고 하면 대부분 받은 원본을 그대로 저장하고 그대로 내려줍니다. 영상 화자가 직접 잰 값은 이렇습니다. 가로 4,032픽셀, 1,200만 화소 사진 한 장이 PNG로 10MB였고, WebP 화질 70으로 바꾸자 780KB, 가로 1,600픽셀로 줄이자 127KB가 됐습니다. 풀HD 영상 1분 100MB는 720p H.264로 다시 인코딩하자 3.5MB가 됐습니다. 목록용 섬네일은 가로 400픽셀, 화질 60이면 5KB입니다. 필자가 같은 파일로 다시 재지는 않았습니다. 화자의 수치는 PNG 원본과 비교한 것이라 차이가 특히 크고, Google이 밝힌 WebP의 효과는 같은 화질의 JPEG보다 25~34% 작은 정도입니다(Google for Developers, WebP). 그래도 가장 큰 절감은 형식보다 크기를 줄이는 데서 나옵니다.

기준을 원본이 아니라 화면에 두라는 것이 이 팁의 핵심입니다. 아이폰 13과 14의 화면은 가로 1,170픽셀입니다(Apple, iPhone 14 기술 사양). 4,000픽셀 사진을 내려 줘도 화면에는 1,170픽셀만큼만 보이고 나머지는 받기만 하고 버립니다. 그래서 저장할 때 크기별로 따로 만듭니다. 목록용 작은 섬네일 하나, 상세용 큰 이미지 하나를 두고, 원본은 보관만 합니다. AI에게는 "업로드한 이미지는 WebP로 바꾸고 가로 1600픽셀, 화질 75로 저장하고, 목록용 400픽셀 섬네일을 따로 만들어 줘"라고 하면 됩니다.

따로 만들기 귀찮으면 Cloudflare 이미지 변환을 씁니다. 이미지 주소 앞에 /cdn-cgi/image/width=400,quality=60,format=auto/처럼 옵션을 붙이면 그 크기로 줄여서 내려줍니다. 무료 플랜에서도 한 달에 고유 변환 5,000건까지 되고, 넘으면 이미 캐시된 변환은 계속 나가지만 새 변환은 9422 오류가 나며 요금은 붙지 않습니다. 원본이 같은 도메인에 있다면 onerror=redirect로 오류 대신 원본을 보내게 할 수 있습니다(Cloudflare Images pricing, 2026-07-08). 이미지 하나를 목록용과 상세용 두 크기로 변환하면 고유 변환 2건으로 세므로, 무료 한도로는 이미지 약 2,500장까지 쓸 수 있는 셈입니다. 첫 화면의 큰 이미지를 언제 받아 오느냐(LCP)까지 포함한 이미지 최적화 전반은 바이브코딩 배포가 느린 진짜 이유의 이미지 절에 정리했습니다.

팁 4. 한글 폰트는 Pretendard 다이나믹 서브셋

AI가 만든 페이지가 어딘가 싸 보이는 이유 중 하나는 폰트가 섞여서입니다. AI는 기본 글꼴로 Inter 같은 영문 폰트를 많이 고르는데, 여기에는 한글이 없습니다. 그러면 브라우저가 그 컴퓨터에 깔린 한글 폰트를 대신 씁니다. 윈도우에서는 맑은 고딕, 맥에서는 Apple SD 산돌고딕 Neo가 나오고, 한 문장 안에서 영문은 Inter, 한글은 다른 폰트라 굵기와 높이가 어긋납니다. 영상 화자는 "한국어 글씨는 제발 Pretendard 쓰세요"라고 말합니다.

Pretendard는 Inter와 본고딕(Source Han Sans), M PLUS 1p를 바탕으로 다듬은 폰트라 영문과 한글이 한 폰트처럼 맞춰져 있습니다. 9가지 굵기와 가변 폰트를 지원하고, SIL 오픈 폰트 라이선스라 글꼴만 따로 파는 것을 빼면 상업적으로 써도 됩니다(Pretendard GitHub).

흰 바탕에 영문 Pretendard와 한글 프리텐다드가 두 줄로 적혀 있고, 왼쪽의 가는 굵기부터 오른쪽의 굵은 굵기까지 글자마다 두께가 점점 굵어진다
Pretendard 저장소의 대표 이미지. 영문과 한글이 같은 굵기 단계로 이어집니다. 출처: orioncactus/pretendard, 길형진, SIL OFL 1.1

문제는 용량입니다. 현대 한글로 만들 수 있는 음절은 11,172자이고(Unicode Standard 3.12), 이 글자를 다 담은 Pretendard Regular 한 굵기의 woff2 파일은 jsDelivr에서 받아 보니 약 766KB였습니다. 모든 굵기를 담은 가변 폰트 파일은 약 2.1MB입니다. 그래서 다이나믹 서브셋을 씁니다. 글자를 92개 조각으로 나눠 두고, 페이지에 실제로 나온 글자가 들어 있는 조각만 받는 방식입니다. 정적 Regular 조각은 하나에 4~20KB, 평균 약 12.6KB이고, 모든 굵기를 담은 가변 폰트 조각은 그보다 2.5배쯤 큽니다.

필자가 이 글 본문으로 직접 계산해 봤습니다. 본문에는 서로 다른 한글 음절이 598자 나오고, 필요한 조각은 92개 중 26개였습니다. 정적 Regular 한 굵기라면 약 301KB로 전체 파일의 39%, 가변 폰트라면 약 709KB로 전체 파일의 34%입니다. 글이 이보다 짧은 페이지라면 받는 조각은 더 적어집니다.

이 글을 Pretendard로 그릴 때 받는 폰트 용량
이 글 본문의 글자를 다이나믹 서브셋 CSS의 unicode-range와 대조해 필요한 조각을 셌습니다. 92조각을 모두 받으면 정적 Regular는 1,162KB, 가변은 2,958KB로 오히려 전체 파일보다 커지므로, 다이나믹 서브셋은 페이지마다 일부 글자만 쓰는 보통의 웹페이지에서 이득입니다. 계산 스크립트는 "이 글의 자료를 고른 방법"에 적었습니다. 출처: Pretendard v1.3.9 파일을 jsDelivr에서 받아 필자가 계산

적용은 링크 한 줄입니다. 본문과 제목에 굵기를 한두 개만 쓴다면 정적 다이나믹 서브셋이 가볍고, 굵기를 여러 개 쓴다면 가변 다이나믹 서브셋 하나로 모든 굵기를 받는 편이 낫습니다. 정적 버전은 페이지에서 쓰는 굵기마다 조각을 따로 받기 때문입니다.

<!-- 굵기를 한두 개만 쓸 때: 정적 다이나믹 서브셋 -->
<link rel="stylesheet" as="style" crossorigin
  href="https://cdn.jsdelivr.net/gh/orioncactus/[email protected]/dist/web/static/pretendard-dynamic-subset.min.css" />
<!-- 굵기를 여러 개 쓸 때: 가변 다이나믹 서브셋 (font-family는 "Pretendard Variable") -->
<!-- <link rel="stylesheet" as="style" crossorigin
  href="https://cdn.jsdelivr.net/gh/orioncactus/[email protected]/dist/web/variable/pretendardvariable-dynamic-subset.min.css" /> -->
<style>
  body { font-family: Pretendard, "Pretendard Variable", -apple-system, sans-serif; }
</style>

국내 개발자들의 기록도 같습니다. 정적 CSS로 700KB가 넘는 폰트 파일 5개, 약 3,500KB를 받던 페이지가 다이나믹 서브셋으로 바꾸자 400~500KB로 줄었다는 글이 있고(velog apparatus1, 2023-09-11), Next.js에서 next/font/local로 넣으면 조각별 unicode-range를 줄 수 없어 자주 쓰이는 조각 5개만 직접 preload했다는 글도 있습니다(velog cncn0069, 2026-06-14). AI에게 "폰트를 next/font로 바꿔 줘"라고 하면 이 함정에 빠질 수 있으니, "Pretendard 다이나믹 서브셋 CSS를 link로 넣어 줘"라고 구체적으로 말하는 편이 낫습니다.

팁 5. 키는 코드에 넣지 않는다: 5분이면 털린다

영상의 첫 장면은 2014년의 일입니다. 한 개발자가 GitHub 공개 저장소에 키를 올렸다가 약 5분 만에 정리하고 잠들었는데, 다음 날 아침 아마존에서 메일 네 통과 부재중 전화가 와 있었고 계정에서 서버 140대가 돌고 있었습니다. 청구액은 2,375달러였고 아마존이 취소해 줬습니다. 원글은 DevFactor 블로그의 "My $2375 Amazon EC2 Mistake"이며, 작성자는 유출된 것이 Rails 설정 파일에 들어 있던 S3 키라고 적었습니다(DevFactor, 아카이브, 2014-12-30; The Register, 2015-01-06).

12년 전 이야기지만 속도는 지금도 같습니다. Palo Alto Networks의 Unit 42는 2023년에 일부러 AWS 키를 GitHub에 노출해 공격자를 관찰했고, "공격자가 GitHub에 처음 노출된 지 5분 안에 자격 증명을 찾아 썼다"고 보고했습니다. 이 실험에서는 GitHub가 AWS에 자동으로 알려 AWS가 2분 안에 격리 정책을 붙였는데, 연구팀은 관찰을 위해 그 정책을 일부러 떼어 냈습니다. 이 캠페인 전체로는 2023년 8월 30일부터 10월 6일까지 서로 다른 채굴기 474개가 관측됐습니다(Unit 42, 2023-10-30).

AWS CloudTrail 이벤트 목록. 2023년 8월 29일 13시 30분 22초에 AWS Internal이 AttachUserPolicy로 격리 정책을 붙였고, 13시 34분 6초부터 python-requests로 GetCallerIdentity가 반복 호출된 뒤, 13시 34분 15초부터 PowerShell로 DescribeRegions, DescribeInstanceTypes, DescribeVpcs, DescribeSecurityGroups 정찰 호출이 이어진다
Unit 42가 노출한 AWS 키의 CloudTrail 기록. 아래에서 위로 읽습니다. AWS가 격리 정책을 붙이고(13:30:22) 4분이 지나기 전에 공격자의 자동화 도구가 키를 확인하고 리전과 인스턴스 종류를 훑기 시작했습니다. 출처: Palo Alto Networks Unit 42, EleKtra-Leak

이런 일이 드물지도 않습니다. GitGuardian은 2025년 한 해 공개 GitHub 커밋에 새로 하드코딩된 시크릿이 2,865만 건으로 전년보다 34% 늘었다고 집계했습니다(GitGuardian, State of Secrets Sprawl 2026, 2026-03-17). 바이브코딩에서는 경로가 더 많습니다. AI가 테스트한다며 키를 코드에 직접 넣기도 하고, .env가 같이 커밋되기도 하고, 프런트엔드 코드에 들어간 키는 브라우저에서 누구나 열어 봅니다. 한 국내 개발자는 공공데이터 API 키가 앱 번들 안에 압축도 안 된 채 들어 있어 누구나 읽을 수 있다는 것을 알고, Worker를 프록시로 세워 키를 wrangler secret put으로 옮겼습니다(네이버 블로그, 2026-09-30). 다른 국내 개발자는 AWS가 건 국제전화를 보이스피싱으로 알고 받지 않았다가 1,755만 원이 청구된 것을 뒤늦게 알았습니다(velog ysung327, 2021-09-03).

GitHub의 방어선도 알아 둘 만합니다. GitHub는 2024년 2월부터 공개 저장소로 가는 푸시에 시크릿 푸시 보호(push protection)를 기본으로 켰습니다. 알려진 형식의 키가 들어 있으면 푸시를 막지만, 사용자가 이유를 고르고 우회할 수 있습니다(GitHub Blog, 2024-02-29; GitHub Docs). 이미 올라간 키는 GitHub가 AWS 같은 발급처에 알려 줍니다. 그래도 마지막 방어선은 습관입니다.

  1. 키는 지우는 것이 아니라 폐기하고 새로 발급합니다. 파일을 지워도 커밋 기록에 남습니다. 한 국내 개발자는 저장소를 공개로 바꾸자마자 노출 경고를 받았고, 기록을 고치려다 포기하고 키를 비활성화한 뒤 재발급했습니다(velog woals3000, 2021-12-11).
  2. 키는 코드가 아니라 시크릿 저장소에 둡니다. Cloudflare에서는 wrangler secret put, 로컬에서는 .gitignore에 넣은 .dev.vars나 .env를 씁니다. 키를 채팅창에 붙여 넣지 않는 것도 같은 원칙입니다.
  3. AWS를 써야 한다면 루트 계정으로 키를 만들지 않고, 첫날 예산 알림을 겁니다. AWS 예산 알림은 기본으로 알림만 보내고 실제 사용보다 늦게 올 수 있습니다(AWS Budgets). 영상 화자가 "AWS는 바이브 코더에게 사치"라고까지 말한 이유이고, 숨은 비용 구조는 서버를 이제 AWS에 올리지 않는 이유에 따로 정리했습니다.

팁 6. CLI를 깔고 에이전트에게 로그를 보게 한다

CLI가 없으면 사람이 AI와 대시보드 사이에서 복사와 붙여 넣기만 하게 됩니다. "대시보드에서 이 메뉴를 누르고 이 값을 복사해 오세요"라는 안내가 반복됩니다. Cloudflare의 CLI인 wrangler가 깔려 있으면 에이전트가 배포, 시크릿 등록, DB 조회, 로그 확인을 직접 합니다. 영상 화자가 가장 크게 체감했다는 것은 로그입니다. 배포한 서비스에서 에러가 나면 에이전트가 실시간 로그를 열어 원인을 찾고, 사람은 에러 메시지를 복사해 줄 필요가 없습니다.

npx wrangler login                          # 브라우저 창에서 승인만 누른다
npx wrangler secret put NEON_DATABASE_URL   # 키는 대화창이 아니라 여기로
npx wrangler hyperdrive create my-db --connection-string="postgres://..."
npx wrangler deploy                         # 배포
npx wrangler tail                           # 배포한 Worker의 실시간 로그
npx wrangler d1 execute my-db --remote --command "SELECT count(*) FROM users"

명령은 모두 wrangler 공식 문서에 있는 그대로입니다. wrangler login은 OAuth로 브라우저를 열어 승인받는 방식이라 API 키를 복사해 채팅창에 붙일 일이 없습니다. 한 국내 블로거는 Codex에게 집 서버 블로그를 Workers와 Supabase로 옮기게 했는데, 에이전트가 시킨 순서가 정확히 wrangler login, 그다음 wrangler secret put이었고 "민감한 정보는 대화창에 입력하지 않고 로컬에 저장"했다고 적었습니다(네이버 블로그, 2026-07-22).

에이전트가 백그라운드에서 wrangler를 돌릴 때는 로그인이 걸림돌이 됩니다. 다른 국내 개발자는 Timed out waiting for authorization code, The consent verifier has already been used, localhost 8976 포트 연결 거부를 차례로 겪고 OAuth 대신 API 토큰으로 바꿨습니다(velog riririb, 2026-09-21). 토큰을 쓸 때는 권한을 필요한 계정과 제품으로 좁힙니다. 읽기 권한으로 시작하고 쓰기 권한은 범위를 좁혀 주는 원칙은 Claude Opus 5.5 잘 쓰는 법에서 정리한 것과 같습니다.

CLI 자체도 바뀌는 중입니다. Cloudflare는 9월 28일 에이전트를 위한 새 CLI cf를 공개했습니다. wrangler가 다루는 작업은 약 280개인데 cf는 Cloudflare API 전체, 3,000개가 넘는 작업을 다루는 것이 목표입니다. 베타가 끝나면 wrangler는 cf를 안내하는 마지막 메이저 버전을 내고 18개월 동안 유지보수만 합니다(Cloudflare Blog, 2026-09-28). 해커뉴스 반응은 "혼자 Worker를 배포하는 개발자에게 좋다"는 쪽과 "CLI 의존성 관리를 사용자에게 떠넘기지 말라"는 쪽으로 갈렸습니다(Hacker News). 지금 시작한다면 wrangler로 충분하고, cf가 정식으로 나오면 옮기면 됩니다. Vercel, Supabase, Neon, GitHub도 CLI가 있으니 쓰는 서비스의 CLI는 처음부터 깔아 둡니다.

팁 7. CDN 주소는 코드 한 곳에서 만든다

CDN을 붙였는데 코드가 여전히 원본 주소로 이미지를 부르면 CDN은 하나도 쓰이지 않습니다. DB에 원본 저장소의 전체 주소가 박혀 있으면 화면은 계속 그 주소로 요청합니다. 영상 화자는 세 가지를 바꾸라고 합니다.

  1. DB에는 전체 주소 대신 파일 키만 저장합니다. 앞에 붙는 CDN 주소는 환경 변수 하나로 관리하면 CDN을 바꿀 때 한 줄만 고치면 됩니다.
  2. 이미지 주소를 만드는 함수를 하나로 모읍니다. 목록에서는 작은 크기, 상세에서는 큰 크기를 이 함수가 붙입니다.
  3. 파일 내용을 바꾸면 이름도 바꿉니다. CDN은 주소가 같으면 캐시가 끝날 때까지 예전 파일을 내려줍니다. 파일 이름에 내용의 해시를 붙이면 내용이 바뀔 때 주소도 바뀌므로 캐시를 1년으로 걸어도 안전합니다. MDN은 이것을 "캐시 버스팅" 패턴이라 부르고, 해시가 붙은 파일에 max-age=31536000, immutable을, HTML에는 no-cache를 권합니다(MDN Cache-Control).

Workers와 R2로 쓰면 다음과 같습니다.

// 업로드: 앞 단계에서 WebP로 줄인 바이트를 받아, 내용의 해시를 파일 이름으로 쓰고 1년 캐시를 건다
async function saveImage(env: Env, bytes: ArrayBuffer): Promise<string> {
  const digest = await crypto.subtle.digest("SHA-256", bytes);
  const hash = [...new Uint8Array(digest)].slice(0, 8)
    .map((b) => b.toString(16).padStart(2, "0")).join("");
  const key = `images/${hash}.webp`;
  await env.FILES.put(key, bytes, {
    httpMetadata: { contentType: "image/webp", cacheControl: "public, max-age=31536000, immutable" },
  });
  return key; // DB에는 이 키만 저장한다
}

// 화면: 주소는 이 함수 하나에서만 만든다
export function imageUrl(cdnBase: string, key: string, size: "thumb" | "full"): string {
  const opts = size === "thumb" ? "width=400,quality=60" : "width=1600,quality=75";
  return `${cdnBase}/cdn-cgi/image/${opts},format=auto/${key}`;
}

국내에도 이 순서를 그대로 밟은 기록이 있습니다. 여행 기록 사이트를 만든 한 블로거는 처음에 Worker가 사진 요청을 받아 R2에서 꺼내 주게 했다가, 사진 한 장이 Worker 실행 한 번이라 페이지당 사진이 100장 넘는 구조에서 하루 10만 건 한도가 걱정돼 R2 버킷에 커스텀 도메인을 붙여 CDN 캐시로 직접 내보내도록 바꿨습니다. 사진은 30일 캐시를 걸고, 같은 이름으로 교체할 때는 그 주소만 캐시를 비웠으며, 옛 주소는 Worker가 301로 넘겼습니다(네이버 블로그, 2026-09-28). 하나 더 확인할 것은 Cloudflare DNS의 프록시 표시입니다. 한 국내 개발자는 네임서버를 Cloudflare에 두고도 프록시(주황 구름)가 꺼져 있어 방화벽과 봇 차단이 작동하지 않았고, 그사이 봇 요청이 Vercel 청구서를 키웠다고 적었습니다. 프록시를 끈 것은 Vercel이 그렇게 권했기 때문이었습니다(velog y0ngha, 2026-10-06). Vercel처럼 자체 CDN이 있는 호스팅 앞에 Cloudflare 프록시를 다시 켤지는 양쪽 안내를 보고 득실을 따져야 합니다. 반대로 R2나 Workers처럼 Cloudflare 안에서 내보내는 파일이라면 처음부터 Cloudflare CDN을 거칩니다.

한국에서는 어느 데이터센터가 응답하나

Cloudflare가 "사용자 가까이"에서 응답한다고 해도, 한국 사용자에게 그곳이 늘 서울은 아닙니다. 필자는 2026년 10월 9일 밤 사무실 유선 회선에서 Cloudflare 뒤에 있는 사이트 다섯 곳에 /cdn-cgi/trace를 요청해 응답한 데이터센터를 확인하고, TCP 연결 시간을 15번씩 쟀습니다. colo= 값은 응답한 데이터센터의 공항 코드입니다.

국내 회선에서 본 Cloudflare 응답 위치와 연결 시간
막대 길이는 연결 시간에 비례합니다. hono-dev.pages.dev는 hono.dev와 다른 사이트입니다. 회선 한 곳, 한 시각의 값이라 통신사와 시간대에 따라 달라집니다. 측정 명령은 아래 "이 글의 자료를 고른 방법"에 적었습니다.

Cloudflare 자체 사이트, astro.build, Pages 기본 주소(*.pages.dev)는 모두 서울에서 17~19ms에 응답했습니다. 같은 날 따로 잰 다른 *.pages.dev 주소 두 곳도 서울이었습니다. 반면 웹 프레임워크 Hono의 공식 문서 hono.dev와 필자가 운영하는 aviss.kr은 로스앤젤레스에서 약 141ms에 응답했습니다. 연결 한 번에 약 120ms가 더 붙는 셈이고, HTTPS는 연결을 맺을 때 왕복이 여러 번 생기므로 캐시되지 않은 첫 요청에서 체감됩니다. 한 국내 개발자도 무료 플랜에서 서울이 아닌 해외 데이터센터로 붙어 128ms가 더 걸렸다고 보고한 적이 있고(velog im_h_jo, 2025-01-18), 바이브코딩 배포가 느린 진짜 이유에서는 R2 이미지가 홍콩을 거쳐 0.3초 걸렸다는 2023년 측정을 소개했습니다. 2026년 10월 필자의 측정에서는 홍콩이 아니라 로스앤젤레스였습니다. Cloudflare는 어떤 요금제의 요청을 어느 데이터센터로 보내는지 공식 문서로 밝히지 않으므로 원인은 단정할 수 없습니다. 다만 한국 사용자 위주의 서비스라면 배포한 뒤에 curl https://내도메인/cdn-cgi/trace를 한 번 보내 colo=가 ICN인지 확인해 보길 권합니다. 지연에 민감한 API라면 같은 프로젝트를 *.pages.dev나 *.workers.dev 기본 주소와 커스텀 도메인으로 나란히 재 보고, 가능하면 다른 통신사 회선에서도 확인한 뒤 고르는 것이 안전합니다.

Cloudflare가 안 맞는 경우

영상 화자도 "이 조합이 정답이 아닌 경우가 있다"며 세 가지를 들었고, 공식 문서로 확인하니 그중 일부는 지금 기준으로 바뀌었습니다. 여기에 앞에서 본 비용과 장애 이야기를 더하면 다음과 같습니다.

  • 무거운 계산. Workers 무료 플랜은 요청 하나에 CPU 시간 10ms이고, 유료는 기본 30초, 최대 5분까지 늘릴 수 있습니다. 메모리는 isolate 하나에 128MB입니다(Workers limits). 한 국내 개발자는 Cloudflare Pages에 인증 라이브러리를 붙였다가 CPU 시간 한도 오류가 계속 나서 비밀번호 해싱을 별도 Worker로 떼어 냈고, 무료 플랜에서는 Argon2id 기본 설정이 버거울 수 있다며 무료용 설정을 따로 뒀습니다(긱뉴스, 2026-03 무렵). 몇 분씩 도는 작업은 Railway 같은 일반 서버가 편합니다.
  • Node.js 전용 패키지. 호환성 날짜를 2026년 8월 4일 이후로 잡으면 Node.js 호환 모드가 기본으로 켜집니다. 그래도 child_process는 불러올 수만 있고 동작하지 않으며, fs는 요청마다 사라지는 메모리 기반 가상 파일 시스템입니다(Workers Node.js, 2026-08-12). 그보다 오래된 날짜로 만든 프로젝트에서는 nodejs_compat 플래그를 직접 넣어야 하고, 빠뜨리면 supabase-js가 internal error; reference = ...라는 알 수 없는 오류를 냅니다(velog jtnoh300, 2025-12-01).
  • 고정 IP가 필요한 외부 API. 결제나 금융 API가 서버 IP를 등록하라고 하면 일반 플랜의 Workers로는 맞출 수 없습니다. 계정 전용 송신 IP는 Enterprise 고객에게만 제공되고, 그 밖의 고객은 Cloudflare 공용 대역(172.64.0.0/13)을 함께 씁니다(Cloudflare Dedicated egress IPs). 이 부분만 일반 서버로 빼면 됩니다.
  • Neon 무료 플랜의 첫 요청. 5분 동안 요청이 없으면 컴퓨트가 꺼지고, 다시 켜질 때 수백 ms가 걸립니다. 무료 플랜은 이 기능을 끌 수 없고 유료 플랜에서는 끌 수 있습니다.
  • 유료 플랜의 상한 없는 청구. 앞에서 본 대로입니다. 하드 캡이 나오기 전까지는 CPU 한도와 예산 알림으로 대신합니다.
  • 한 회사에 모두 거는 위험. 2025년 11월 18일 Cloudflare는 데이터베이스 권한 변경으로 봇 관리용 설정 파일의 크기가 두 배가 되면서 전 세계에서 장애를 냈습니다. 핵심 트래픽은 약 3시간 뒤에 대부분 돌아왔고 완전 복구까지는 약 6시간이 걸렸습니다(Cloudflare Blog). 12월 5일에는 약 25분 동안 HTTP 트래픽의 약 28%가 영향을 받았습니다(Cloudflare Blog). 12월 장애 때는 배달의민족이 약 10분 동안 접속 장애를 겪었고 업비트도 영향을 받았습니다(디지털데일리, 2025-12-05). 그런데도 긱뉴스에는 "정직한 사후보고서 덕분에 클라우드플레어를 계속 쓸 것 같다"는 댓글이 달렸습니다(긱뉴스, 2025-11-18).

그래서 "바이브 코더 99%는 Cloudflare 하나면 충분하다"는 말은 이렇게 고쳐 읽는 것이 정확합니다. 요청을 받고 DB를 읽고 응답하는 가벼운 웹앱이라면 충분하고, 무료 플랜에 머무는 동안은 청구서 걱정도 없다. 다만 무거운 계산, 고정 IP, 한국 사용자 대상의 낮은 지연이 필요하거나 유료로 올린다면 그 부분은 따로 챙겨야 한다. 전부 옮길 필요는 없고 걸리는 부분만 일반 서버로 빼면 됩니다. 영상 화자도 정작 본인의 서버와 DB는 Railway에 올려 쓰고 있다고 말합니다.

이 글의 자료를 고른 방법

이 글은 2026년 10월 9일에 확인한 자료로 썼습니다. Workers, R2, D1, Hyperdrive, Images, Placement의 한도와 가격은 Cloudflare 개발자 문서를 직접 열어 문장을 대조했고, 문서에 표시된 수정일을 함께 적었습니다. Neon의 플랜과 리전은 Neon 문서, 키 유출 통계는 GitGuardian 보고서, 키 악용 속도는 Unit 42 원문, GitHub 푸시 보호는 GitHub 블로그와 문서를 썼습니다. 2,375달러 일화의 원글은 현재 열리지 않아 인터넷 아카이브와 당시 The Register 보도로 확인했습니다.

영상의 숫자는 대부분 맞았습니다. 고쳐 쓴 것은 다음과 같습니다. D1의 10GB는 유료 플랜 기준이고 무료는 DB당 500MB입니다. Node.js 호환 플래그는 호환성 날짜가 2026년 8월 4일 이후인 프로젝트에서는 기본으로 켜집니다. 2,375달러 일화는 2014년 일이고 유출된 키는 작성자 표현으로 S3 키였습니다. "한도를 넘으면 멈춘다"는 무료 플랜에만 해당하고 R2 초과분과 유료 플랜은 과금된다는 단서를 붙였습니다. 이미지와 영상 압축 수치(10MB에서 127KB, 100MB에서 3.5MB, 섬네일 5KB)는 화자의 측정이고 필자가 다시 재지 않았습니다.

응답 데이터센터와 연결 시간은 다음 명령으로 쟀습니다.

for u in https://hono.dev https://hono-dev.pages.dev https://aviss.kr https://developers.cloudflare.com https://astro.build; do
  colo=$(curl -s -A "Mozilla/5.0" $u/cdn-cgi/trace | grep '^colo=')
  med=$(for i in $(seq 1 15); do curl -so /dev/null -A "Mozilla/5.0" -w '%{time_connect}\n' $u/cdn-cgi/trace; done \
    | sort -n | awk '{a[NR]=$1} END{printf "%.1f", a[int((NR+1)/2)]*1000}')
  echo "$u $colo ${med}ms"
done

Pretendard 용량은 jsDelivr에서 v1.3.9 파일을 직접 받아 바이트 수를 셌습니다. 이 글에 필요한 조각 수는 원고에서 머리말, 코드 블록, SVG, 링크 주소를 뺀 본문 글자를 다이나믹 서브셋 CSS의 unicode-range와 대조해 셌습니다. 계산 스크립트(font-subset-calc.py)는 CSS와 조각 파일을 내려받아 정적 Regular와 가변 폰트 두 경우를 모두 계산하며, 원고를 고칠 때마다 다시 돌려 숫자를 맞췄습니다.

최근 30일(2026년 9월 9일~10월 9일) 커뮤니티 반응은 레딧, 해커뉴스, X, dev.to를 봤고, 10,811달러 사례는 당사자의 X 게시물 원문과 정리 글을 함께 확인했습니다. 레딧 일부 게시판과 Medium은 자동 수집이 막혀 읽지 못했습니다. 국내 블로그(네이버 블로그, velog, 브런치)와 긱뉴스 댓글은 개인 경험으로만 소개했고, 가격이나 한도 같은 사실 주장의 근거로는 쓰지 않았습니다. 요금 비교표나 강의 홍보 성격이 강한 글은 뺐습니다. Hyperdrive와 Neon을 함께 쓴 국내 후기는 찾지 못했습니다.

본문의 이미지는 직접 만든 차트 2개와 섬네일을 빼면 Cloudflare 개발자 문서, Unit 42 보고서, Pretendard 저장소의 원본 이미지이고, 해당 자료를 소개하려고 인용하면서 캡션에 출처를 달았습니다. 섬네일의 일러스트는 이미지 생성 AI로 만들었고, 제목과 로고는 따로 얹었습니다.

필자의 한계. 필자는 이 글의 7가지 구성을 하나의 서비스로 직접 운영해 청구서를 받아 본 것은 아닙니다. 필자가 확인한 것은 공식 문서의 한도와 가격, 그리고 한 회선에서 잰 응답 위치입니다. 데이터센터 측정은 통신사와 시점에 따라 결과가 다를 수 있고, aviss.kr과 hono.dev가 어떤 요금제를 쓰는지에 따른 차이는 확인하지 못했습니다.

자주 묻는 질문

Workers 무료 플랜에서 하루 한도를 넘으면 사이트 전체가 멈추나요?

Worker가 처리하는 요청만 막힙니다. 하루 10만 건을 넘으면 Worker 요청에 Error 1027이 돌아가고, 한국 시간 오전 9시(UTC 자정)에 다시 채워집니다. 정적 파일 요청은 무료이고 무제한이라 이 한도에 들어가지 않습니다. 설정에 따라서는 넘었을 때 Worker를 건너뛰고 요청을 그대로 통과시키는 fail open으로 둘 수도 있습니다. 보안 검사를 하는 Worker라면 반대로 막는 쪽(fail closed)이 맞습니다.

유료 플랜으로 올린 뒤 요금 폭탄을 막으려면 어떻게 하나요?

2026년 10월 현재는 하드 캡이 없으므로 세 가지로 대신합니다. 설정 파일의 limits.cpu_ms로 호출당 CPU 시간 상한을 걸고, 예산 알림 기준을 낮게 잡고, Durable Objects 알람이나 큐 재시도처럼 스스로 다시 실행되는 코드에 종료 조건이 있는지 사람이 확인합니다. Cloudflare는 하드 캡을 2026년 4분기에 조기 제공하겠다고 밝혔으니, 나오면 바로 켜는 것이 좋습니다.

R2 무료 한도를 넘으면 어떻게 되나요?

Workers 무료 플랜처럼 멈추지 않고 넘은 만큼 청구됩니다. R2는 처음 쓸 때 결제 절차를 거쳐 구독을 만들어야 하고, 매달 저장 10GB, Class A 요청 100만 건, Class B 요청 1,000만 건을 넘는 사용량은 그대로 청구서에 올라갑니다. 저장은 GB당 월 0.015달러이고 egress는 무료라 이미지와 영상을 많이 내보내는 서비스일수록 유리하지만, 업로드나 덮어쓰기처럼 쓰기 요청이 많은 구조라면 Class A 요청 수를 먼저 계산해 보세요. 사진을 Worker를 거치지 않고 R2 커스텀 도메인으로 직접 내보내면 Worker 요청 수도 함께 줄어듭니다.

Next.js 앱도 Workers에 올릴 수 있나요?

올릴 수 있습니다. Cloudflare 문서는 2026년 8월 기준으로 Next.js API를 Vite 위에서 다시 구현한 vinext를 Workers에서 Next.js를 돌리는 기본 방법으로 권하고, 기존 OpenNext 경로도 안내합니다. vinext는 아직 베타라, 문서는 운영 중인 앱에 적용하기 전에 호환성 검사(npx vinext check)부터 하라고 안내합니다(Cloudflare Docs, Next.js, 2026-08-25). Next.js 기능을 많이 쓰는 앱이라면 Vercel에 두는 편이 덜 번거로울 수 있습니다.

한국 사용자만 상대한다면 Neon 대신 무엇을 쓰나요?

Neon은 아시아 리전이 싱가포르와 시드니뿐이고, 한 국내 개발자의 측정으로는 서울에서 싱가포르까지 왕복 70~90ms였습니다. 서울 리전이 있는 Supabase Postgres(Supabase Docs, Regions)를 Hyperdrive로 붙이는 방법이 있고, Cloudflare 문서에 연결 안내가 있습니다. 어느 쪽이든 Smart Placement를 켜서 Worker를 DB 가까이에 두면 쿼리 왕복이 짧아집니다.

마치며

왜 다들 Cloudflare로 가는지 한 줄로 줄이면 무료 플랜이 한도를 넘으면 요금 대신 멈추기 때문이고, 그 바닥은 월 5달러를 내는 순간 사라진다는 것입니다.

  • 코드는 Workers, 파일은 R2에 두면 리전을 고를 필요가 없고, 무료 플랜은 하루 10만 요청을 넘으면 오류로 멈춥니다.
  • R2 초과분과 유료 플랜은 상한 없이 과금됩니다. 하드 캡이 나오기 전까지는 CPU 한도와 예산 알림, 반복 코드 점검으로 막습니다.
  • 커질 서비스라면 D1 대신 Postgres를 Hyperdrive로 붙이고 Smart Placement를 켭니다.
  • 이미지는 화면 크기에 맞춰 줄이고, 한글은 Pretendard 다이나믹 서브셋을 씁니다.
  • 키는 시크릿 저장소에 두고, 유출되면 지우지 말고 폐기합니다. CLI를 깔아 에이전트가 직접 배포하고 로그를 보게 합니다.
  • CDN 주소는 함수 하나에서 만들고 파일 이름에 해시를 붙입니다. 배포한 뒤에는 colo=가 ICN인지 확인합니다.

Cloudflare가 하드 캡을 내놓거나 무료 플랜 한도가 바뀌면 이 글을 갱신하겠습니다.

sources:auto

출처

  1. 왜 다들 클라우드플레어로 갈까: youtube.com/watch?v=c7IM7r3ZPLI
  2. 네이버 블로그, 2026-08-30: blog.naver.com/babydreamer5/224395034913
  3. r/vibecoding, 2026-09-17: reddit.com/r/vibecoding/comments/1wiilbk/vibecoding_stack
  4. Cloudflare Blog, 2026-09-28: blog.cloudflare.com/cloudflare-cf-cli-launch
  5. Cloudflare Workers limits, 2026-10-08: developers.cloudflare.com/workers/platform/limits
  6. Cloudflare Workers pricing, 2026-10-02: developers.cloudflare.com/workers/platform/pricing
  7. Cloudflare R2 pricing, 2026-10-01: developers.cloudflare.com/r2/pricing
  8. D1 pricing: developers.cloudflare.com/d1/platform/pricing
  9. Hyperdrive pricing: developers.cloudflare.com/hyperdrive/platform/pricing
  10. Cloudflare Images pricing, 2026-07-08: developers.cloudflare.com/images/pricing
  11. Neon plans: neon.com/docs/introduction/plans
  12. R2 get started: developers.cloudflare.com/r2/get-started
  13. Cloudflare Budget alerts: developers.cloudflare.com/billing/manage/budget-alerts
  14. Changelog, 2026-07-20: developers.cloudflare.com/changelog/post/2026-06-15-budget-alerts-defau…
  15. @shmily7, 2026-10-06: x.com/shmily7/status/2107481028726251762
  16. 후속 글, 2026-10-08: x.com/shmily7/status/2108060782302990699
  17. aiidelist, 2026-10-08: aiidelist.com/blog/cloudflare-10811-bill-codex-durable-objects-alarm-lo…
  18. dev.to, 2026-09-23: dev.to/howardzlh/why-cloudflare-bills-spike-8-d1-and-durable-objects-ca…
  19. gfuse.dev, 2026-09-16: gfuse.dev/one-hour-of-bots-on-cloudflare-workers
  20. Cloudflare Blog, 2026-10-02: blog.cloudflare.com/enterprise-for-all-update
  21. r/CloudFlare, 2026-10-04: reddit.com/r/CloudFlare/comments/1wxdo7p
  22. AWS News Blog, 2026-09-16: aws.amazon.com/blogs/aws/aws-reimagines-the-getting-started-experience
  23. D1 limits, 2026-04-21: developers.cloudflare.com/d1/platform/limits
  24. D1 SQL statements: developers.cloudflare.com/d1/sql-api/sql-statements
  25. 네이버 블로그, 2026-09-09: blog.naver.com/re_vuer/224406040372
  26. 네이버 블로그, 2026-07-01: blog.naver.com/senshig/224332482255
  27. r/CloudFlare, 2026-09-19: reddit.com/r/CloudFlare/comments/1wkjxd1/architecture_review_single_sha…
  28. Neon scale to zero: neon.com/docs/introduction/scale-to-zero
  29. Cloudflare Docs, How Hyperdrive works, 2026-07-05: developers.cloudflare.com/hyperdrive/concepts/how-hyperdrive-works
  30. Hyperdrive, Neon: developers.cloudflare.com/hyperdrive/examples/connect-to-postgres/postg…
  31. Hyperdrive query caching: developers.cloudflare.com/hyperdrive/concepts/query-caching
  32. Neon regions: neon.com/docs/introduction/regions
  33. velog y0ngha, 2026-10-06: velog.io/@y0ngha/Vercel-월-345에서-AWS-월-60까지-청구서의-80였던-ISR전송-요금-그리고-옮긴-뒤-…
  34. Cloudflare Docs, Placement, 2026-04-23: developers.cloudflare.com/workers/configuration/placement
  35. Hyperdrive, Supabase: developers.cloudflare.com/hyperdrive/examples/connect-to-postgres/postg…
  36. Google for Developers, WebP: developers.google.com/speed/webp
  37. Apple, iPhone 14 기술 사양: support.apple.com/en-us/111850
  38. orioncactus/pretendard: github.com/orioncactus/pretendard
  39. Unicode Standard 3.12: unicode.org/versions/Unicode18.0.0/core-spec/chapter-3
  40. velog apparatus1, 2023-09-11: velog.io/@apparatus1/web-font
  41. velog cncn0069, 2026-06-14: velog.io/@cncn0069/Pretendard-92분할-폰트-nextfontlocal-대신-link-relpreload를…
  42. DevFactor, 아카이브, 2014-12-30: web.archive.org/web/20150107051102/http://www.devfactor.net:80/2014/12/…
  43. The Register, 2015-01-06: theregister.com/security/2015/01/06/dev-put-aws-keys-on-github-then-bad…
  44. Palo Alto Networks Unit 42, EleKtra-Leak, 2023-10-30: unit42.paloaltonetworks.com/malicious-operations-of-exposed-iam-keys-cr…
  45. GitGuardian, State of Secrets Sprawl 2026, 2026-03-17: blog.gitguardian.com/the-state-of-secrets-sprawl-2026
  46. 네이버 블로그, 2026-09-30: blog.naver.com/mummumni/224426555442
  47. velog ysung327, 2021-09-03: velog.io/@ysung327/AWS-1700만원-요금폭탄-맞았다
  48. GitHub Blog, 2024-02-29: github.blog/news-insights/product-news/keeping-secrets-out-of-public-re…
  49. GitHub Docs: docs.github.com/en/code-security/concepts/secret-security/push-protecti…
  50. velog woals3000, 2021-12-11: velog.io/@woals3000/이슈-AWS-Access-key-노출
  51. AWS Budgets: docs.aws.amazon.com/cost-management/latest/userguide/budgets-managing-c…
  52. wrangler 공식 문서: developers.cloudflare.com/workers/wrangler/commands
  53. 네이버 블로그, 2026-07-22: blog.naver.com/sys-mayo/224354476133
  54. velog riririb, 2026-09-21: velog.io/@riririb/wrangler-login-timed-out-consent-verifier-already-used
  55. Hacker News: news.ycombinator.com/item?id=49879577
  56. MDN Cache-Control: developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Cache-Contr…
  57. 네이버 블로그, 2026-09-28: blog.naver.com/enne123/224425316485
  58. velog im_h_jo, 2025-01-18: velog.io/@im_h_jo/Cloudflare의-Https프록싱에는-함정이-있다
  59. 긱뉴스, 2026-03: news.hada.io/topic?id=27399
  60. Workers Node.js, 2026-08-12: developers.cloudflare.com/workers/runtime-apis/nodejs
  61. velog jtnoh300, 2025-12-01: velog.io/@jtnoh300/Cloudflare-Workers로-백엔드-API-구축하기-Supabase-Auth-커스텀-도…
  62. Cloudflare Dedicated egress IPs: developers.cloudflare.com/smart-shield/configuration/dedicated-egress-i…
  63. Cloudflare Blog: blog.cloudflare.com/18-november-2025-outage
  64. Cloudflare Blog: blog.cloudflare.com/5-december-2025-outage
  65. 디지털데일리, 2025-12-05: ddaily.co.kr/page/view/2025120519071154715
  66. 긱뉴스, 2025-11-18: news.hada.io/topic?id=24449
  67. Cloudflare Docs, Next.js, 2026-08-25: developers.cloudflare.com/workers/framework-guides/web-apps/nextjs
  68. Supabase Docs, Regions: supabase.com/docs/guides/platform/regions
/sources:auto

글쓴이

주홍철은 네이버 출신 개발자이자 AI 핀테크 스타트업 어비스(AVISS)의 대표입니다. 경제·증시 분석 AI, AI 에이전트, 데이터 파이프라인을 직접 설계하고 개발하며, 『면접을 위한 CS 전공지식 노트』와 『클로드 코드 제대로 시작하기』(길벗)를 썼습니다. 회사 소개는 어비스 홈페이지에, 다른 글은 어비스 블로그에 있으며, 글에 대한 정정 요청이나 문의는 [email protected]으로 보내 주세요.