一覧に戻る

ObsidianをCMSとしてブログを作る

#obsidian#cloudflare

このブログはObsidian + Cloudflare R2 backendでお送りします

はじめに

エンジニアたるもの「ポートフォリオサイト」が必要であるということで、過去何度も作ったり壊したりしてきている。

https://kiguchi999.hatenablog.com/ ポートフォリオサイトというか単なるブログ。昔は有料化してお名前.comで買った独自ドメインをあてたりしていたが、今振り返るとはてブロは高額すぎた。

https://spatialty-io.spatialty.workers.dev/ spatialty.ioとして最初に公開していたページ。SvelteKit + Cloudflare Pages + Newtで作られている。良い感じのオウンドメディアを構築するお仕事の事前学習を兼ねて。

https://portfolio-spatialtyio.super.site/ Notion + Super。ContentsをManagementして良い感じにWeb公開するというニーズの最小手数であると思う。他にはWraptasも試したりした。

そしてこのサイトが2025年7月現在最新のもの。Remix + Cloudflare Workersで構築している。Remixを選んだのは使ったことがなかったから。UIは大部分Claude Codeに書かせている。

ただしこのサイトにはブログがなかった。Newtはサ終するからどうしようかなぁと思っていた折、ObsidianをCMSにするという記事を読んだので、作り直してみることにした https://qiita.com/nasubi_dev/items/2237101b170f7327e4a0

Obsidianの構成

上記の記事を読めば、Cloudflare R2を保存先とすることは簡単。あとはどうやって読み出すか。R2はS3互換で、データを一覧したり、取得したりは結構プリミティブなものしか提供されていない。また、画像などのアセットももちろん保存できるのだが、それをWebサイト上でそのまま表示できるかというとそういうこともない。ということで、以下のような「規約」のもと設計した。

  1. 記事のファイル名に一定の命名規則を設ける
  2. 記事のフォルダと画像などのアセットのフォルダを分ける

ファイル名の命名規則

R2(=S3互換)でオブジェクトの一覧を取得する場合はListObjectという操作を行うが、これはあまり柔軟なクエリができるわけではなく、最大1000件(ページング可)のオブジェクトを常に昇順で引いてくるようなもの。もちろん個別ファイルの中身を見ることは出来ない(N+1をやれば出来るけどもちろんやらない)。なので、下記のような規則でファイルを命名することで、ファイル名から投稿日とタイトルがわかるようにした。

yyyy-mm-dd_title of post.md

これにより、ListObjectで得られる情報だけで、記事の一覧ページを最低限組み立てることができる。以下のようなトレードオフがある。

  • ページングのことは考えておらず、1000件まではまとめて取得する想定。クライアントサイドでページングはあり得るかもしれない。これまで10年くらいで書いた技術記事全てを合計しても1000件に達していないので向こう5年くらいは問題ないだろう。
  • タグによる絞り込みは出来ない。
  • 降順でクエリすることはできないが、Webサイト上では降順で表示したいので、全件取得してオンメモリでソートしている。prefixが年月日になっているので、昇順ソートは可能。1000件くらいならオンメモリでええやろ精神。

画像アセットの配置

前述のObsidianのスクリーンショットを見るとわかるが、assetsフォルダを別に作成して、画像は全てそこに放り込んでいる。特定の記事に関する画像アセットはその記事の近くにあるべきという考え方を持っているので、当初は記事単位でフォルダを作成し相対パスで読んでいたが、これをやるとListObjectで記事以外のアセットが引っかかってしまい、記事一覧の構築に支障をきたした(単純な対処としてはMarkdown以外をフィルタすればよいのだが、最大1000件の制限にすぐヒットしてしまうだろう)。ということで、完全に別のフォルダ(prefix)とした。 そのうえで、このR2バケットをパブリックアクセス可(=Cloudflareではカスタムドメインをあてる)とし、Webサイト側ではSSRでObsidian上の相対パスをアセットへのURLに良い感じに書き換えることで、全体としてシンプルに保っている(このパスの書き換え自体はシンプルで、Markdown内の相対パスに、R2バケットのドメインを付与しているだけ)。

例:
![](assets/2025-07-27_01.png)
-> https://blog-assets.spatialty.io/assets/2025-07-27_01.png

終わりに

安さ・シンプルさを手にいれるために結構なトレードオフを受け入れいてる状態。タグやカテゴリで絞り込みも出来ないし、パフォーマンスが良いはずもなく。何らかのインデックスページをObsidian側で作っておくのがObsidianっぽいんだと思う。まあ個人ブログなのでシンプルさが一番だいじとしておく。今後はQiitaとかの記事をせっせとお引越ししていこうかと思っている(した)。