맥미니를 켜놓고, 정전 걱정하고, 인터넷 끊기면 봇이 죽고, 매주 업데이트하는 — 그 모든 부담 없이 봇을 운영하는 방법. 평생 무료(또는 월 $5)로 1만 명에게 서비스 가능.
| 비교 | 맥미니 (집) | Cloudflare Workers |
|---|---|---|
| 초기 비용 | ₩90만 | ₩0 |
| 월 비용 | 전기료·인터넷 | ₩0~₩7,000 |
| 다운타임 | 정전·인터넷·본인 부재 시 | 거의 없음 (글로벌 엣지) |
| 자동 업데이트 | 본인이 직접 | git push 1번 |
| 확장성 | 고객 50명 한계 | 무제한 자동 스케일 |
| 보안 | 본인 책임 | CF DDoS 방어 무료 |
고객 (Telegram)
↓ 메시지
Telegram Bot API
↓ Webhook
Cloudflare Workers ← (KV: 사용량) ← (D1: 고객 DB)
↓ Anthropic API 호출
응답 → Telegram → 고객
@BotFather 검색 → 대화/newbot → 이름·아이디 입력 → 토큰 받음123456:AAH...)npm create cloudflare@latest leasebot
cd leasebot
npx wrangler login
export default {
async fetch(request, env) {
if (request.method !== "POST") return new Response("OK");
const update = await request.json();
const message = update.message;
if (!message?.text) return new Response("OK");
const userId = String(message.from.id);
const chatId = message.chat.id;
const text = message.text;
// 1. 사용량 체크
const sonnetUsed = parseInt(await env.KV.get(`s:${userId}`) || "0");
const haikuUsed = parseInt(await env.KV.get(`h:${userId}`) || "0");
let model;
if (sonnetUsed < 3000) {
model = "claude-sonnet-4-6";
await env.KV.put(`s:${userId}`, String(sonnetUsed + 1));
} else if (haikuUsed < 5000) {
model = "claude-haiku-4-5";
await env.KV.put(`h:${userId}`, String(haikuUsed + 1));
} else {
await sendTelegram(env, chatId, "이번 달 한도 도달. 추가팩 결제 안내 →");
return new Response("OK");
}
// 2. Anthropic API 호출
const reply = await callAnthropic(env, model, text);
// 3. Telegram 응답
await sendTelegram(env, chatId, reply);
return new Response("OK");
}
};
async function callAnthropic(env, model, prompt) {
const res = await fetch("https://api.anthropic.com/v1/messages", {
method: "POST",
headers: {
"x-api-key": env.ANTHROPIC_KEY,
"anthropic-version": "2023-06-01",
"content-type": "application/json",
},
body: JSON.stringify({
model,
max_tokens: 1024,
system: "너는 친절한 비즈니스 어시스턴트다. 간결하게 답한다.",
messages: [{ role: "user", content: prompt }],
}),
});
const data = await res.json();
return data.content?.[0]?.text || "응답 오류. 다시 시도해주세요.";
}
async function sendTelegram(env, chatId, text) {
await fetch(`https://api.telegram.org/bot${env.BOT_TOKEN}/sendMessage`, {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ chat_id: chatId, text }),
});
}
name = "leasebot"
main = "src/index.js"
compatibility_date = "2026-05-01"
kv_namespaces = [
{ binding = "KV", id = "your-kv-id" }
]
[vars]
# 비밀 변수는 wrangler secret put 으로
npx wrangler kv:namespace create KV
npx wrangler secret put ANTHROPIC_KEY
npx wrangler secret put BOT_TOKEN
npx wrangler deploy
# https://leasebot.YOUR.workers.dev 발급됨
# Telegram에 webhook 등록 (1회)
curl "https://api.telegram.org/botBOT_TOKEN/setWebhook?url=https://leasebot.YOUR.workers.dev"
// wrangler.toml
[triggers]
crons = ["0 0 1 * *"]
// src/index.js
export default {
async fetch(...) { /* 위와 동일 */ },
async scheduled(event, env) {
// 매월 1일 0시: 모든 사용량 리셋
const list = await env.KV.list();
for (const key of list.keys) {
await env.KV.delete(key.name);
}
},
};
| 항목 | 무료 티어 | 유료 ($5/월) |
|---|---|---|
| Workers 요청 | 10만/일 | 1,000만/일 |
| KV 읽기 | 10만/일 | 1,000만/일 |
| KV 쓰기 | 1,000/일 | 100만/일 |
| 고객 수용 (1일 100질문/명) | 약 500명 | 약 5만명 |
"집에서 운영" 매력은 통제감이지만, 무인 자동화 목표와는 반대 방향이다. Cloudflare Workers는 "내가 신경 쓸 게 없다"는 자유를 준다. 그게 진짜 자동화다.