道具の手触りや暮らしの思索を重ねながら、革しごとやガジェットに向き合う日々の試行錯誤の記録

デジタル手仕事 08|ブログに生活を混ぜない。ObsidianとMinIOを自作プラグインで仕分ける仕組み

デジタル手仕事
デジタル手仕事 08|ブログに生活を混ぜない。ObsidianとMinIOを自作プラグインで仕分ける仕組み
目次 ▼
嫁ちゃん 嫁ちゃん
この前作った画像の倉庫、ブログの写真だけやなくて、そら(愛犬)の写真とかプライベートなものも入ってるんやろ? ネットで見られたりせぇへんの?
わたし わたし
URL一覧は見えへん設定にしてるから基本は大丈夫なんやけど……やっぱり、同じ箱に入ってるの、ちょっと気持ち悪いよな。
嫁ちゃん 嫁ちゃん
気持ち悪いわ。大事なもんは別の引き出しに入れとき。
わたし わたし
せやな。引き出し、きっちり分けて作り直すわ。

MinIOの環境を構築した後に残った「気になる点」
#

前回、Obsidian Syncの1GB上限を回避するため、自宅のM1 Mac miniにMinIOを立てた。

重たい画像やPDFをVaultの外へ逃がし、テキストだけを同期させる。画像はすべて https://okadai.me/lili-memory-image-bucket/... という公開URLで参照する仕組みを整え、容量の圧迫という悩みからは無事に解放されたはずだった。

けれど、仕組みがうまく回り始めて数日と経たないうちに、胸の奥に「モヤっ」とした小さな違和感が残り始めた。

妻の素朴な問いかけが、まさにその急所を突いていた。 私がObsidianに放り込む画像は、ブログに掲載する革しごとの道具や制作途中の写真だけではない。 愛犬のチワワ「そら」が無防備なお腹を見せて寝ている日常の一コマ、スーパーの買い物メモ、工房の棚の配置メモ。そうした、世界に見せる必要のまったくない私生活の断片が、すべて同じ「世界公開されているバケット」の中に同居していたのだ。

もちろん、技術的な理屈は分かっている。 MinIOの前段に置いたNginxでは、ディレクトリの一覧表示(autoindex)を無効にしている。アップロードされるファイル名は推測不可能なハッシュ文字列やタイムスタンプが振られているため、URLを第三者にピンポイントで当てられない限り、勝手に覗き見られる可能性は極めて低い。それくらいは、元プログラマーとしても当然把握していた。

実を言えば、いずれMinIOのバケットを公開用と非公開用の2つに分けるべきだということは、最初から頭の片隅にあったのだ。 ただ、前回はまず画像ストレージとして動かすことを最優先にしたかったし、何より設定や実装が少し面倒そうだったから、「まあ、一覧は見えないんだし後でやればいいか」と見て見ぬ振りをしていただけだった。

けれど、生活者としての自分が、静かに首を振る。

玄関のドアを開け放ったまま、「部屋の奥の引き出しには鍵がかかっているから大丈夫」と言い張っているような居心地の悪さ。 万が一の設定ミスや、URLの誤送信ひとつで、そらの間抜けな寝顔や生活の記録が外に出てしまうかもしれないという不安な感覚。 「気をつけて扱えば大丈夫」という運用の注意深さに依存した安心は、手仕事の道具として決して健全ではない。

そもそも、なぜ最初からバケットを1つだけにしていたのか。 理由は単純で、既存のObsidian用S3プラグインが「バケットを1つしか扱えない仕様」だったからだ。設定画面にはバケット名の入力欄がひとつしかない。だからこそ、分けるとなれば手元の環境ごと手を入れる必要があり、腰が重かったのだ。

けれど、もう言い訳はやめよう。後回しにしていた宿題に、きっちりケリをつけることにした。


設計の引き算:「コンテナを増やすな、出口を消せ」
#

二重底の道具箱のようなストレージの境界線

境界線を引くと決めたとき、まず立ち止まって考えたのは「いかに仕組みを複雑にしないか」という引き算の設計だった。

プライベートな画像を分けるために、いくつかのアプローチが頭をよぎる。

  1. フォルダ(プレフィックス)で分ける 同一バケットの中に public/ と private/ のようなフォルダを作り、Nginx側で private/ へのアクセスを拒否するルールを書く。 ——もっとも手軽に見えるが、Nginxのロケーション設定に一行のミスがあれば一瞬で漏れる。心理的なトゲを抜く解決策としては心許ない。
  2. MinIOのDockerコンテナをもう1基増設する 公開用MinIOと、完全非公開用MinIOを別コンテナ・別ポートで動かす。 ——隔離としては完璧だが、管理コストが二倍に膨らむ。自宅サーバーで走らせる常駐コンテナは必要最小限に留めたい。これは「引き算の美学」に反する。
  3. 同一MinIO内で「バケット」を分ける(採用) ひとつのMinIOプロセスの中で、ブログ公開用の lili-memory-image-bucket とは別に、完全プライベート用の lili-memory-private-bucket を作成する。

この3つ目のバケット分割を採用したうえで、決定打としたのは極めてシンプルな設計思想だった。

「非公開バケットには、外への出口(Webルート)を1行も書かない」

Nginxの設定ファイルにおいて、okadai.me の公開サーバーブロックには lili-memory-image-bucket へのプロキシ転送だけを記述し、新しく作った lili-memory-private-bucket に関する設定は一切書かない。 リバースプロキシの出口が存在しない以上、インターネット側からどれほど巧妙なリクエストを送ろうが、Cloudflare Tunnelをどう潜り抜けようが、外の世界からそのバケットに到達する経路そのものが物理的に存在しない。

この非公開バケットにアクセスできるのは、アトリエの宅内LAN、あるいはTailscaleのセキュアなメッシュVPNで繋がった私の個人端末だけだ。 「鍵をかけて守る」のではなく、「そもそも外に通じるドアを作らない」。 それだけで、運用の緊張感は劇的に和らぐ。


私が使うことだけを前提とした:自作プラグイン do-minio-uploader
#

だが、サーバー側に非公開バケットを用意しただけでは、仕事の半分しか終わっていない。 問題は、それを扱う手元の「UI」の振る舞いだった。

そもそも、手元のObsidianを「ブログ公開用」と「プライベート用」でVault自体を2つに分けてしまえば、こんな面倒な工夫は要らなかったのかもしれない。それぞれのVaultで別々のS3プラグイン設定を持たせれば済むからだ。

けれど、私はVaultを複数に分けるのが単純に好きではなかった。日々の思考も、読書メモも、ブログの下書きも、すべてがひとつの大きな机の上に並んでいてほしい。思考の境界線を、エディタの切り替えという摩擦で分断されたくないのだ。

それに加えて、私が使っているObsidian SyncのStandardプラン(1GB)は「同期できるVaultが1つ」という制限がある。Vaultを2つに分けるとなれば上位のPlusプラン(10GB)へ切り替える必要があり、月額コストを増やしたくないという「引き算の設計」にも反してしまう。

だからこそ、ひとつのVaultの中で解決する必要があった。 しかし、背後のバケットを2つに分けたところで、Obsidianに画像をドラッグ&ドロップするたびに、 「これはブログ用だから公開バケット……」 「これは日々のメモだから非公開バケット……」 と人間が手作業でアップロード先を選んでいたのでは、いつか必ず間違える。疲れている夜や急いでいるときに、判断を誤ってポイと放り込んでしまうのが人間の常だ。

人間の「注意深さ」に依存する運用は、いずれ仕組みの失敗を招く。 理想は、これまでと何ひとつ変わらず、手元のエディタへ無造作に画像を放り込むだけで、しかるべき引き出しへと勝手に収まることだ。

既存のプラグインにないなら、作るしかない。 幸い、私には以前自作したPDFアップローダーのスクリプトがあった。これを拡張し、画像とPDFの両方に対応した自分専用のObsidianプラグイン「do-minio-uploader」を仕立てることにした。

仕分けのロジックは極めて明快にした。

// アクティブなノートが hugo-site/ 配下にあるかどうかでバケットを切り替える
const isInHugo = activeFile?.path.startsWith('hugo-site/');

const targetBucket = isInHugo
  ? 'lili-memory-image-bucket'    // 公開:ブログ記事用
  : 'lili-memory-private-bucket';  // 非公開:日々の思考・生活用

手元のObsidianにおいて、Webに公開される文章はすべて hugo-site/content/posts/ という決まったディレクトリの下で書いている。それ以外のノート——日々の壁打ちメモや読書録、家計や愛犬の記録は、すべてVaultの別のフォルダに鎮座している。

つまり、「いま開いているノートのパス」を見るだけで、その画像が外部に見せるべきものか、私生活の記録であるかは100%自動で判定できる。

  • hugo-site/ 配下の記事に画像をドロップした場合: 公開バケットにアップロードされ、https://okadai.me/lili-memory-image-bucket/... の公開URLが挿入される。
  • それ以外のノートに画像をドロップした場合: 非公開バケットにアップロードされ、宅内LAN/Tailscale経由でしか開けない http://192.168.10.15:9000/lili-memory-private-bucket/... のローカルURLが挿入される。

エディタを触っている私の手元には、選択肢のダイアログすら出ない。 ただ思考のままに画像を貼り付けるだけで、境界線が静かに、そして確実に引かれる。


大掃除:155件の引越しとパージの爽快感
#

整理整頓され、余計なものが消えた静かな作業台

道筋が整ったところで、最後の大仕事が待っていた。 これまで公開バケットにごちゃ混ぜになってしまっていた既存の画像を救出し、掃除することだ。

スクリプトを走らせてVault内を精査すると、ブログ以外のプライベートなノートから参照されていた画像が「155件」見つかった。 これらをすべてローカルサーバー経由で新設した非公開バケット(lili-memory-private-bucket)へと転送・コピーする。

続いて、Vault内のMarkdownノート80ファイル、計157箇所に散らばっていた画像リンクのURLを、一括置換で新しい非公開パスへと書き換えていく。 手作業なら面倒な作業だが、正規表現とスクリプトの力を借りれば一瞬で整う。手元のObsidianで過去のノートを開き、そらの写真や過去のメモの画像が何事もなかったかのように綺麗に表示されるのを確認した。

そして、仕上げのパージ(消去)だ。 公開バケット(lili-memory-image-bucket)に残された、本来そこにあるべきではなかった155件のプライベート画像データを完全に削除した。

移行したのは、たったの155件。人から見れば「そんな些細な数」かもしれない。けれど、これが数千枚、数万枚と溜まって取り返しのつかない混沌になる前に、早いうちに方針を決めて境界線を引けたのは本当によかったと思う。

外付けHDDのアクセスランプが静まり返り、公開バケットの中身が「純粋なブログ用のアセットだけ」になった瞬間、胸のすくような爽快感が広がった。

ちなみに、今回MinIOのデータ保存先としてM1 Mac miniに繋いでいるのは、以前使っていたNASから流用したハードディスクだ。新しく高価な外付けストレージを買い直すのではなく、手元にあったドライブを玄人志向のシンプルなスタンド(KURO-DACHI)に挿して使っている。机の片隅で無骨に、けれど文句ひとつ言わずに静かに動いてくれるこういう道具立てが、私の身の丈にはちょうどいい。

それは、散らかり放題だった革の作業机の上を箒で掃き清め、散乱していた菱目打ちや革包丁をそれぞれの鞘に戻し、から拭きしたときの手触りにとてもよく似ていた。


おわりに:道具に気を遣わせないための手仕事
#

もちろん、私は単純に効率化だけを求めてこんなことをしているわけではない。Dockerの設定を試行錯誤したり、TypeScriptでプラグインを組んだり、思い通りの環境を手作業で構築していくその過程自体が、ものづくりとして楽しくて好きなのだ。

けれど、楽しんで作ったはずの仕組みのせいで、日々の執筆中に「これは漏れていないだろうか」「間違えていないだろうか」と人間が神経を尖らせていては本末転倒だ。

デジタル手仕事の本当の面白さは、手を動かして作る楽しさを味わったあと、余計な心配事を日常から消し去って、大切なことに没頭できる「心の余白」を手に入れることにある。

公開と非公開の引き出しがきっちりと分かれた今、私は何も気にすることなく、愛犬が足元で丸まっている姿をスマートフォンで撮り、手元のObsidianに放り込むことができる。 そして何食わぬ顔でブラウザを閉じ、革を裁ち、針に麻糸を通す時間へと戻っていく。

嫁ちゃん 嫁ちゃん
……で、ちゃんと大事なもんとブログの引き出し、分かれたん?
わたし わたし
うん、バッチリや。これでそらの間抜けな寝顔も、家の領収書も、外からは絶対に見えへん安全な場所に勝手に収まるようになったわ。
そらちゃん そらちゃん
くぅ〜ん……(安心したようにひと伸びして、また丸くなる)
嫁ちゃん 嫁ちゃん
そらも『これで安心して昼寝できるわ』ゆーてるわ。
わたし わたし
せやな。そらの昼寝を邪魔せんように、私も静かに革を縫うとするわ。

安全が仕組みとして担保されているからこそ、道具の存在は背景へと退いていく。 目立たないけれど頼もしい、そんなデジタルの手仕事をひとつずつ重ねていくことが、私にとっては何より心地よい。


※本サイトの漫画やイラストはフィクションであり、実在の製品・団体・人物・地名とは関係ありません。

※本サイトに掲載する情報には充分に注意を払っておりますが、その内容について保証するものではありません。

※本サイトの使用ならびに閲覧によって生じたいかなる損害にも責任を負いかねます。