頭ん中

しがないITエンジニアが、考えた事を書きます。

Vercel と Cloudflare R2 のハイブリッド構成にする

Vercel で適当なアプリをホスティングしていると、アクセスが増えだしたときに真っ先に心配になるのが Fast Data Transfer (転送量) の制限です。

無料の Hobby プランだと 100GB までで、容量大きいデータがあると意外とあっという間に使い切ってしまいます。100GB を超えると有料の Pro プラン(月額 $20〜)へのアップグレードが必要になりますが、個人開発としてはできればコストを抑えたいところ。

そこで今回は、アプリ本体は Vercel に置いたまま、静的コンテンツだけを転送量無料の Cloudflare R2 に逃がすハイブリッド構成を試します。


全体構成

  • Vercel: Next.js との親和性が高く、NextAuth や Firebase を使ったサーバーサイドの処理がそのまま動く。
  • Cloudflare R2: Amazon S3の互換サービスだが、データ転送量 (Egress) が完全に無料なので、ファイルの配信に最適。無料枠も大きい。

Cloudflare Pages にアプリごと移すと、Edge Runtime の制約で Node.js 依存のライブラリ(Firebase Admin など)を書き換える必要があるため、今回はハイブリッドな形を選びました。

実装のポイント

Cloudflare R2のバケットを作る

R2 Object Storageで新規バケットを作ったら、

パブリックアクセスを有効にして、

バケットに書き込むためのAPIトークンを作成します(Account API token)

データ取得 URL を環境変数で切り替える

ローカル開発時は手元のファイル、本番環境では R2 の URL を見に行くように、簡単なユーティリティを作成しました。

export const getDataUrl = (path: string) => {
  const baseUrl = process.env.NEXT_PUBLIC_DATA_URL || '';
  const normalizedPath = path.startsWith('/') ? path : `/${path}`;
  return `${baseUrl}${normalizedPath}`;
};

各コンポーネントでの fetch 部分をこれに置き換えます。

// 今まで
fetch('/data/xxxxx.png')

// これから
fetch(getDataUrl('/data/xxxxx.png'))

Vercel の環境変数 NEXT_PUBLIC_DATA_URL に R2 バケットのパブリックURLを設定すれば、本番環境だけ R2 を参照するようになります。未設定ならローカルのファイルを見に行くので、開発環境を汚さないのもいい感じです。

GitHub Actions で R2 に自動同期

public/data/ 以下のファイルに変更があった時だけ、rclone コマンドで R2 へ差分同期(Sync)するように設定しています。GitHubのシークレットには先ほど作った R2 バケットのエンドポイントやAPIトークンを設定します。

on:
  push:
    branches: [main, release]
    paths: ['appdir/public/data/**']

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Install rclone
        run: sudo apt-get install -y rclone
      - name: Configure & Sync
        run: |
          # rclone 設定後に sync 実行
          rclone sync appdir/public/data r2:my-bucket/data --progress
        env:
          R2_ACCESS_KEY_ID: ${{ secrets.R2_ACCESS_KEY_ID }}
          R2_SECRET_ACCESS_KEY: ${{ secrets.R2_SECRET_ACCESS_KEY }}
          R2_ENDPOINT: ${{ secrets.R2_ENDPOINT }}
          R2_BUCKET_NAME: ${{ secrets.R2_BUCKET_NAME }}

これで、今まで通り git push するだけで、アプリ本体(Vercel)とデータ(R2)が同時に最新の状態に保たれます。

忘れがちな CORS 設定

R2 のデータをブラウザから直接 fetch するため、Cloudflare 側で CORS 設定を追加する必要があります。

[
  {
    "AllowedOrigins": ["https://app-domain.com"],
    "AllowedMethods": ["GET"],
    "AllowedHeaders": ["*"]
  }
]

おわりに

この構成に切り替えた結果、Vercel 側の転送量は JS などの軽量なファイルのみになり、100GB 制限の不安はほぼなくなりました。アクセスが急増した時でも、転送量無料の R2 が盾になってくれるので、精神衛生上も非常によろしいです。

同じように Vercel の転送量でお悩みの方は、ぜひ検討してみてください。

GitHub Copilot から Gemini(Google AI Pro)に乗り換えた

もともと Google フォト・ドライブに課金して Google One でギガを家族共有していたので、Google AI Pro というプランは恐ろしく魅力的でした。

AIコーディング用途だけでなく、普通に家族もチャットAIを使い始めており、GitHub Copilot 単独でサブスクを維持するより、それなら Googleに寄せて Gemini 3 使えた方がいいんじゃないかと。正直、それだけで乗り換えを決めたところがあります。

個人的な使用感の変化をまとめておきます。

続きを読む

WinUI 3 デスクトップアプリで正円形のウィンドウを実現する

今回は、このようなウィンドウを正円形に切り抜く実装をしていきます。

UWP と同じで WinUI 3 ではウィンドウの一部を透明にするような手段は用意されていません。したがって、Win32 API を使って実現することになりますが、Windows 11 のウィンドウ仕様の影響で若干の考慮が必要となります。

続きを読む

Next.js プロジェクトを Firebase Hosting に GitHub Actions でデプロイする

最近はフロントエンド界隈に追いていかれないよう必死で勉強中です。せっかくなので作ったアプリはホスティングサービスで公開したいと思い、 プレビュー版ですが Next.js に対応した Firebase Hosing を試します。

firebase.google.com

  • セットアップ
  • GitHub Actions でデプロイする
    • トラブルシュート1
    • トラブルシュート2
    • トラブルシュート3, 4, 5
    • トラブルシュート6
    • トラブルシュート7
    • 結果
続きを読む

ふりかえり

4月から役職になります。

もともと全員が裁量労働制の会社なので、役職になって何がどう変わるのか正直まだよくわかっていません。ただ、権限と責任は大きくなるはずですし、「良い会社にしたい」という思いは強いので、できることから一歩ずつ頑張っていこうと思います。

せっかくなので、新卒入社からの10年余りをざっくり振り返ります。

続きを読む

マンションを買った。<購入編>

前回の続き。

なんとなく「大規模マンション」「眺望、周辺環境が良い」という共通認識が妻とできてきたあたりで、家探しがはじまります。ここから実際に購入に至るまで、足掛け2年かかりました。その足取りを辿ります。

  • はじめてのマンションギャラリー
  • 西へ東へ(北へ南へ)
  • ぶれた基準を絞る
    • 大規模➡敷地が広い多棟型の超大規模に限定
    • 眺望➡「海が見える」に限定
    • 車は持たない覚悟を決める
  • ひたすら出待ち
  • ついに購入
  • まとめ
続きを読む

Puppeteerを使った税金支払い節約術

はじめに

通常は現金しか使えない税金・公共料金の支払いに、セブンイレブンnanaco払いを使うという節約術は、その筋では昔から有名です。クレジットチャージの改悪等で昔より旨みは減ってしまいましたが、2023年現在の主流は福利厚生サービス「ベネフィット・ステーション」等で手に入れたnanacoギフトコードを使う方法です。この方法のいいところは2つあります。

  • 還元率は1%~2%くらい。(時期によって変動、大体1.5%)
  • nanacoギフトはチャージ上限が無いので高額な支払に使える。*1

ただし、この方法には致命的な問題があります。nanacoギフトは1枚1000円なので、まとまった額の支払いとなると何百ものギフトコードが必要になる訳ですが、このチャージ操作が恐ろしく大変なんです。

半ばルーティンワークになっているこのクソめんどい作業をNode.jsライブラリ Puppeteer 使ったスクリプトで自動化したいと思います。

  • はじめに
  • 環境
  • Puppeteerコード
    • id属性を指定して要素を操作する
    • id属性が無い場合
  • 完成

*1:通常、nanacoカードは5万円+センター預かり分5万円、合わせて10万円が残高上限です。nanacoギフトはこのセンター預かり分5万円の上限を超えてチャージができるため、1枚のnanacoで10万円以上の高額な支払も可能になります。

続きを読む