whywaita Advent Calendar 2025 20日目です。 whywaita Advent Calender 10周年、おめでとうございます。
前回は hydrogen さんの記事でした。 今のところ無です。 whywaitaからリマインドされたときに若者とnot 若者の遅刻の定義が違うと言う話をされました。 担当日の0時までに投稿しないと遅刻という人と、担当日の23:59までに投稿すればセーフという人がいるらしいです。 自分は若者 && 担当日の23:59までに投稿すればセーフだと思っているので、not 若者は0時までに投稿するんだな〜、やっぱ Advent Calendar 原理主義なんだな〜とか思ってたら、若者が0時までに投稿できなくて謝ってきたらしく、俺はnot 若者だったらしいです。 年をとったなあ。
また、whywaita との関係性に最初に触れれば、あとはなにを書いてもwhywaita Advent Calendar になるというもの。 とはいえ wahywaita との関係性は多く、つい昨日までも仕事の合宿で二泊三日寝食を共にし、もはや作家を軟禁する編集のような気分でした。 whywaita 先生、引き続きよろしくお願いします。
さて、本題ですが自宅サーバーの話です。 MMAのアドベントカレンダーでサーバーラックを買った話 をしてから早9年がたったようです。 学生の頃は自宅サーバーの話をこすり続けましたが、社会人になって一人暮らしを始めるとともにサーバーラックを卒業しました。 そこから静かな部屋で眠ることを学び、NASのHDDの回転音にもキレそうになったため、自宅サーバーもおさらばかなと思っていましたが......

今年普通にサーバーラックを買いました。 コレです。めっちゃやすいし、タンスの上に置けて取り回ししやすくて最高。 普通にユニット数がたりないので8Uにすればよかったです。
ただ、スイッチはセミファンレスにしました。 サーバーも自作ベースでファンはすべてNoctuaにし、最初はオールSSDにしていてめっちゃ静かでした。 データ量が思ったよりも多くなったのでHDDを増やしましたが、深夜のデータアクセスを減らすようにデザインしました。 夜中もずっとファンの音を子守歌にしていたあの頃と比べてすごく大人になっています。 今回はそんな自作サーバーで作っているものを紹介します。
自宅サーバーで何を動かしているのか
皆さん自宅サーバーをやっている人たちは一度は思うことがあるのではないのでしょうか?
「最強のプライベートGoogle Driveがほしい...」
世はまさに大AI時代のなので、そんな夢を Claude Code Max $100 を個人契約してかなえていこうと思います。 ただ、実は2021年に一度チャレンジしていたりします。 その辺の反省も踏まえて開発しています。
全体アーキテクチャ
コンポーネントは、主にファイルシステムをHTTP経由でアクセスできるようにするn0fsと、MySQLベースでファイルに対してメタデータを付与するn0indexに分かれます。 概要図は以下のようになります。
それぞれをひとつのコンソールで確認することができます。 例えばn0fsベースではファイルシステムに対してそのままアクセスできるため、以下のようにGoogle Driveのようなディレクトリ構造でアクセスできます。

また、以下のようにn0indexを参照してタグベースでコンテンツを検索できるようになっています。 スマホ表示もいい感じに対応しています。 データは昔 Pixiv からアーカイブしておいたものを表示しています。

前回のシステムはn0fsのような抽象レイヤを用意せずに、実ファイルの保存をsha256のuidでminioに保存する方式をとったため、そのシステムの運用をやめた結果残ったのはなにもわからないsha256の名前のファイル群だけになってしまいました。 今回は、HTTPのサービスをファイルシステムに後付するような構成をとっているので、それを改善できています。 (そのデータもAIに当時のMySQLと突合させて復元できました)
n0fs
n0fs は AWS S3 を参考にしたシンプルなHTTPサーバーです。 基本的なデザインは
GET /fs/:file_path: ファイルの参照HEAD /fs/:file_path: ファイルの参照PUT /fs/:file_path: ファイルの保存DELETE /fs/:file_path: ファイルの削除
になっており、まるで原初のHTTPです。 ここからクエリパラメータで以下のような機能を実装しています。
| メソッド | クエリパラメータ | 機能 |
|---|---|---|
| GET | ?directory |
指定されたディレクトリの配下のリストをJSONで返す |
| GET | ?sha256 |
指定されたファイルのsha256を返す |
| GET | ?image |
libvips で画像のリアルタイムリサイズやクリッピングなど |
| GET | ?image_attribute |
画像の情報(解像度やEXIFなど)をJSONで返す |
| GET | ?video |
ffmpeg で画像のリアルタイムエンコード |
| GET | ?video_attribute |
映像の情報をJSONで返す |
n0fsはファイルシステムのみをバックエンドとして持つので、サムネイルなどをキャッシュとしては持たないようにしています。
また、ffmpegは AI に良しなに頼むことで NVENC によるハードウェアオフロードがきいています。 使っているGPUは GT710 なので1920x1080は若干速度が怪しいですが、十分動きます。 ffmpegのパラメータチューニングは職人芸ですが、AIは非常に強力でした。 例えば映像をリサイズする場合
- 映像をデコード
- 映像のリサイズ
- 映像のエンコード
を行う必要があるのですが、 1と3は NVENC と NVDEC によってハードウェアオフロードがきき、2はCUDAによってオフロードがききます。 ただ、GT710が古すぎてCUDAに制限があったため、リサイズはCPUで行う必要がありました。 そのため、GPUに送ってデコードし、CPUに戻してリサイズし、GPUに送ってエンコードして、とCPUとGPUを行ったり来たりすることが発生します。 しかし、いろいろAIに任せきりでベンチマークを取ったところ、CPUでデコードしてリサイズまでやり、エンコードだけGPUにやらせるほうが早かったのです。 不思議ですが、この辺の試行錯誤が手軽にできたあたり時代は変わったなあと思いました。
結論として、この辺の拡張されたファイルシステムを組み合わせることでコンソールでは
などを実現しています。
n0index
n0index は n0fs をベースにコンテンツとしてのアクセス性を上げるために、MySQLにメタデータを保存して拡張します。 MySQLのER図は以下のような形になります。
大きく分けると
という2種類のエンティティがいます。 工夫ポイントとしては以下のような感じです。
- FileのPKはファイル自身のsha256にすることで、同一ファイルをダウンロードした場合や、ファイルを移動した場合でも、メタデータが追従できるようにしました。
- File の sha256 ハッシュとファイルパスの関係はキャッシュしてあり、ファイルの更新日時とファイルサイズをもとに、パスのsha256の再計算をスキップしています。
- Contents から File への紐づけはページ番号を付与することで、思った通りの順番で表示できます。
- File には Title や Description のような、手動で管理するようなメタデータを入れないように割り切り、解像度などの自動で管理するメタデータのみを格納することで、シンプルにしています。
- APIはGraphQLを採用しています。SQLの最適化はAIにぶん投げです。
とりあえず、ここまででかなり Google Drive のような利用感を実現できているのですが、ここからさらにAIによるファイルに対するタグ付けやベクトル検索の対応などをするとさらによさそうな気がしています。 そのためQdrantを入れてみたりしているのですが、すでに180万ほどファイルがあるのでベクトル化にも一苦労しています。 GT710だとCUDAが弱すぎるし...... そもそもHDDの残容量が500GBを切っていて心もとないし...... HDDも高くなっててつらい...... やっぱりサーバーを4UくらいにしないとHDDもGPUも刺さらん...... でも、ラックのユニット数が足りてない...... っていう現状です。今後に期待。
まとめ
遅刻せずに間に合いました(not 若者基準)。 正直かなり満足するものが作れています。 仕事の後の時間をつかって、二週間でここまで来れているので、AIは大したものです。 自分がほくほくするために作っているのでコードを公開するつもりはありませんが、皆さんも一家に一台サーバーを構築してやってみてはいかがでしょうか。
ところで急に知見を書きますが、Google TVのYouTubeが不調な人はIPv6を切ると調子がよくなるかもしれません。 うちはログインすらできない環境でしたが、IPv4だけにしたら改善しました。 フレッツ光 1G / Biglobe (PPPoE併用) / ひかり電話なし (/64 RA) みたいな環境です。 IPv6を使えとどこかから圧を感じますが、困ってたら是非。 Google TVにリンクローカル以外のIPv6アドレスが2個ついていたのが気になったりもしたので、対策を知っている方がいれば教えて下さい。
