💡 Tips

個人開発SaaSを月額ほぼ0円で動かす Cloudflare Pages+D1構成ガイド

結論:Cloudflareだけで月額ほぼ0円のSaaSインフラが成立する

個人開発でSaaSを立ち上げる最大の壁は「収益が出る前のインフラコスト」です。VPSやRDSを使うと月1〜3万円は軽くかかり、PMF前に資金が尽きるリスクがある。

その解決策が Cloudflare Pages+D1+Workers+R2 の組み合わせです。すべてCloudflareの無料枠または従量課金の範囲に収まり、小〜中規模SaaSなら月額ほぼ0〜数百円で本番運用できます。

免責: 無料枠の上限・料金体系は変更される場合があります。実装前にCloudflare公式の最新料金ページを必ず確認してください。


各サービスの無料枠早見表

サービス用途無料枠の目安
Cloudflare Pagesフロントエンドホスティングビルド500回/月、帯域無制限
Cloudflare WorkersAPIサーバー/BFF10万リクエスト/日
Cloudflare D1SQLiteベースのRDB5GBストレージ、500万行読み取り/日
Cloudflare R2オブジェクトストレージ10GB/月、Aクラス100万回/月
Cloudflare KVセッション・キャッシュ10万回読み取り/日

月間アクティブユーザーが数百〜数千人規模であれば、無料枠を超えることはほぼありません。超えた場合も従量課金は安価(Workersは100万リクエストあたり$0.30)です。


全体構成図

┌─────────────────────────────────────────────────────┐
│                    Cloudflare Network                 │
│                                                       │
│  ┌──────────────┐     ┌──────────────────────────┐  │
│  │ Cloudflare   │────▶│   Cloudflare Workers     │  │
│  │   Pages      │     │   (Hono / API Routes)    │  │
│  │ (Astro/React)│     └───────────┬──────────────┘  │
│  └──────────────┘                 │                  │
│                          ┌────────┼────────┐         │
│                          ▼        ▼        ▼         │
│                        ┌───┐   ┌───┐   ┌───┐        │
│                        │ D1│   │ KV│   │ R2│        │
│                        │SQL│   │KVS│   │S3 │        │
│                        └───┘   └───┘   └───┘        │
└─────────────────────────────────────────────────────┘
              ▲                          │
              │         外部連携         │
              │   (Stripe Webhook, etc.) │
              └──────────────────────────┘

フロントエンドはCloudflare Pagesでホストし、APIはWorkersで処理。データはD1(構造化データ)・KV(セッション、レートリミット)・R2(ファイル)に分けて格納するのが基本パターンです。


実装パターン:HonoでAPI Workersを作る

Workers上で動くAPIフレームワークとして Hono が最もおすすめです。軽量かつTypeScript対応が優秀で、D1バインディングとの相性も抜群。

プロジェクト初期化

npm create cloudflare@latest my-saas-api -- --template hono
cd my-saas-api

wrangler.toml の設定

name = "my-saas-api"
compatibility_date = "2024-11-01"

[[d1_databases]]
binding = "DB"
database_name = "my-saas-db"
database_id = "xxxx-xxxx-xxxx"   # wrangler d1 create で発行

[[kv_namespaces]]
binding = "SESSION"
id = "xxxxxxxx"

[[r2_buckets]]
binding = "STORAGE"
bucket_name = "my-saas-storage"

D1を使ったCRUDエンドポイント例

// src/index.ts
import { Hono } from 'hono'
import { cors } from 'hono/cors'

type Bindings = {
  DB: D1Database
  SESSION: KVNamespace
  STORAGE: R2Bucket
}

const app = new Hono<{ Bindings: Bindings }>()

app.use('*', cors({ origin: 'https://your-saas.pages.dev' }))

// ユーザー一覧取得
app.get('/api/users', async (c) => {
  const { results } = await c.env.DB.prepare(
    'SELECT id, email, plan, created_at FROM users ORDER BY created_at DESC LIMIT 50'
  ).all()
  return c.json(results)
})

// ユーザー作成
app.post('/api/users', async (c) => {
  const { email, plan } = await c.req.json<{ email: string; plan: string }>()
  const result = await c.env.DB.prepare(
    'INSERT INTO users (email, plan, created_at) VALUES (?, ?, ?) RETURNING *'
  )
    .bind(email, plan, new Date().toISOString())
    .first()
  return c.json(result, 201)
})

export default app

D1マイグレーション

-- migrations/0001_create_users.sql
CREATE TABLE IF NOT EXISTS users (
  id       TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))),
  email    TEXT UNIQUE NOT NULL,
  plan     TEXT NOT NULL DEFAULT 'free',
  created_at TEXT NOT NULL
);

CREATE INDEX idx_users_email ON users(email);
# ローカルに適用
npx wrangler d1 execute my-saas-db --local --file=migrations/0001_create_users.sql

# 本番に適用
npx wrangler d1 execute my-saas-db --file=migrations/0001_create_users.sql

フロントエンド(Astro)をPagesにデプロイ

Cloudflare Pagesは静的サイトのみならず、Astro SSRもサポートしています。

npm create astro@latest my-saas-front
cd my-saas-front
npx astro add cloudflare   # Cloudflareアダプタを追加

astro.config.mjs にアダプタを設定後、GitHubリポジトリをPagesのダッシュボードに接続するだけでCI/CDが完成します。プッシュするたびに自動ビルド・デプロイが走る。


R2でファイルアップロードを実装する

// ファイルアップロードエンドポイント
app.post('/api/upload', async (c) => {
  const formData = await c.req.formData()
  const file = formData.get('file') as File
  if (!file) return c.json({ error: 'No file' }, 400)

  const key = `uploads/${crypto.randomUUID()}-${file.name}`
  await c.env.STORAGE.put(key, file.stream(), {
    httpMetadata: { contentType: file.type },
  })

  // 署名付きURLを返す(7日間有効)
  const url = await c.env.STORAGE.createPresignedUrl?.('GET', key, { expiresIn: 604800 })
  return c.json({ key, url })
})

コスト比較:従来構成 vs Cloudflare構成

項目VPS+RDS構成Cloudflare構成
サーバーVPS 月2,000〜5,000円Workers 月0円〜
DBRDS最小 月3,000〜D1 月0円〜
ストレージS3互換 月数百円〜R2 月0円〜(10GB)
CDN別途設定 月数百円〜Pages込み 0円
合計月5,000〜10,000円月0〜数百円

初期フェーズの数ヶ月をほぼ無料で乗り越えられるのは、個人開発者にとって大きなアドバンテージです。

📚 おすすめ書籍

個人開発の教科書

個人開発のリアルな知見が詰まった一冊。構成設計の参考に

Amazonで見る →

注意点・デメリット

  • D1はSQLiteベースのため、PostgreSQL固有の機能(配列型、全文検索など)は使えない。複雑なクエリが必要なら設計を工夫するか、Hyperdrive経由で外部DBを使う検討も必要。
  • Workersのコールドスタートは基本なしだが、CPU時間は無料プランで10ms/リクエストの制限がある。重い処理には向かない。
  • D1はまだGA(一般提供)が新しいサービスのため、大規模トランザクションや高頻度書き込みには本番実績を確認してから採用すること。
  • 日本のデータ主権・個人情報保護法の観点から、データのリージョン制御が必要な場合は別途検討が必要。

まとめ

ステップやること
1wrangler d1 create でDBを作成
2Honoでapi Workersを実装・デプロイ
3AstroフロントエンドをPages に接続
4R2バケットを作りファイルアップロードを追加
5KVでセッション・レートリミット管理を実装

Cloudflare Pages+D1+Workers+R2の組み合わせは、個人開発SaaSの初期コスト問題を根本から解決する現時点で最有力の選択肢の一つです。無料枠が充実しているため、PMFを確認してから課金プランに移行するという戦略が取りやすい点も大きな魅力です。

まずはローカルでwrangler devを動かし、小さな機能から試してみてください。Cloudflareのエコシステムは一度覚えると非常に生産性が高く、個人開発の強力な武器になります。