homelab notes ポート開放できない家の自宅サーバー

ローカル LLM を GPU で動かして UI から使う

Ollama と Open WebUI を別々に立てたら、UI からモデルが1つも見えなかった。 原因は Docker ネットワークで、そもそも一度も繋がっていなかった。

症状

Open WebUI の設定には OLLAMA_BASE_URL=http://ollama:11434 と書いてある。 なのにモデル一覧が空。コンテナの中から叩くと、

$ docker exec open-webui curl -s -o /dev/null -w '%{http_code}' http://ollama:11434/
000

名前解決すらできていない。

原因

Docker の内蔵 DNS でコンテナ名を引けるのは 同じユーザー定義ネットワークに参加しているコンテナ同士だけ。 2つは別々のネットワークにいた。

$ docker inspect open-webui --format '{{range $k,$v := .NetworkSettings.Networks}}{{$k}} {{end}}'
ai-net
$ docker inspect ollama --format '{{range $k,$v := .NetworkSettings.Networks}}{{$k}} {{end}}'
ollama_default

別々の compose ファイルで立てたので、それぞれのプロジェクト既定ネットワークに入っていた。

直し方

片方を、もう片方のネットワークにも参加させる。既定網は残す。

services:
  ollama:
    networks:
      # 既定網に加えて ai-net にも参加させ、UI 側から
      # http://ollama:11434 で名前解決できるようにする
      - default
      - ai-net

networks:
  ai-net:
    external: true      # 別の compose が作ったものを使う
$ docker exec open-webui python3 -c "
import urllib.request, json
d = json.load(urllib.request.urlopen('http://ollama:11434/api/tags', timeout=10))
print([m['name'] for m in d['models']])"
['qwen3-abliterated:8b', 'llama3.1:8b', 'qwen2.5-coder:7b']
curl が入っていないコンテナは多い。 Python が入っていれば urllib で代用できる。 わざわざパッケージを入れる必要はない。

GPU に載っているか確認する

「動いた」だけでは足りない。CPU で動いていても答えは返る。

$ curl -s http://127.0.0.1:11434/api/ps | python3 -c '
import sys, json
for m in json.load(sys.stdin)["models"]:
    t, v = m["size"], m["size_vram"]
    print("%s: 合計 %.2fGB / VRAM %.2fGB (%d%% GPU)" % (m["name"], t/1024**3, v/1024**3, 100*v/t))'
llama3.1:8b: 合計 4.91GB / VRAM 4.91GB (100% GPU)

size_vramsize と一致していれば全部 GPU に載っている。 一部だけだと極端に遅くなる。

初回の測定値を信じない

更新後の動作確認で、生成速度を測ったらこうなった。

1回目   1.9 tok/s     ← モデルのロード直後
2回目  54.5 tok/s     ← ウォーム状態
モデルがメモリに載っていない状態の1回目は、桁が違うほど遅く出る。 「更新で壊れた」と勘違いしかけた。ベンチは必ず2回目以降を見る。

API のレスポンスに内訳が入っているので、切り分けはそれで足りる。

load_duration         モデルのロード時間
prompt_eval_duration  プロンプト処理
eval_count / eval_duration  → 生成速度

モデルはバックアップしない

モデルの実体は 13.6GB あった。全部 ollama pull で再取得できるので、 バックアップ対象から外している。

$ docker run --rm -v <project>_ollama_data:/d:ro alpine du -sh /d
13.6G   /d

ボリューム名の前置に注意。名前を間違えると 空のボリュームが新規作成される

認証がないことを忘れない

Ollama の API には認証がない。リバースプロキシで https://ollama.<tailnet>.ts.net のような名前を付けると、 その VPN に参加している全員がモデルを叩ける。 1人で使っているうちは問題ないが、誰かを招く前に ACL で絞る必要がある。