OllamaをDocker Composeでマルチサービス構成にデプロイする方法|Open WebUI・NginxをYAMLで一元管理してチーム運用を安定化させる

宮崎智広 この記事の監修:宮崎智広(Linux実務・教育歴20年以上・受講者3,100名超)
HOMELinux技術 リナックスマスター.JP(Linuxマスター.JP)ローカルLLM > OllamaをDocker Composeでマルチサービス構成にデプロイする方法|Open WebUI・NginxをYAMLで一元管理してチーム運用を安定化させる
「Dockerでサービスを個別に起動しているが、起動順が崩れると連携が壊れて毎回手動で対処している」
「OllamaとOpen WebUIとNginxをバラバラにdocker runで管理していて、チームメンバーへ手順を共有しても再現できないと言われる」
そんな状況に直面しているLinuxサーバー管理者は少なくない。この記事では、OllamaとOpen WebUI・NginxをDocker Composeのマルチサービス構成にまとめる手順を解説する。
起動順制御・ネットワーク分離・ボリューム永続化・ヘルスチェックまでをYAML1ファイルに集約することで、docker compose up -d一発で全サービスが立ち上がる再現性のある運用環境を構築する。GPUパススルーの設定方法と、運用でよく踏むトラブルの対処法も合わせて示す。

この記事のポイント

・Ollamaのhealthcheckcondition: service_healthyでOpen WebUIの起動順を確実に制御できる
networks.backend.internal: trueでOllamaを外部ネットワークから構成レベルで隔離できる
・GPUパススルーにはnvidia-container-toolkitとdaemon.jsonのランタイム設定が前提条件になる
・docker-compose.ymlをGitで管理すれば別サーバーでも完全再現できる環境になる


OllamaをDocker Composeでマルチサービス構成にデプロイする方法|Open WebUI・NginxをYAMLで一元管理してチーム運用を安定化させる

「このままじゃマズい」と感じていませんか?
参考書を開く気力もない、同年代に取り残される不安——
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

Docker ComposeでOllamaを一元管理する構成上のメリット

単体コンテナをdocker runで個別に起動する方法と比べて、Docker Composeには明確な利点がある。まず、サービス間の依存関係(depends_on)を宣言的に定義できる。OllamaのヘルスチェックがパスするまでOpen WebUIを起動しない、という起動順制御がYAMLで書けるため、手動での順序管理が不要になる。
次に、ネットワーク分離が構成レベルで実現できる。Ollamaを内部ネットワーク専用に閉じ込め、外部にはNginx経由のポートだけ露出する設計が数行のYAMLで完結する。
さらに重要なのが再現性だ。docker-compose.ymlnginx.confをGitリポジトリで管理すれば、別サーバーでもgit clone後にdocker compose up -dだけで同一環境が立ち上がる。現場でよく聞く「手順書が古くてdocker runの引数が違っていて動かない」という問題が根本から解消される。
なお、Ollamaのインストールや初回セットアップについてはUbuntu ServerでローカルLLMを構築する方法で詳しく解説しているので、環境を一から作る場合はそちらも参照してほしい。

前提条件と環境の確認

1. DockerとDocker Composeのバージョン確認

この記事はDocker Compose V2(docker composeサブコマンド形式)を前提とする。旧来のV1(docker-composeコマンド)とはYAML構文に差異があるため、バージョンを先に確認する。

$ docker --version Docker version 27.3.1, build ce12230 $ docker compose version Docker Compose version v2.29.7

Docker Compose version v2系であれば問題ない。V1のまま残っている環境はsudo apt install docker-compose-pluginでV2に移行する。

2. NVIDIA GPUドライバとnvidia-container-toolkitの確認

GPUを使ってLLM推論する場合、ホストに以下の2つが揃っている必要がある。

$ nvidia-smi +-----------------------------------------------------------------------------+ | NVIDIA-SMI 550.120 Driver Version: 550.120 CUDA Version: 12.4 | |...(省略)... $ dpkg -l | grep nvidia-container-toolkit ii nvidia-container-toolkit 1.17.2-1 amd64

nvidia-container-toolkitが入っていない場合は以下でインストールする。

$ sudo apt install -y nvidia-container-toolkit $ sudo nvidia-ctk runtime configure --runtime=docker $ sudo systemctl restart docker

CPUのみの環境では、後述のdocker-compose.ymlからGPU設定ブロックを削除するだけで動作する。

3. 作業ディレクトリの作成

$ mkdir -p ~/ollama-compose/nginx $ cd ~/ollama-compose

以降の操作はすべてこのディレクトリを基点にする。

docker-compose.ymlの基本構成を作る

1. Ollamaサービスのみの最小構成

まずOllamaコンテナだけを定義した最小構成から始め、後続ステップでサービスを追加していく。

# ~/ollama-compose/docker-compose.yml services: ollama: image: ollama/ollama:latest restart: unless-stopped ports: - "11434:11434" volumes: - ollama_models:/root/.ollama deploy: resources: reservations: devices: - driver: nvidia count: all capabilities: [gpu] volumes: ollama_models:

deploy.resources.reservations.devicesブロックがGPUパススルーの設定だ。CPUのみの環境ではこのブロックごと削除する。
volumes.ollama_modelsで名前付きボリュームを定義することで、コンテナを削除・再作成してもモデルデータが消えない設計になる。ボリュームの実体は/var/lib/docker/volumes/ollama-compose_ollama_models/に保存される。

2. 起動と動作確認

$ docker compose up -d ollama $ curl http://localhost:11434/api/tags {"models":[]}

空のモデルリストが返ればOllamaは正常に起動している。この時点でモデルはまだ入っていないので、docker compose exec ollama ollama pull llama3.3:70b-instruct-q4_0で必要なモデルをダウンロードしておく。どのモデルを選ぶべきかはローカルLLMのモデルを比較する方法が参考になる。

Open WebUIコンテナを追加する

1. open-webuiサービスとヘルスチェックの定義

Open WebUIはGitHubコンテナレジストリ(ghcr.io)からイメージを取得する。OLLAMA_BASE_URL環境変数でOllamaコンテナのエンドポイントを指定するのがポイントだ。
同時に、Ollamaサービスにhealthcheckを追加してOpen WebUIの起動順を制御する。

services: ollama: image: ollama/ollama:latest restart: unless-stopped volumes: - ollama_models:/root/.ollama deploy: resources: reservations: devices: - driver: nvidia count: all capabilities: [gpu] healthcheck: test: ["CMD", "curl", "-f", "http://localhost:11434/api/tags"] interval: 30s timeout: 10s retries: 5 start_period: 60s open-webui: image: ghcr.io/open-webui/open-webui:main restart: unless-stopped depends_on: ollama: condition: service_healthy environment: - OLLAMA_BASE_URL=http://ollama:11434 volumes: - open_webui_data:/app/backend/data ports: - "3000:8080" volumes: ollama_models: open_webui_data:

depends_on.ollama.condition: service_healthyが重要な設定だ。OllamaのヘルスチェックがパスするまでOpen WebUIコンテナの起動を待つため、「WebUIが起動したがOllamaにまだ繋がらない」という競合状態を防げる。
http://ollama:11434というURLは、Dockerのサービスディスカバリーによりollamaコンテナへ名前解決される。コンテナ間通信では必ずサービス名を使い、IPアドレスには依存しない設計にする。

2. ブラウザでの動作確認

$ docker compose up -d $ docker compose ps NAME IMAGE STATUS ollama-compose-ollama-1 ollama/ollama:latest Up (healthy) ollama-compose-open-webui-1 ghcr.io/open-webui/open-webui Up

全サービスがUpになったらhttp://サーバーIP:3000でOpen WebUIにアクセスできる。初回アクセスでは管理者アカウント登録画面が表示されるので、管理者メールアドレスとパスワードを登録する。
社内情報システムポリシーでクラウドAIが利用制限されている環境でのローカルLLM活用の背景については、社内でChatGPTが使えないときの代替手段も参照してほしい。

NginxリバースプロキシをDocker Composeに組み込む

Open WebUIのポート3000番を直接外部に公開するより、Nginxをフロントに置いてポート80番に統一する方が運用しやすい。WebSocketを使うチャット通信のタイムアウト設定も、Nginxで一元管理できる。

1. nginx.confの作成

# ~/ollama-compose/nginx/nginx.conf upstream open_webui { server open-webui:8080; } server { listen 80; server_name _; client_max_body_size 100M; location / { proxy_pass http://open_webui; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # WebSocket対応(チャット通信に必須) proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_read_timeout 300s; proxy_connect_timeout 75s; } }

proxy_read_timeout 300sはLLMの推論時間を考慮した設定だ。Nginxのデフォルトは60秒であり、70Bモデルで長い回答を生成している最中にタイムアウトが発生するケースが現場でよく報告される。

2. docker-compose.ymlにnginxサービスを追加する

nginx: image: nginx:stable-alpine restart: unless-stopped depends_on: - open-webui ports: - "80:80" volumes: - ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf:ro

:ro(読み取り専用)でバインドマウントすることで、コンテナ内からの設定書き換えを防ぐ。このNginxをフロントに置いたことで、open-webuiのports: "3000:8080"設定は外部に公開する必要がなくなる。外部への窓口はNginxの80番のみに絞れる。

ネットワーク分離・ボリューム・ヘルスチェックの最終構成

1. 完成版docker-compose.yml

各サービスを内部ネットワーク(backend)と外部向けネットワーク(frontend)に分離した最終構成を示す。

services: ollama: image: ollama/ollama:latest restart: unless-stopped volumes: - ollama_models:/root/.ollama networks: - backend deploy: resources: reservations: devices: - driver: nvidia count: all capabilities: [gpu] healthcheck: test: ["CMD", "curl", "-f", "http://localhost:11434/api/tags"] interval: 30s timeout: 10s retries: 5 start_period: 60s open-webui: image: ghcr.io/open-webui/open-webui:main restart: unless-stopped depends_on: ollama: condition: service_healthy environment: - OLLAMA_BASE_URL=http://ollama:11434 volumes: - open_webui_data:/app/backend/data networks: - backend - frontend nginx: image: nginx:stable-alpine restart: unless-stopped depends_on: - open-webui ports: - "80:80" volumes: - ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf:ro networks: - frontend networks: backend: internal: true frontend: volumes: ollama_models: open_webui_data:

networks.backend.internal: trueがセキュリティ上の要点だ。internal: trueを設定したネットワークは、コンテナからインターネット方向への通信が遮断される。OllamaとOpen WebUI間の推論通信はこのバックエンドネットワーク内にとどまり、Ollamaの11434番ポートは外部に一切露出しない。
外部への窓口はNginxのfrontendネットワーク経由のポート80のみになる。モデルデータや推論内容が外部に漏れるリスクをネットワーク設計として構成レベルで低減できる。

2. 設定変更後の更新手順

nginx.confを変更した場合は構文チェックを通してから再起動する。

# nginx設定の構文チェック $ docker compose exec nginx nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful # nginxだけ再起動(他サービスは停止しない) $ docker compose restart nginx

docker-compose.yml自体を変更した場合はdocker compose up -dを再実行する。変更のあったサービスのコンテナだけが差し替えられ、他は影響を受けない。

Docker Composeを使った運用でよくあるトラブルと対処法

トラブル1: GPUがコンテナに認識されない

docker compose exec ollama nvidia-smiでエラーが返る場合、/etc/docker/daemon.jsonにnvidiaランタイムの設定が入っているか確認する。

$ cat /etc/docker/daemon.json { "runtimes": { "nvidia": { "args": [], "path": "nvidia-container-runtime" } } }

このエントリがない場合はsudo nvidia-ctk runtime configure --runtime=dockerを実行してDockerを再起動する。daemon.jsonの設定がない状態では、docker-compose.ymlのdeploy.resources.reservations.devicesブロックが無視されるため、GPUがコンテナに見えない状態になる。

トラブル2: Open WebUIがOllamaに接続できない

ブラウザ上のOpen WebUIで「Ollamaに接続できません」と表示される場合、まずコンテナ間の疎通を確認する。

$ docker compose exec open-webui curl http://ollama:11434/api/tags {"models":[...]}

このコマンドが成功するなら、Open WebUIの設定画面(管理者→設定→接続)でOllama URLをhttp://ollama:11434に設定し直す。初期設定でlocalhostが入っているとコンテナ間通信が通らない。
コマンドが失敗する場合は、ollamaとopen-webuiが同じbackendネットワークに属しているかをdocker network inspect ollama-compose_backendで確認する。internal: trueのネットワークではollama pullコマンド実行時にモデル取得が失敗する点にも注意が必要だ。モデル取得はollamaサービスのnetworksに一時的にfrontendも追加するか、先にモデルを取得してからinternal: trueに戻す手順を踏む。

トラブル3: モデルダウンロード後にディスクが枯渇する

70Bクラスのモデルは-q4_0量子化でも40GBを超えるケースがある。docker system df -vでボリュームの使用量を確認し、不要なモデルはdocker compose exec ollama ollama rm モデル名で削除する。ストレージが逼迫している場合は、OLLAMA_MODELS環境変数でモデル保存先を外付けHDDやマウントボリュームへ変更する方法が有効だ。

まとめ

OllamaをDocker Composeのマルチサービス構成にまとめることで、起動順管理・ネットワーク分離・設定の再現性という3つの課題を一括して解決できる。YAMLに全設定を集約してGitで管理すれば、チームへの展開も別サーバーへの移設もdocker compose up -d一発で済む。この記事の要点をまとめる。
操作 コマンド 備考
全サービス起動 docker compose up -d 依存順に自動起動。YAMLの変更後も同コマンドで差分更新
サービス状態確認 docker compose ps STATUS欄の「(healthy)」でヘルスチェック通過を確認
モデル取得 docker compose exec ollama ollama pull llama3.3:70b-instruct-q4_0 コンテナ内でollamaコマンドを実行
モデル削除 docker compose exec ollama ollama rm llama3.3:70b-instruct-q4_0 ディスク逼迫時に不要モデルを削除
nginx設定反映 docker compose restart nginx 他サービスを止めずにnginxだけ再起動
ログ確認 docker compose logs -f ollama サービス名を指定して個別確認
全サービス停止 docker compose down ボリュームは残る(モデルデータ保持)
ローカルLLMを「個人の実験環境」から「チームの業務インフラ」に格上げする際、Docker Composeによる一元管理はその第一歩になる。構成ファイルをGitでバージョン管理することで、どのメンバーが何を変更したかも追跡できるようになる。

ローカルLLMのCompose本番構成を2日間で体験する

Docker ComposeでOllama・Open WebUI・Nginxをまとめて管理し、チームで安定稼働するローカルLLM環境を一から構築する。そのプロセスを実機で体験してみたい方は多いはずだ。実機GPU環境で手を動かしながら習得したい方向けに、「ローカルAIマスターセミナー」を開催しています。
少人数(最大8名)ZOOMハンズオン形式で実施しています。

>> ローカルAIマスターセミナーの詳細を確認する
ローカルLLMの構築・運用に関する関連記事もあわせて参考にしてください。

Ubuntu ServerでローカルLLMを構築する方法|Ollamaで機密データを外に出さず業務AIを動かす完全ガイド
社内でChatGPTが使えないときの代替手段|機密データを守るローカルLLMという選択肢
ローカルLLMのモデルを比較する方法|Llama3.3・Mistral・Gemma・Phi-4をUbuntuで使い分けるポイント

無料メルマガで学習を続ける

Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。

登録無料・いつでも解除できます

暗記不要・1時間後にはサーバーが動く

3,100名以上が実践した「型」を無料で公開中

プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。

姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

Linux無料マニュアル(図解60P) 名前とメールで30秒登録
宮崎 智広

この記事を書いた人

宮崎 智広(みやざき ともひろ)

株式会社イーネットマーキュリー代表。現役のLinuxサーバー管理者として20年以上の実務経験を持ち、これまでに累計3,100名以上のエンジニアを指導してきたLinux教育のプロフェッショナル。「現場で本当に使える技術」を体系的に伝えることをモットーに、実践型のLinuxセミナーの開催や無料マニュアルの配布を通じてLinux人材の育成に取り組んでいる。

趣味は、キャンプにカメラ、トラウト釣り。好きな食べ物は、ラーメンにお酒。休肝日が作れない、酒量を減らせないのが悩み。最近、ドラマ「フライトエンジェル」を観て涙腺が崩壊しました。