배포와 인프라 — $0으로 실서비스 운영하기

 


월 서버비 $0의 현실

사이드 프로젝트의 가장 큰 적은 서버 비용이다. 아이디어가 좋아도, 매달 나가는 호스팅비와 API 비용이 부담되면 결국 서비스를 내린다. "만들고 싶은 것"과 "운영할 수 있는 것" 사이에는 비용이라는 장벽이 있다.

이 사주 앱의 총 운영 비용은 $0이다. 도메인 비용을 제외하면, 호스팅, API, CDN, SSL 모든 것이 무료다. 어떻게 가능한지, 그리고 그 대가로 무엇을 포기했는지를 솔직하게 정리한다.

아키텍처: 정적 + 서버리스

전체 인프라는 두 축으로 구성된다.

첫째, 정적 호스팅은 GitHub Pages가 담당한다. React 앱을 빌드한 결과물(HTML, CSS, JS, 이미지)을 GitHub Pages로 서빙한다. GitHub Pages는 공개 레포지토리에 대해 무료이고, CDN이 기본 제공되며, HTTPS도 자동 설정된다.

둘째, AI API 프록시는 Cloudflare Workers가 담당한다. 클라이언트(브라우저)에서 직접 Groq API를 호출하면 API 키가 노출된다. Cloudflare Workers가 중간에서 프록시 역할을 한다. 클라이언트가 Workers에 요청을 보내면, Workers가 API 키를 붙여서 Groq API를 호출하고, 스트리밍 응답을 클라이언트에 전달한다.

이 구조에서 서버가 없다. 전통적인 의미의 백엔드 서버, 데이터베이스, 파일 스토리지 모두 없다. 사주 계산은 클라이언트 브라우저에서 실행되고(룰 엔진이 순수 JS), AI 해석은 서버리스 함수(Workers)를 통해 외부 API로 위임된다.

GitHub Pages: 정적 호스팅의 선택

GitHub Pages를 선택한 이유는 단순하다. 무료이고, 안정적이고, 배포가 간단하다.

빌드 결과물을 특정 브랜치(gh-pages)에 푸시하면 자동으로 배포된다. GitHub Actions로 CI/CD 파이프라인을 구성하면, main 브랜치에 푸시할 때마다 빌드 → 사이트맵 생성 → 프리렌더링 → 배포가 자동으로 이루어진다.

커스텀 도메인 설정도 간단하다. 레포지토리 설정에서 커스텀 도메인을 입력하고, DNS에 CNAME 레코드를 추가하면 끝이다. HTTPS 인증서는 GitHub가 Let's Encrypt를 통해 자동 발급해준다.

GitHub Pages의 제한 사항은 명확하다. 정적 파일만 서빙할 수 있고, 서버 사이드 로직은 불가능하다. 사이트 크기 제한(권장 1GB), 대역폭 제한(월 100GB 소프트 리밋)이 있다. 사주 앱 수준에서는 이 제한에 걸릴 일이 거의 없다. 프리렌더링된 HTML을 포함한 전체 빌드 결과물이 수십 MB 수준이고, 개인 사이드 프로젝트의 트래픽이 월 100GB를 넘기는 경우는 드물다.

Cloudflare Workers: 서버리스 AI 프록시

Cloudflare Workers는 이 프로젝트에서 가장 중요한 인프라 조각이다. AI 해석 기능의 전체 흐름이 Workers를 통과한다.

Workers의 역할은 세 가지다.

첫째, API 키 보호다. Groq API 키를 Workers의 환경 변수에 저장한다. 클라이언트는 Workers의 엔드포인트만 알면 되고, 실제 API 키에는 접근할 수 없다. 프론트엔드 코드에 API 키가 노출되지 않는 것이 핵심이다.

둘째, 스트리밍 프록시다. Groq API의 스트리밍 응답(Server-Sent Events)을 Workers가 받아서 클라이언트에 그대로 전달한다. Workers는 스트리밍을 네이티브로 지원하므로, 응답의 첫 토큰부터 마지막 토큰까지 지연 없이 릴레이된다.

셋째, CORS 처리다. GitHub Pages에서 호스팅되는 프론트엔드와 Cloudflare Workers의 도메인이 다르기 때문에, CORS(Cross-Origin Resource Sharing) 헤더를 Workers에서 설정해야 한다. 허용할 오리진(GitHub Pages의 도메인)을 명시하고, 필요한 헤더와 메서드를 허용하는 CORS 미들웨어를 Workers에 구현했다.

Cloudflare Workers의 무료 티어는 일일 10만 건의 요청을 허용한다. 사주 해석 한 건에 Workers 요청이 1~2회(종합 해석 + 선택적 상세 해석)이므로, 일일 5만 건 이상의 사주 분석을 처리할 수 있다. 개인 사이드 프로젝트에서 이 한도에 도달할 가능성은 극히 낮다.

Groq API: 빠르고 무료인 AI

AI 해석의 실질적인 엔진은 Groq API다. Groq은 자체 개발한 LPU(Language Processing Unit) 하드웨어 위에서 LLaMA 등 오픈소스 모델을 구동하며, 매우 빠른 추론 속도가 특징이다.

Groq의 무료 티어를 선택한 이유는 두 가지다. 비용이 $0이라는 것, 그리고 추론 속도가 빨라서 스트리밍 체감이 좋다는 것이다. 첫 토큰까지의 시간(TTFT)이 매우 짧고, 토큰 생성 속도도 빨라서 사용자에게 "즉시 응답이 시작되는" 경험을 줄 수 있다.

무료 티어의 제한은 분명히 있다. 분당 요청 수 제한(RPM), 일일 토큰 수 제한이 있다. 구체적인 한도는 모델과 시기에 따라 달라지지만, 개인 프로젝트 수준에서는 충분하다.

다만 무료 티어의 한도에 근접할 때를 대비한 전략이 필요하다.

Rate Limiting 전략

무료 API의 한도를 효율적으로 관리하기 위해 여러 단계의 rate limiting을 적용했다.

첫째, 클라이언트 측 제한이다. 같은 사주를 일정 시간 내에 재요청하면 로컬 캐시에서 결과를 반환한다. "새로고침을 연타하는" 사용자가 불필요한 API 호출을 발생시키는 것을 방지한다.

둘째, Workers 측 제한이다. 같은 IP에서 단시간에 과도한 요청이 들어오면 429(Too Many Requests) 응답을 반환한다. 이것은 악의적 사용이나 봇 트래픽을 차단하기 위한 장치다.

셋째, 에러 핸들링이다. Groq API가 rate limit 응답(429)을 반환하면, Workers가 이를 클라이언트에 적절한 메시지로 변환한다. "현재 이용자가 많습니다. 잠시 후 다시 시도해주세요." 사용자에게 기술적 에러 대신 이해할 수 있는 안내를 보여주는 것이다.

넷째, 모델 분기의 부가 효과다. 앞서 비용 최적화에서 언급한 종합=고성능 모델, 개별=경량 모델 분기는 rate limiting에서도 효과가 있다. 경량 모델은 토큰 한도가 더 넉넉한 경우가 많아서, 개별 카테고리 해석의 호출을 경량 모델로 보내면 전체 한도를 더 효율적으로 사용할 수 있다.

빌드 파이프라인

전체 빌드에서 배포까지의 파이프라인을 정리하면 이렇다.

개발 단계에서는 vite dev로 로컬 개발 서버를 실행한다. Hot Module Replacement(HMR)로 코드 수정이 즉시 반영되어 개발 경험이 쾌적하다.

빌드 단계에서는 세 가지가 순차 실행된다. vite build로 React 앱을 프로덕션 빌드하고, generate-sitemap 스크립트로 사이트맵을 자동 생성하고, prerender 스크립트로 주요 페이지를 정적 HTML로 렌더링한다.

배포 단계에서는 빌드 결과물을 gh-pages 브랜치에 푸시한다. GitHub Actions가 이 전체 과정을 자동화한다. main에 커밋을 푸시하면, CI가 빌드 → 사이트맵 → 프리렌더링 → 배포를 순차 실행한다.

Cloudflare Workers는 별도로 배포한다. wrangler CLI로 Workers 코드를 배포하고, 환경 변수(API 키 등)는 Cloudflare 대시보드에서 설정한다. Workers의 코드 변경은 프론트엔드와 독립적으로 배포할 수 있다.

$0의 트레이드오프

무료 인프라에는 당연히 트레이드오프가 있다. 솔직하게 정리한다.

첫째, 확장성의 천장이다. 트래픽이 급증하면 GitHub Pages의 대역폭 제한, Cloudflare Workers의 요청 제한, Groq API의 토큰 제한에 동시에 걸릴 수 있다. 사이드 프로젝트에서 현실적인 문제는 아니지만, "만약 바이럴이 터지면" 대응이 어렵다.

둘째, 모델 선택의 제약이다. Groq 무료 티어에서 사용할 수 있는 모델은 한정되어 있다. Claude Sonnet이나 GPT-4o 같은 최상위 모델은 쓸 수 없다. LLaMA 기반 모델도 충분히 좋은 해석을 내놓지만, 최상위 모델과의 품질 차이가 있는 것은 사실이다.

셋째, 서비스 의존성이다. GitHub Pages, Cloudflare Workers, Groq API. 세 개의 무료 서비스에 의존하고 있다. 이 중 하나라도 무료 정책을 변경하거나 서비스를 중단하면 영향을 받는다. 물론 이것은 유료 서비스도 마찬가지이지만, 무료 서비스는 SLA(서비스 수준 협약)가 보장되지 않는다.

넷째, 서버 사이드 로직의 부재다. 사용자 인증, 데이터 저장, 분석 히스토리 같은 기능은 서버가 없으면 구현이 어렵다. 현재 앱은 로컬 스토리지에만 데이터를 저장하므로, 브라우저를 바꾸거나 기기를 바꾸면 데이터가 사라진다.

트레이드오프를 받아들인 이유

이 트레이드오프를 기꺼이 받아들인 이유는 명확하다. 사이드 프로젝트의 첫 번째 목표는 "세상에 나오는 것"이기 때문이다.

완벽한 인프라를 갖추려고 AWS나 GCP를 설정하고, 데이터베이스를 구축하고, 인증 시스템을 만들다 보면 프로젝트가 영원히 완성되지 않는다. 무료 인프라의 제약 안에서 핵심 기능을 먼저 출시하고, 트래픽이 실제로 늘어나면 그때 유료 인프라로 전환하는 것이 합리적이다.

"나중에 필요하면 그때 바꾸면 된다"는 생각이 아니다. 아키텍처를 처음부터 "교체 가능한 구조"로 설계한 것이다. Cloudflare Workers의 프록시 뒤에 있는 AI API를 Groq에서 다른 서비스로 바꾸려면, Workers의 엔드포인트 코드만 수정하면 된다. 프론트엔드는 변경이 없다. GitHub Pages에서 Vercel이나 Netlify로 옮기는 것도, 빌드 결과물을 다른 호스팅에 올리면 끝이다.

이 "교체 가능성"이 $0 인프라를 선택할 수 있게 해준 핵심 설계 원칙이다.

실서비스 운영의 현실

$0 인프라로 실서비스를 운영한 경험을 정리하면 이렇다.

안정성은 예상보다 좋았다. GitHub Pages의 다운타임은 거의 경험하지 못했고, Cloudflare Workers도 안정적이었다. Groq API가 간헐적으로 느려지는 경우는 있었지만, 서비스가 완전히 중단된 적은 없었다.

속도도 만족스러웠다. GitHub Pages의 CDN 덕분에 정적 자산의 로딩이 빠르고, Groq의 빠른 추론 속도 덕분에 AI 해석의 스트리밍 체감이 좋았다. 첫 화면 로딩부터 분석 결과 표시까지의 전체 흐름이 쾌적했다.

운영 부담이 거의 없다는 것이 가장 큰 장점이었다. 서버를 모니터링할 필요가 없고, 보안 패치를 적용할 필요가 없고, 스케일링을 걱정할 필요가 없다. 코드를 푸시하면 자동으로 배포되고, 나머지는 세 개의 무료 서비스가 알아서 처리한다. 사이드 프로젝트에서 이 "운영 부담의 최소화"는 서비스를 오래 유지하는 데 결정적인 요소다.

이 선택이 의미하는 것

총 비용 $0으로 실서비스를 운영한다는 것은 기술적 성취이기도 하지만, 더 중요한 의미가 있다.

누구나 아이디어만 있으면 실서비스를 출시할 수 있다는 것이다. 서버 비용 때문에 프로젝트를 포기하는 시대는 지났다. GitHub Pages, Cloudflare Workers, Groq API 같은 무료 인프라를 조합하면, 코딩 실력과 아이디어만으로 서비스를 세상에 내놓을 수 있다.

물론 트래픽이 늘면 비용이 발생한다. 하지만 그것은 "좋은 문제"다. 사용자가 많아져서 비용이 생기는 것은, 사용자가 없어서 서비스를 접는 것보다 훨씬 나은 상황이다. $0에서 시작하고, 성장에 따라 비용을 늘려가는 것. 이것이 사이드 프로젝트의 현실적인 인프라 전략이다.

다음 편 예고

20편 시리즈의 3/4을 지나왔다. 설계부터 도메인 모델, 계산 엔진, AI 해석, UI, SEO, 배포까지 사주 앱의 전체 여정을 다루었다. 다음 편부터는 프로젝트 전체를 돌아본다. 타로와 사주 두 프로젝트를 거치면서 진화한 AI 협업 방법론, 그리고 복잡한 도메인에서 사람만이 할 수 있는 것의 경계를 정리한다.

댓글

이 블로그의 인기 게시물

사랑을 직접 올리지 않는 설계

감정을 변수로 옮기다 — 3계층 감정 모델

시작의 충동 — "타로 웹앱을 만들어볼까?"