
K3s自宅AIファクトリー構築:LibreChat + vLLM + Nemotron をブラウザ/スマホから使えるようにする
最近やってるAIファクトリー構築の続きです。
今回は、自宅のK3s環境上で、LibreChat をフロントに置き、vLLM 上の Nemotron をブラウザから使える構成を組みました。
最終的に、
PCブラウザ
iPhone
の両方から chat.home.lab でアクセスし、チャットUI経由でローカルLLMに到達できるところまで確認できました。
今回やったことは、単にローカルLLMを起動することではなく、AIをサービスとして出す最小構成 を自宅で再現することです。
全体構成
構成はシンプルにするとこうです。
[ Browser / Smartphone ]
↓
chat.home.lab
↓
[ AdGuard DNS ]
↓
[ ingress-nginx / MetalLB ]
↓
[ LibreChat ]
↓
[ vLLM / Nemotron API ]
↓
[ GPU Node ]
+ MongoDB(会話履歴・ユーザー情報)要するに、
DNS → Ingress → UI → 推論API → GPU
の流れをK3s上で成立させています。
今回の主な構成要素
LibreChat (NEW)
チャットUI。OpenAI互換APIクライアントとして動作。vLLM + Nemotron
GPU上で動く推論サーバ。/v1/* のOpenAI互換APIを提供。MongoDB (NEW)
LibreChatの状態保持用。Ingress-nginx + MetalLB
LAN内から chat.home.lab で到達するための入口。AdGuard Home
chat.home.lab -> 192.168.50.241 の名前解決を担当。
構築の流れ
1. MongoDB を先に構築
LibreChat は状態を持つので、まず MongoDB を ai-apps namespace 上に作成しました。
ここで必要だったのは、
PVC
Deployment
Service
の3点です。
MongoDB のデータは永続ボリューム(今回は NFS)に保存する必要がありますが、最初はここでエラーになりました。
原因は、コンテナ側のユーザーと、NFS 側の書き込み権限が一致しておらず、データディレクトリに書き込めなかったためです。
そのため、securityContext を設定し、MongoDB コンテナの実行ユーザーをボリューム側に合わせることで解決しました。
また、MongoDB は同じデータ領域を複数のインスタンスで同時に扱うことができないため、
Kubernetes のデフォルト設定である「古いコンテナを残したまま新しいコンテナを起動する(RollingUpdate)」とは相性がよくありません。
このままだと、同じストレージを複数のコンテナが同時に使おうとして不整合が発生します。
そこで、古いコンテナを完全に停止してから新しいコンテナを起動する方式(Recreate)に変更しました。

2. vLLM / Nemotron を再起動して API確認
推論系は以前の検証後に scale 0 にして止めていたので、まず Deployment を戻しました。
その後、モデルロード完了まで待ち、/v1/models が返ることを確認。
返ってきた served model name は nemotron-fp8 でした。
(過去にFP16の実装後に追加した軽量テスト用モデルです。)
ここで重要なのは、Pod が Running でも、モデルロード完了前はまだ使えない ことです。
Nemotronクラスだと、起動後しばらくは待つ必要があります。
(NASの2.5Gbps 回線からのマウントが原因と思われます)

3. LibreChat をデプロイ
LibreChat 側では最低限、
MONGO_URI
OPENAI_REVERSE_PROXY
JWT_SECRET
JWT_REFRESH_SECRET
を設定して起動。
最初は JWT secret が足りず落ちましたが、追加後は安定して 1/1 Running になりました。
MongoDB との接続も通り、LibreChat Service の endpoints も正常に入りました。

4. Ingress で chat.home.lab を公開
librechat Service に対して Ingress を作成し、host を chat.home.lab に設定。
ingress-nginx の LoadBalancer IP は 192.168.50.241 だったので、
このIPを DNS 側で引けるようにすれば外から入れる構成になります。

5. AdGuard で DNS登録
AdGuard Home に
chat.home.lab -> 192.168.50.241を設定。

最初は Windows 側が IPv6 の外部DNSを優先していてうまく引けませんでしたが、
NIC の DNS を AdGuard に固定し、IPv6 側を整理することで解決しました。
ここはK8s側ではなく、クライアントの名前解決経路の問題 でした。

PC と iPhone の両方で確認
まず PC で http://chat.home.lab にアクセスし、LibreChat のログイン画面が表示されることを確認。


その後、iPhone でも同じURLにアクセスし、同様に表示されることを確認しました。


iPhone 側は最初そのままでは開けず、Wi-Fi 側の DNS を AdGuard に向ける必要がありました。
これで、PCだけでなくスマホからもローカルAIチャット基盤へ到達可能 になりました。
動作確認と今後の課題
LibreChat から nemotron-fp8 を選んで投げると、応答自体は返ってきました。
つまり、以下の全経路が実際に機能しています。
ブラウザ / スマホ
DNS
Ingress
LibreChat
vLLM / Nemotron
GPU
ただし、出力内容には課題がありました。
Nemotron 側が reasoning 風のテキストをそのまま返してしまい、LibreChat にもそれが表示されます。(先のスクショ通り)
なので今回の評価はこうです。
基盤PoCとしては成功
出力品質は今後の改善対象
今回の到達点
今回の構築で確認できたことは以下です。
K3s上で LibreChat + MongoDB + vLLM を統合
Ingress 経由で chat.home.lab からアクセス可能
AdGuard を使ったローカルDNS運用
PC / iPhone の両方から動作確認
Nemotron へのチャット到達まで確認
つまり、
ローカルGPU推論を、ブラウザから使えるAIサービスとして出す最小構成
は成立しました。
今後の改善点
今後はこのあたりを詰めたいところです。
Nemotron の出力制御(思考っぽいテキストの抑制)
LibreChat 側のモデル設定整理
まとめ
今回やったのは、ローカルでLLMを動かすだけではなく、
AIをサービスとして利用できる形まで整える ところです。
K3s、GPU推論、MongoDB、Ingress、DNS をつないで、
PCとスマホの両方から chat.home.lab でアクセスできるところまで持っていけたので、PoCとしてある程度のカタチとなったところです。
一方で、実際に使いやすいAIサービスにするには、モデル出力制御やUI側設定の調整がまだ必要です。
とはいえ、自宅環境でもここまでは普通に再現できる、というところまでは確認できました。
本日はここまで
2026/4/2