# このスタックを選ぶ理由目標は、ローカルAIを導入する中小企業や技術チームの4つの具体的なニーズを満たすことです。推論エンジン(Ollama)、Webユーザーインターフェース(Open WebUI)、RAG用のベクトルデータベース(Qdrant)、そしてノーコードの自動化レイヤー(n8n)です。これらの前段にリバースプロキシとしてTraefikを配置し、TraefikがLet's Encryptを使ったHTTPSとルーティングを担当します。
各サービスは、永続化ボリュームを備えた独立したコンテナ内で動作します。他のサービスを壊すことなく1つを無効にしたり、単一のコンポーネントのみを更新したり、1つのコマンドでスタックをステージング環境に複製したりできます。
i
このガイドに含まれない内容
これはKubernetesのガイドではありません。10〜50人のチームが単一サーバー(1つのGPUで最大約10人の同時ユーザー)を使用する場合、Docker Composeで十分です。それ以上、またはマルチノードのハイアベイラビリティが必要な場合は、k3sやNomadを検討してください。
# ターゲットアーキテクチャ✓
ローカルエージェントキット
あなたのマシンで動作するエージェント:エージェント型 Cline、MCP、n8n + Ollama、ローカル自動化。
永久に利用できるオンラインスペース PDF + ファイル 生涯アップデート
Traefik (ポート 80/443) リバースプロキシと、Let's Encryptを利用した自動TLS終端を担います。すべての外部トラフィックはこれを経由します。
Open WebUI(内部) ChatGPT風のチャットインターフェースで、chat.votre-domaine.fr上で提供されます。認証はローカル認証またはOIDCです。
Ollama (内部) 推論デーモン。公開されません。Dockerネットワーク内からのみアクセス可能です。
Qdrant(内部) RAG用のベクトルデータベース。ドキュメントの埋め込みベクトルを保存します。
n8n ノーコード自動化。n8n.votre-domaine.frからアクセスできます。
Prometheus + Grafana オプションであり、GPU/CPU/RAMのモニタリング用に内部で公開されています。 # 前提条件
Linuxサーバー Ubuntu 22.04 LTSまたはDebian 12、root権限でのSSHアクセス、最低16GBのRAM、200GBのディスク容量。
NVIDIA製GPUを推奨 14B~32B のモデルを快適に動かすなら RTX 3090 24GB または RTX 4090、7B のモデルなら RTX 4070 12GB が適しています。GPU がない場合は、CPU で動かすモデルを 3B にとどめてください。
ドメイン名 DNSにアクセスしてサブドメインを作成できる。Let's Encrypt に必須
Docker Engine + Compose v2 公式スクリプトget.docker.comでインストールします。2022年以降、composeプラグインが含まれています。
NVIDIA Container Toolkit GPUをお持ちの場合、これはDockerがコンテナにそのGPUを公開できるようにするものです。 # 1. サーバーの準備クリーンなUbuntu 22.04から始めます。インストールが必要なものは3つです:Docker、NVIDIA Container Toolkit(GPUがある場合)、そして適切なファイアウォール。
Docker インストール ⧉ コピー
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER
newgrp docker
docker compose versionNVIDIA Container Toolkit ⧉ コピー
distribution=$(. /etc/os-release; echo $ID$VERSION_ID)
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg
curl -s -L https://nvidia.github.io/libnvidia-container/$distribution/libnvidia-container.list | \
sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \
sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
sudo apt-get update && sudo apt-get install -y nvidia-container-toolkit
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart dockerDockerがGPUを認識しているかテストする ⧉ コピー
docker run --rm --gpus all nvidia/cuda:12.4.0-base-ubuntu22.04 nvidia-smiUFWの最小限のファイアウォール ⧉ コピー
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp comment 'SSH'
sudo ufw allow 80/tcp comment 'HTTP - redir vers HTTPS'
sudo ufw allow 443/tcp comment 'HTTPS Traefik'
sudo ufw enable!
Ollamaを直接公開することは絶対に避けてください
Ollama のポート 11434 には認証機能がありません。インターネットに公開すると、誰でも GPU リソースを使い、API 経由でモデルを外部に持ち出せるようになります。すべての通信は、認証を備えた Traefik を経由します。
# 2. docker-compose.yml(コメント付き)作業フォルダとメインファイルを作成してください。これがデプロイの中核となります。全体の動作を壊さずに調整できるよう、各セクションにコメントが付いています。
ディレクトリ構成 ⧉ コピー
mkdir -p /opt/llm-stack/{traefik,ollama,open-webui,qdrant,n8n}
cd /opt/llm-stack
touch docker-compose.yml .env.env(要記入) ⧉ コピー
DOMAIN=votre-domaine.fr
ACME_EMAIL=admin@votre-domaine.fr
N8N_BASIC_AUTH_USER=admin
N8N_BASIC_AUTH_PASSWORD=changez-moi-vraiment
TRAEFIK_DASHBOARD_AUTH=admin:$$apr1$$xxxxxxx # generé avec htpasswddocker-compose.yml ⧉ コピー
name: llm-stack
networks:
proxy: # réseau public exposé par Traefik
internal: # réseau privé Ollama <-> WebUI <-> Qdrant
volumes:
ollama_data:
open_webui_data:
qdrant_data:
n8n_data:
traefik_certs:
services:
# --- Traefik : reverse proxy + Let's Encrypt automatique ---
traefik:
image: traefik:v3.2
restart: unless-stopped
command:
- --providers.docker=true
- --providers.docker.exposedbydefault=false
- --entrypoints.web.address=:80
- --entrypoints.web.http.redirections.entrypoint.to=websecure
- --entrypoints.web.http.redirections.entrypoint.scheme=https
- --entrypoints.websecure.address=:443
- --certificatesresolvers.le.acme.email=${ACME_EMAIL}
- --certificatesresolvers.le.acme.storage=/certs/acme.json
- --certificatesresolvers.le.acme.tlschallenge=true
- --api.dashboard=true
ports:
- 80:80
- 443:443
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- traefik_certs:/certs
networks: [proxy]
labels:
- traefik.enable=true
- traefik.http.routers.dashboard.rule=Host(`traefik.${DOMAIN}`)
- traefik.http.routers.dashboard.service=api@internal
- traefik.http.routers.dashboard.entrypoints=websecure
- traefik.http.routers.dashboard.tls.certresolver=le
- traefik.http.routers.dashboard.middlewares=dashboard-auth
- traefik.http.middlewares.dashboard-auth.basicauth.users=${TRAEFIK_DASHBOARD_AUTH}
# --- Ollama : moteur d'inférence, JAMAIS exposé en public ---
ollama:
image: ollama/ollama:latest
restart: unless-stopped
volumes:
- ollama_data:/root/.ollama
environment:
- OLLAMA_HOST=0.0.0.0:11434
- OLLAMA_KEEP_ALIVE=24h
- OLLAMA_NUM_PARALLEL=2
networks: [internal]
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: all
capabilities: [gpu]
# --- Open WebUI : interface chat, exposée en HTTPS ---
open-webui:
image: ghcr.io/open-webui/open-webui:main
restart: unless-stopped
depends_on: [ollama]
environment:
- OLLAMA_BASE_URL=http://ollama:11434
- WEBUI_AUTH=true
- ENABLE_SIGNUP=false
volumes:
- open_webui_data:/app/backend/data
networks: [proxy, internal]
labels:
- traefik.enable=true
- traefik.http.routers.chat.rule=Host(`chat.${DOMAIN}`)
- traefik.http.routers.chat.entrypoints=websecure
- traefik.http.routers.chat.tls.certresolver=le
- traefik.http.services.chat.loadbalancer.server.port=8080
# --- Qdrant : base vectorielle pour le RAG ---
qdrant:
image: qdrant/qdrant:latest
restart: unless-stopped
volumes:
- qdrant_data:/qdrant/storage
networks: [internal]
# --- n8n : automatisation no-code ---
n8n:
image: docker.n8n.io/n8nio/n8n:latest
restart: unless-stopped
environment:
- N8N_BASIC_AUTH_ACTIVE=true
- N8N_BASIC_AUTH_USER=${N8N_BASIC_AUTH_USER}
- N8N_BASIC_AUTH_PASSWORD=${N8N_BASIC_AUTH_PASSWORD}
- N8N_HOST=n8n.${DOMAIN}
- N8N_PROTOCOL=https
- WEBHOOK_URL=https://n8n.${DOMAIN}/
volumes:
- n8n_data:/home/node/.n8n
networks: [proxy, internal]
labels:
- traefik.enable=true
- traefik.http.routers.n8n.rule=Host(`n8n.${DOMAIN}`)
- traefik.http.routers.n8n.entrypoints=websecure
- traefik.http.routers.n8n.tls.certresolver=le
- traefik.http.services.n8n.loadbalancer.server.port=5678→
なぜ2つのネットワークなのか
internalネットワークからはリバースプロキシにアクセスできません。OllamaとQdrantはこのネットワーク内に隔離されているため、Traefikを経由した攻撃者が両者のAPIに直接アクセスする手段はありません。Open WebUIは両方のネットワークに接続されており、proxy経由で公開トラフィックを受信し、internal経由でOllamaと通信します。
# 3. Traefik および DNS の設定最初の docker compose up を実行する前に、サーバーの公開 IP アドレスを指す A レコードの DNS エントリを 3 つ作成してください。
chat.votre-domaine.fr ユーザーインターフェースのOpen WebUI。
n8n.votre-domaine.fr ワークフロー編集ツール n8n。
traefik.votre-domaine.fr Traefikのダッシュボード(basic authで保護されています) Traefik ダッシュボードの basic auth 用のハッシュを生成します。注意:.env 内では $ を二重にしてください(docker-compose のエスケープ)。
Basic認証用のハッシュ ⧉ コピー
sudo apt install apache2-utils
htpasswd -nb admin VotreMotDePasse | sed -e 's/\$/\$\$/g'!
Let's Encryptおよびレート制限
Let's Encrypt はドメインごと、週ごとに50件の証明書までを制限しています。テストフェーズでは --certificatesresolvers.le.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory を使用し、ステージングサーバーに指向してください。すべての機能が正常に動作するまでその設定を変更してください。
# 4. 初回起動および確認01
スタックを起動する
/opt/llm-stack内でdocker compose up -dを実行してください。Traefikが数秒でLet's Encryptの証明書を取得するので、ログを監視してください。
02
サービスの稼働状態を確認する
docker compose ps doit afficher tous les services en running. Aucun ne doit redémarrer en boucle.
03
最初のモデルをダウンロードする
docker compose exec ollama ollama pull qwen3.5:9b(6.6 GB、コンテキスト256k、2026年の標準的な8 GB向け汎用モデル)。24 GB GPUでより高性能なモデルを使う場合:qwen3.8:27b(VRAM約18 GB、コンテキスト262k、Apache 2.0ライセンス)。
04
インターフェースをテスト
https://chat.votre-domaine.fr を開いてください。最初に作成されたアカウントが管理者になります。ENABLE_SIGNUP=falseにすると、それ以降、一般ユーザーによる新規登録がすべてブロックされます。
05
GPUが実際に使用されているかを確認
docker compose exec ollama ollama ps : la colonne PROCESSOR doit afficher 100% GPU.
Traefikのログをリアルタイムで表示 ⧉ コピー
docker compose logs -f traefik | grep -i acme# 5. セキュリティの強化設定が不適切なパブリックスタックは、1時間以内にスキャンされます。Docker ComposeによるLLMの本番環境デプロイメントが、誰かのshodan.ioに載らないための、妥協の許されない6つのルールをご紹介します。
強力で使い回さないパスワード openssl rand -base64 32 でシークレットを生成してください。.envファイルに記載されている例のパスワードは一切使用しないでください。
一般ユーザーの新規登録を無効にする Open WebUIでENABLE_SIGNUP=falseを設定してください。これを設定しないと、誰でもアカウントを作成し、あなたのGPUリソースを使用できます。
Traefikミドルウェアを介したセキュリティヘッダー HSTS、frame-deny、content-type-nosniffを備えたsecureHeadersミドルウェアを追加してください。わずか3行で、大きな効果が得られます。
コンテナごとのリソース制限 deploy.resources.limitsの下に、memoryとcpusを設定してください。サービスがクラッシュした場合、サーバー全体をダウンさせないようにします。
可能な限り読み取り専用のコンテナを使用 TraefikおよびQdrantにread_only: trueを追加してください。一時的な書き込みディレクトリにはTmpfsを使用してください。
月次更新 watchtower は自動プルを実行しますが、プロダクション環境でのバージョン管理には、cron タスクと明示的な git tag の組み合わせを推奨します。 セキュリティヘッダー用ミドルウェア ⧉ コピー
# À ajouter sur le service open-webui en labels:
- traefik.http.routers.chat.middlewares=secure-headers
- traefik.http.middlewares.secure-headers.headers.stsSeconds=31536000
- traefik.http.middlewares.secure-headers.headers.stsIncludeSubdomains=true
- traefik.http.middlewares.secure-headers.headers.frameDeny=true
- traefik.http.middlewares.secure-headers.headers.contentTypeNosniff=true
- traefik.http.middlewares.secure-headers.headers.browserXssFilter=true→
Traefikの前段にFail2banを配置
Basic認証(Traefikのダッシュボード、n8n)への総当たり攻撃を防ぐには、Traefikのログを解析するフィルターとともにfail2banをインストールしてください。5回の試行 → IPアドレスを1時間ブロック。設定は10行で完了します。
# 6. Prometheus+Grafanaによる監視本番環境で必ず監視すべき3つの指標:Ollama によるVRAM使用量、Open WebUI のリクエスト遅延、およびLet's Encrypt証明書の状態(Traefikはすべてを /metrics で公開します)。
docker-compose.yml に追加するブロック ⧉ コピー
prometheus:
image: prom/prometheus:latest
restart: unless-stopped
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
- prometheus_data:/prometheus
networks: [internal]
nvidia-exporter:
image: utkuozdemir/nvidia_gpu_exporter:latest
restart: unless-stopped
devices: [/dev/nvidiactl, /dev/nvidia0]
volumes:
- /usr/lib/x86_64-linux-gnu/libnvidia-ml.so.1:/usr/lib/x86_64-linux-gnu/libnvidia-ml.so.1:ro
- /usr/bin/nvidia-smi:/usr/bin/nvidia-smi:ro
networks: [internal]
grafana:
image: grafana/grafana:latest
restart: unless-stopped
volumes:
- grafana_data:/var/lib/grafana
networks: [proxy, internal]
labels:
- traefik.enable=true
- traefik.http.routers.grafana.rule=Host(`grafana.${DOMAIN}`)
- traefik.http.routers.grafana.entrypoints=websecure
- traefik.http.routers.grafana.tls.certresolver=le
- traefik.http.services.grafana.loadbalancer.server.port=3000prometheus.yml ⧉ コピー
global:
scrape_interval: 15s
scrape_configs:
- job_name: 'traefik'
static_configs:
- targets: ['traefik:8080']
- job_name: 'nvidia'
static_configs:
- targets: ['nvidia-exporter:9835']
- job_name: 'qdrant'
static_configs:
- targets: ['qdrant:6333']Grafana では、ダッシュボード ID 14574(NVIDIA GPU Exporter)と17346(Traefik v3)をインポートしてください。5分で、VRAM、GPU 温度、サブドメイン別の HTTP リクエストレート、P95 レイテンシをまとめて把握できます。
# 7. バックアップと更新5つのボリュームにすべての重要データが含まれます:ollama_data(モデル)、open_webui_data(アカウント + 会話 + RAG)、qdrant_data(ベクトル)、n8n_data(ワークフロー)、traefik_certs(証明書)。
/usr/local/bin/backup-llm-stack.sh ⧉ コピー
#!/bin/bash
set -e
BACKUP_DIR=/var/backups/llm-stack
TS=$(date +%Y%m%d-%H%M)
mkdir -p "$BACKUP_DIR"
for vol in open_webui_data qdrant_data n8n_data traefik_certs; do
docker run --rm \
-v llm-stack_${vol}:/data \
-v "$BACKUP_DIR":/backup \
alpine tar czf "/backup/${vol}-${TS}.tar.gz" -C /data .
done
find "$BACKUP_DIR" -name '*.tar.gz' -mtime +30 -delete毎日午前3時に実行するcron設定 ⧉ コピー
sudo chmod +x /usr/local/bin/backup-llm-stack.sh
echo "0 3 * * * root /usr/local/bin/backup-llm-stack.sh" | sudo tee /etc/cron.d/llm-stack-backupi
ollama_data をバックアップしない理由
モデルはすぐに数十GBに達し、ollama pullで再ダウンロードできます。日々のバックアップにモデルを含める必要はありません。代わりに、モデルのリストを保存してください:docker compose exec ollama ollama list > models.txt。
アップデートは慎重に行ってください。バージョンを固定し(image: ollama/ollama:0.5.4を使い、:latestは使わない)、更新のたびに事前にVPSのスナップショットを取り、まずステージング環境でテストしてください。
適切な更新手順 ⧉ コピー
cd /opt/llm-stack
docker compose pull
docker compose up -d
docker image prune -f# トラブルシューティング
Traefik は証明書を生成しません ポート80と443が開いていること、そしてDNSが正しくサーバーを指していることの両方を確認してください。docker compose logs traefik | grep -i error で、問題の90%を特定できます(DNSがまだ伝播していない、レート制限、チャレンジの失敗)。
Open WebUIに 'No models found' と表示される Ollama でまだモデルをダウンロードしていません。docker compose exec ollama ollama pull qwen3.5:9b を実行してください。また、OLLAMA_BASE_URL=http://ollama:11434 も確認してください(localhost ではなく、サービス名を指定します)。
GPUがコンテナ内で検出されません nvidia-container-toolkit がインストールされていないか、Docker が設定後に再起動されていません。docker run --rm --gpus all nvidia/cuda:12.4.0-base-ubuntu22.04 nvidia-smi でテストしてください。
n8nがHTTPへのリダイレクトを繰り返します WEBHOOK_URL と N8N_PROTOCOL=https を設定する必要があります。設定しないと、n8nはHTTPで動作していると認識し、ブラウザの動作がおかしくなります。
Traefikの後ろにあるGrafanaにアクセスできません そのenvironmentにGF_SERVER_ROOT_URL=https://grafana.${DOMAIN}とGF_SERVER_SERVE_FROM_SUB_PATH=falseを追加してください。
複数ユーザーが利用する場合、遅延が急激に増加します OLLAMA_NUM_PARALLELの設定値がVRAM容量に対して高すぎます。グラフィックカードに応じて1または2に下げてください。負荷がかかっている間はollama psで状態を確認してください。 # さらに詳しくスタックは稼働し、監視とバックアップも行われています。運用をさらに本格化するための次のステップとして、3つの方向性が考えられます。
RAGをあなたのドキュメントに接続する ChromaDBとMistralを使うRAGのガイドは、Qdrantにも容易に応用できます。埋め込みとチャンク分割の考え方は同じで、使うベクトルデータベースが異なるだけです。
ビジネスプロセスの自動化 「n8nとOllamaで自動化する」ガイドでは、メールの翻訳、リードの分類、RSSの要約など、具体的な10のレシピが紹介されており、これらはあなたのスタックを直接活用します。
コンプライアンスに対応する 「ローカルLLMとRGPD」ガイドでは、企業での導入にあたり文書化すべき法的義務(記録簿、保存期間、ユーザーの権利)を詳しく説明しています。 このガイドは役に立ちましたか?
ご意見、誤りのご指摘、補足はありますか?ぜひお知らせください。皆さんにとってより良いガイドにするために役立ちます。
👍 役に立った 👎 わかりにくい ✏️ エラーを報告