turushihara.workの技術スタック

このブログはastroとtailwindをベースに、Cloudflareのエッジインフラを活用して構築されています。 ドキュメントを外部サービスに置いたりするのは管理やセキュリティが難しいと感じたのでプライベートなCMSとしてこのサイトを構築しました。 これでドキュメントを書かない言い訳が一つ減りました! 以下では、使用している技術スタックとその選定理由について詳しく解説します。

技術選定の背景

このブログは以下の要件を満たすために設計されました:

  • 運用コスト: サーバーレスアーキテクチャによる低コスト運用
  • SEO対応: 静的サイト生成による検索エンジン最適化
  • 管理機能: 記事の投稿・編集・公開制御
  • セキュリティ: CloudflareによるDDoS対策、アクセス制限、token認証

フロントエンド技術

Astro 5.12.9

静的サイト生成フレームワークのAstroを採用。以下の特徴があります:

  • SEO最適化: 静的HTMLの生成により、検索エンジンに優しい構造
  • セキュリティ: ローカルでのビルドとデプロイにより、サーバーサイドの脆弱性を排除

TailwindCSS 4.1.11

ユーティリティファーストのCSSフレームワーク:

  • 高速開発: プリセットクラスによる迅速なスタイリング
  • デザインシステム: 一貫したデザインの維持
  • 最適化: 未使用CSSの自動削除によるファイルサイズ最小化

Cloudflareエッジスタック

Cloudflare Workers

サーバーレス実行環境で以下を実現:

  • エッジ実行: 世界200以上の都市で処理を実行
  • 低レイテンシ: ユーザーに最も近い場所での処理
  • APIエンドポイント: 記事CRUD操作、画像アップロード
  • 低コスト: 静的コンテンツの配信に最適化された料金体系

Cloudflare R2

オブジェクトストレージ:

  • 低コスト: egress料金なしの費用効率

Cloudflare D1

SQLiteベースの分散データベース:

  • 記事メタデータ: タイトル、作成日、タグ情報
  • 公開制御: 記事の公開・非公開状態管理

コンテンツ管理

処理パイプライン

  • remark: Markdownの解析
  • rehype: HTMLへの変換と拡張
  • Shiki: シンタックスハイライト
  • Mermaid: 図表・ダイアグラムの描画

開発・ビルド環境

TypeScript

TypeScriptの一貫した言語採用によりfront/backのコンテキストスイッチを低減

デプロイメントフロー

このブログは管理画面での記事作成からデプロイまでの流れが整備されています:

Cloudflare Infrastructure

ローカル開発環境

管理画面での記事作成

管理画面アクセス

記事メタデータ入力

Markdownファイル作成

記事投稿・保存

ローカル環境

npm run build

Astro SSG実行

静的ファイル生成

npm run deploy

Cloudflare Workers Deploy

サイト更新完了

記事投稿からデプロイまでの詳細手順

  1. 記事作成: 管理画面で記事のタイトル、タグ、本文(Markdown)を入力
  2. メタデータ保存: D1データベースに記事情報を保存
  3. ローカルSSG: npm run buildでAstroが全記事を静的HTMLに変換
  4. デプロイ: npm run deployでCloudflare Workersに配信
ユーザーCloudflareローカル環境D1 Database管理画面管理者ユーザーCloudflareローカル環境D1 Database管理画面管理者Edge Network世界中に配信記事作成・編集メタデータ保存npm run buildAstro SSG実行npm run deploy新記事配信

Cloudflareを活用したセキュリティ対策

APIエンドポイントの保護

Zero Trust > Access > サービス認証で利用できるサービストークンを用いてtoken認証を実装しています。 まずCloudflare Accessの概念として、以下のような感じになってます。

  1. アプリケーション: DNSやポリシーを組みわせて最終的にどういう挙動にするかコントロールする機能
  2. ポリシー: アクセスに対してどのような制限を行うかを定義する機能
  3. サービス認証: ポリシーで利用できるアクセス制限手段の一つ

サービス認証からトークンを生成し、ポリシーを先ほど作ったServiceTokenを設定して作成。さらにアプリケーションを作成から制限対象のエンドポイントを設定し、ポリシーをアタッチして完了という感じになってます。 設定画面

実装としては以下のように、APIリクエストのヘッダーにトークンを追加することで、Cloudflare Accessを通じて認証を行います。 当サイトではCloudflare Workersをエンドポイントとして設定しているので、Workersのエントリー実行前に認証が行われるイメージです。 また、Workersから保護されたAPIエンドポイントを呼び出す場合には、Cloudflareの環境変数にトークンを設定しておく必要があります。 環境変数はCLIからnpx wrangler secret putで設定するのが楽です。

const HEADERS = {
  'CF-Access-Client-Id': import.meta.env.CF_ACCESS_CLIENT_ID,
  'CF-Access-Client-Secret': import.meta.env.CF_ACCESS_CLIENT_SECRET,
};
 
const response = await fetch(
  `${HOST}/any/private/endpoint`,
  {
    headers: HEADERS,
  },
);

こちらの記事が詳しく説明されています→https://dev.classmethod.jp/articles/use-service-tokens-to-authenticate-cloudflare-access-from-my-application/

まとめ

技術選定では、最新技術の採用と実用性のバランスを重視し、長期間の運用に耐えうる安定した構成を心がけました。