All posts

EmDash のブログを Cloudflare の無料プランで公開するまでにやった設定まとめ

EmDash(Astro ベースの CMS)のブログを Cloudflare Workers に置き、独自ドメイン・費用の見張り・AI に見つけてもらうための設定まで、無料プランでやったことを画面つきでまとめました。

EmDash のブログを公開するまでにやった設定まとめ。独自ドメインだけで配信、予算アラート 1 ドル、AI クローラーを許可、Crawler Hints、Markdown で配信の 5 項目

このブログ(おきなこ備忘録)は、Cloudflare が作った CMS「EmDash」で動いています。Cloudflare の無料プランのまま、独自ドメインで公開して、費用の見張りと「AI に見つけてもらう」ための設定までやりました。あとで自分が見返せるように、やった設定を画面つきでまとめておきます。料金やプランの条件、画面の見た目は 2026年10月時点のものです。

全体の構成

  • CMS: EmDash 1.3(Astro ベース)の cloudflare:blog テンプレート
  • 置き場所: Cloudflare Workers(記事は D1、画像は R2、セッションは KV)
  • ドメイン: Cloudflare Registrar で取った okinako.dev
  • デプロイ: 手元から npm run deploy(GitHub との自動デプロイ連携はしていない)

1. 独自ドメインだけで配信する

Worker のドメインタブ。workers.dev の URL は本番もプレビューもオフで、okinako.dev がカスタムドメインとして割り当てられている

wrangler.jsonc で、workers.dev の URL を無効にして、独自ドメインだけで配信しています。

{
  "name": "okinako-blog",
  "workers_dev": false,
  "preview_urls": false,
  "routes": [{ "pattern": "example.com", "custom_domain": true }],
  "vars": { "EMDASH_SITE_URL": "https://example.com" }
}
  • workers.dev の URL には、アカウントのサブドメインが入ります。ブログの名義とアカウントを結び付けたくなかったので、使わないことにしました。
  • 同じサイトが2つの URL で見えると、検索エンジンに別のサイトとして扱われることがあります。ページには正式な URL(canonical)が入っていますが、そもそも1つにしておくほうがすっきりします。
  • 管理画面のログイン(パスキー)は独自ドメインに結び付くので、workers.dev からは管理画面に入れません。
  • ドメインを取るときの登録者情報は、Cloudflare Registrar の既定で WHOIS には出ません。組織名の欄は空にしておきます。

2. 変数・シークレット・データの置き場所

Worker の設定タブ。EMDASH_ENCRYPTION_KEY はシークレット、EMDASH_SITE_URL は変数として登録され(値は非表示)、D1・R2・KV がバインディングとして並んでいる
  • EMDASH_SITE_URL を固定する: 指定しないと、管理画面の初期設定をした URL がサイトの URL として記録され、管理者のパスキーもその URL に結び付きます。
  • EMDASH_ENCRYPTION_KEY: 本番用にローカルとは別のキーを npx emdash secrets generate で作り、wrangler secret put で登録しました。なくすとプラグインに保存した秘密情報が読めなくなるので、控えはパスワードマネージャーに置いています。
  • D1・R2・KV: 初回の wrangler deploy で自動で作られます。ただし R2 だけは、アカウントで一度ダッシュボードから有効にしておく必要がありました。

3. 費用を見張る

請求の予算アラート。usage-spend-1usd という名前で、従量課金が 1 ドルを超えたらメールで知らせる設定
  • Workers・D1・KV の無料プランは、上限に達するとリクエストが止まるだけで、請求は発生しません。
  • R2 だけは、無料枠を超えた分が従量で請求されます。
  • 製品ごとの利用量の通知は Pro プラン以上でしか使えないので、代わりに予算アラートを使っています。アカウント全体の従量課金が 1 ドルを超えたらメールが来ます。R2 を有効にしたときに自動で作られた 10 ドルのアラートを、1 ドルに下げました。

4. アクセス解析

Web Analytics の一覧で、okinako.dev が自動セットアップで追加されている

Cloudflare Web Analytics を使っています。Cookie を使わない仕組みです。Cloudflare で配信しているサイトなら、自動セットアップで計測用のスクリプトが入ります。

5. AI に見つけてもらうための設定

AI クローラーをブロックしない

AI Crawl Control のセキュリティ画面。クローラーをブロックのスイッチはすべてオフで、ClaudeBot のリクエストが許可済みになっている

AI Crawl Control のセキュリティ画面で、どのクローラーもブロックしていません。ClaudeBot がすでに来て、正常に読めています。

robots.txt で利用を許可する(Content Signals)

robots.txt の中身。Content-Signal で search、ai-input、ai-train をすべて yes にしていて、コメントで Ko-fi への一言を添えている
  • Content-Signal で、検索(search)・AI の回答での引用(ai-input)・AI の学習(ai-train)を、すべて許可しています。
  • コメントで、役に立ったら Ko-fi で応援してほしい、と一言添えています。
  • robots.txt は、EmDash の管理画面の SEO 設定で全文を書けます。既定の内容が丸ごと置き換わるので、管理画面を除外する行(Disallow: /_emdash/)とサイトマップの行も自分で書きます。

更新を検索エンジンに知らせる(Crawler Hints)

Caching の構成画面で、Crawler Hints のスイッチがオンになっている

Crawler Hints をオンにすると、記事を公開・更新したときに、IndexNow で Bing などに通知されます。ChatGPT の検索や Copilot は Bing の索引も使っているとされるので、AI に早く拾われることを期待しています。オンにすると補足条項に同意したことになります。

AI エージェントには Markdown を返す

AI Crawl Control の概要画面。エージェント用 Markdown は Pro プラン限定で、Bot Preference Sync はオンになっている

Cloudflare の「エージェント用 Markdown」は Pro プラン限定なので、同じことをサイト側で自前で作りました。

Accept: text/markdown を付けて記事を取得すると、タイトル・URL・公開日などのフロントマター付きの Markdown が返ってくる
  • リクエストの Accept に text/markdown があるか、URL の末尾が .md なら、HTML の代わりに Markdown を返します。
  • 本文は EmDash の portableTextToMarkdown で変換し、先頭にタイトル・URL・公開日・更新日・要約を付けます。
  • HTML 側には <link rel="alternate" type="text/markdown"> で Markdown 版の場所を書き、Vary: Accept も付けます(キャッシュで HTML と取り違えないように)。

記事ページ(Astro)の先頭で、次のように分岐しています(要点だけ)。

import { portableTextToMarkdown } from "emdash/client";

const wantsMarkdown =
  Astro.url.pathname.endsWith(".md") ||
  (Astro.request.headers.get("accept") ?? "").includes("text/markdown");

if (wantsMarkdown) {
  const body = portableTextToMarkdown(post.data.content);
  return new Response(`# ${post.data.title}\n\n${body}`, {
    headers: { "Content-Type": "text/markdown; charset=utf-8", Vary: "Accept" },
  });
}
// HTML を返すときも、同じ URL で中身が変わることをキャッシュに伝える
Astro.response.headers.set("Vary", "Accept");

診断で確かめる

エージェントの準備状況の診断で、レベル1が5/5完了。Content Signals と Markdown Negotiation も完了になっている

エージェントの準備状況の診断では、レベル 1「すぐに実行できる改善」が 5/5 完了になりました。レベル 2 以降(API の一覧、AI 向けのログイン手順、コマースなど)は、サービスを提供するサイト向けなので、ブログでは対応していません。

6. EmDash 側でやったこと

  • 初期設定: サンプル記事は入れずに「Empty site」で始める(英語のダミー記事が公開されないように)。管理者はパスキーで登録する。
  • コメント: 既定は first_time で、初めてコメントする人の投稿だけが承認待ちになります(承認済みの人は次から即公開)。全件を承認制にしたいなら all にします。
  • 日本語向けの調整:
    • <html lang="ja"> と、文節での折り返し(word-break: auto-phrase など)をサイト全体に当てる(折り返しの記事)
    • 日付を日本語の書式・日本時間で表示する(Workers は UTC で動くため)
    • 読了時間を「分」表記にする
  • コードブロックの色付け: Astro に入っている Shiki で色を付け、light-dark() でライト/ダークに追従させる。
  • Ko-fi のボタン: 公式のボタン画像をサイトに置いて配信する(外部のスクリプトを読み込まない)。

Discussion

No comments yet