テックブログを書きたくなったのでサイトから作ってみた
2025-12-24
azblob://2025/12/23/eyecatch/2025-12-24-setup-blog-site-000.png

はじめに

お疲れ様です。

今年もアドベントカレンダーの季節になり、何か面白いことをしたいと思いました。

業務での学びや技術的な試行錯誤をまとめられる個人的な場所が欲しかったこともあり、ブログサイトを自作することにしました。

既存のブログサービスを使うことも考えましたが、自分でデザインや機能を考えたかったので、ゼロから作ることにしました。

この記事では、コンセプトづくりや Figma を使ったモック作成、技術選定、Next.js と Cloudflare を中心とした実装プロセスをまとめています。なお、紹介する方法は必ずしも「ベストプラクティス」ではないことをご了承ください。

コンセプトづくり

サイトとしてのコンセプト

ブログサイトを作るにあたって、まずは大まかな方向性を整理します。

今回作成するブログサイトは「気軽にかけて、気軽に読める技術ブログ」をコンセプトにしています。

機能を盛り込みすぎず、まずは以下3点を満たすことを目標にしました。

1. 読みやすいこと

技術記事は内容が中心になるため、装飾を控えめにし、余白やフォントのバランスを優先しました。

2. 更新しやすいこと

記事投稿フローをできるだけシンプルにし、編集画面や構成も自分が迷わない形にしました。

3. 長く使えること

必要に応じていつでも拡張できるよう、設計をシンプルに保つようにしました。

Figma でのデザイン

コンセプトが固まった段階で、Figma を使ってデザインを具体化しました。

ブランドカラーには深めのグリーンを採用し、背景やテキストには落ち着いたトーンを合わせて、読みやすさを損なわない配色にまとめています。

コンセプトカラー

続いてワイヤーフレームを作成し、このワイヤーフレームとカラーパレットをもとに モックアップを作成 しました。


レスポンシブ対応も考慮して、モバイル・タブレット・PC の 3 デバイス分を用意しました。

mock

さらに、作成したモックアップを使って 画面遷移をまとめたフロー図 を作成し、必要な導線やデータの流れを視覚化しました。

画面遷移

Figma 上でモック・カラー・ロゴを先に固めたことで、Next.js のコンポーネント構成や CSS 設計の方針が明確になり、実装段階で迷う時間が少なくなったと感じています。

技術選定

実装に入るにあたって、今回必要になる技術を整理しました。


普段はアプリケーション側の開発を担当していることもあり、今回も アプリ側の実装を中心に進める ことを前提としています。

そのため、インフラ周りは必要最低限の設定で済み、かつ 運用負荷が小さく扱いやすいサービス を選びたいという背景がありました。これらの条件に最も合っていたのが Cloudflare でした。

どこででも接続、保護、構築 | Cloudflare

フロントエンドには Next.js を採用しました。
App Router とサーバーアクションを使うことで、API サーバーを別途用意する必要がなく、記事投稿や編集といった CRUD 操作を簡潔に実装できる点が大きなメリットでした。

Next.js by Vercel - The React Framework

アーキテクチャ設計

今回のブログサイトは、できるだけシンプルな構成で運用できることを意識して設計しました。
大きく分けると、Next.js 側のアプリケーションCloudflare 側の基盤サービス の2つに役割を分けています。

全体構成

ざっくりとした構成は以下のようなイメージです。

  • フロントエンド:Next.js(App Router)
  • サーバーサイド処理:Next.js のサーバーアクション
  • データベース:Cloudflare D1
  • 画像・アセット:Cloudflare R2
  • 認証/保護:Cloudflare Access
  • 配信・エッジ:Cloudflare(CDN / Workers)

Next.js が画面表示とサーバーアクションを担当し、データの永続化や静的ファイルの配信などを Cloudflare 側に任せる形にしています。

データフロー

記事の取得と投稿の流れはざっくり以下のような感じです。

  • 記事の取得
    1. ユーザーが記事一覧/詳細ページにアクセス
    2. Next.js のサーバーコンポーネント or サーバーアクションから D1 にクエリ
    3. 取得したデータをページにレンダリング
  • 記事の投稿・更新
    1. 管理画面からフォームを送信
    2. サーバーアクション経由で D1 に対して INSERT / UPDATE
    3. 必要に応じて R2 に画像をアップロードし、そのパスを記事データに紐づける

今回はAPI サーバーを別で用意せず、「Next.js のサーバーアクション → D1」 というシンプルな動線にしています。

記事データ構造

記事データは、D1 上にシンプルなテーブルを1つ用意して管理しています。
基本的なカラムとしては、タイトル・本文・スラッグ・公開フラグ・作成/更新日時など、ブログとして最低限必要な情報に絞っています。

セキュリティ設計(Access を使った管理画面保護)

管理画面については、アプリ側でログイン機能を実装するのではなく、Cloudflare Access を使って保護する構成 にしています。

  • 管理画面にアクセスする前に Access が認証を実施
  • 許可されたユーザーのみが管理画面に到達できる

これによって、アプリケーション側で認証機能を一から実装せずに済み、個人開発でも比較的安全な形で管理画面を公開できるようにしています。

Cloudflare の構成

今回のブログでは、インフラまわりの実装や運用コストをできるだけ小さくしたかったため、Cloudflare のマネージドなサービスに寄せて構成を組みました。Workers、D1、R2、Access の4つを組み合わせて利用しています。

Workers

Workers は、サーバーレスでJavaScriptを実行できるエッジプラットフォームです。

Cloudflare Workers | サーバーレスアプリケーションを構築 | Cloudflare

以前は静的アセットを Cloudflare Pages でホストして、動的なサーバー処理を Worker で使用するような構成が一般的でしたが、2024年9月のアップデートにより、 Pages の機能が Worker に統合される形になり、単一Workerでフルスタックアプリケーションを構築することが可能になりました。


主に 配信まわりや Next.js の動作基盤 として利用しており、特別な設定をしなくても Cloudflare のエッジで高速に動いてくれる点が便利でした。

D1

D1 は SQLite ベースのサーバーレスなマネージドデータベースです。

ネイティブにサーバーレスなSQLデータベースをCloudflare D1で構築 | Cloudflare

スキーマを作り、Next.js のサーバーアクションから直接クエリを発行するだけで CRUD 処理が完結します。
大規模なデータ構造を必要としなかった今回のブログにはちょうどよい選択でした。

今回は記事データの保存に利用しています。

R2

R2 は、オブジェクトストレージです。

Cloudflare R2 | エグレス料金ゼロのオブジェクトストレージ | Cloudflare

記事内で使用する画像のアップロード先として利用しています。AWS S3 互換の API で扱いやすく、コストも低いので、個人開発としてはとても使いやすいストレージでした。
記事の投稿時に R2 に画像をアップロードし、その URL を記事データに紐づけるだけで運用できます。

Access

管理画面の保護には、Cloudflare Access を使用しています。

Access | ゼロトラストネットワークアクセス(ZTNA)ソリューション | Cloudflare

アプリ側でログイン機能を実装すると工数がかかるため、Access 側で認証を完結できるのは非常に助かりました。


ポリシーの作成により、許可されたユーザーだけが管理画面にアクセスできるようになるため、個人開発でも比較的安全な運用ができます。

Cloudflare を使ってみて

Cloudflare を選んだ理由は「設定が少なく、必要な部分だけを最低限使える」点でしたが、D1 を使ったデータ管理、R2 を使った画像保存・Access による管理画面の保護など、欲しい機能がシンプルに組み合わせられるため、アプリ側の実装に集中できる環境が整えやすかったです。

アプリ側の実装

フロントエンドの実装

フロントエンドは Next.js を使って実装しました。
Figma で作成したモックをベースに、UI コンポーネント → 機能コンポーネント → ページの順番で組み上げています。

Figmaによるコンポーネント作成

まずは UI の土台を整えるため、Storybook を使って UI コンポーネントの単体開発 から着手しました。ボタン・入力欄・カードなど、ブログ全体で再利用する要素を先に整えておくことで、その後の開発がかなりスムーズになりました。

UI コンポーネントのデザインは、デジタル庁デザインシステム を参考にしています。アクセシビリティや視認性が重視されたデザイン体系なので、ブログのように読むことが中心になる UI とは相性が良く、余白や文字サイズ、フォーカス状態などを踏襲しながら調整しました。

デザインシステム|デジタル庁

UI が揃ったら、続けて 機能コンポーネント(記事一覧の取得・検索機能・プレビュー表示など) を実装し、最後に各ページで必要な処理を組み合わせてページ全体を仕上げていきました。

バックエンドの実装

今回は Next.js のサーバーアクションを入口にして、記事の CRUD や画像アップロードなどのサーバー処理をまとめました。


別途 API サーバーを立てずに、フォーム送信をそのままサーバー処理に繋げられるのが大きなメリットです。

具体的には、フォームの action にサーバーアクションを指定するだけで、次のような処理を実装できます。

  • 記事の作成 / 更新 / 削除
  • 記事一覧・詳細の取得
  • 画像アップロード(R2)との連携

サーバーアクションは use server を付けた関数として定義し、その中で D1 へのクエリR2 へのアップロードを行っています。


リクエスト/レスポンスのための API ルートや型定義を大量に用意せずに済むので、管理画面のような用途では実装がかなりシンプルになりました。

管理画面の実装

管理画面では、以下の操作を行えるようにしています。

  • 記事一覧の表示
  • 記事の編集
  • 新規記事の作成(プレビュー付き)

管理画面は App Router の サーバーコンポーネント を中心に構成しています。
ブログの編集や作成は「サーバー側のデータをそのまま扱う」場面が多いため、クライアント側で余計な状態やキャッシュを持たないようにし、常に最新の情報を見にいく形にしています。

  • 記事一覧

記事一覧では、D1 から取得したデータをサーバーコンポーネントで直接描画しています。
React の状態をほとんど持たずに済むため、記事を更新した後にリロードしたり、手動でステートを管理したりする必要がありません。

  • 記事編集

編集画面では、URL のパラメータから記事 ID を受け取り、サーバーコンポーネント側で該当記事を読み込みます。
編集フォームはシンプルな構成にしており、フォーム送信時にサーバーアクションを呼び出すだけで更新処理が完結します。

  • 記事作成(プレビュー付き)

新規作成画面には プレビュー機能 をつけています。
これは、入力しているタイトルや本文をそのまま別コンポーネントに渡して描画しているだけのシンプルな構成ですが、書いている内容をリアルタイムに確認できるため執筆体験がかなり良くなりました。

全体の設計意図

管理画面全体として、

  • クライアント側には余計な状態を持たない
  • 必要なデータは都度サーバーで取得
  • フォーム送信のロジックはすべてサーバーアクションに委譲
  • 画面遷移は App Router の仕組みで完結
  • 認証は Cloudflare Access で管理

という構成にすることで、小さくシンプルで壊れにくい管理画面 に仕上げています。

完成したブログサイト

ここまで実装を進めて、最終的に今回のブログサイトは次のような形になりました。

Mosslog - Technical blog

トップ記事詳細ダッシュボード記事管理記事編集

全体として派手さはありませんが、日常的に記事を書いたり管理したりするうえでは十分な機能が揃ったシンプルな技術ブログになったと思います。

おわりに

アドベントカレンダーをきっかけに始めた今回のブログサイト作りですが、当初予定していたものより色々作り込むことになり、結果的にとても良い経験になりました。

まずは最低限の機能だけですが、実働が2週間くらいの割にはそこそこいいものができたと思います。

今後も少しずつ機能を追加していく予定です。
 

どこか一部でも参考になれば嬉しいです。ありがとうございました!