OctopをVPSでセルフホストする方法
Octop v0.9.19をDocker Composeのtagで固定してVPSに導入する手順です。ユーザー分離、OpenAI互換モデル、TLS設定と、curlインストーラーを避ける理由を解説します。
Octop の概要と、自分でホストする理由
Octop は、家庭や小規模チーム向けのセルフホスト型 AI アシスタントです。単なるチャットフロントエンドではなく Octop を自分でホストする理由は、ユーザー同士を分離できることにあります。Open WebUI は、モデルの前段にブラウザーインターフェースを提供します。Octop は、admin ロール、ユーザーごとのプライベートワークスペースと認証情報、タスクごとに切り替えられる専門エージェントのライブラリを追加します。この違いにより、1 台の VPS で 1 人ではなく 5 人が利用できます。
プロジェクトは github.com/TencentCloud/Octop にあります。1 つのプロセスで Web ダッシュボード、コマンドラインインターフェース、チャットチャネル(Feishu、DingTalk、QQ、Discord、WeCom)、スケジュールジョブを提供し、すべてが ~/.octop/ 配下の単一の SQLite データベースに保存されます。以下の内容はすべて、2026 年 8 月 5 日にリリースされた tag v0.9.19 を前提としています。プラットフォームをまだ比較中であれば、VPS で実行できる Open WebUI の代替製品の比較で、より広い選択肢を確認できます。
時間をかけて導入する前に、1 点明確にしておきます。Octop は、ベンダーの GitHub organization から公開されている 1.0 未満のソフトウェアで、2026 年 8 月時点の star 数は約 900 です。開発は速く、バージョン番号にもそれが表れています。ここで安定したアップグレード経路を保証するものではありません。tag を固定し、changelog を読み、バックアップを保持してください。
開始前に必要なもの
- Docker Engine と Compose plugin を実行できる Ubuntu 24.04 の VPS。Compose を初めて使う場合は、VPS 向け Docker Compose の基本から始めてください。
git。イメージを pull するのではなく、release tag を checkout するために必要です。- VPS を指すドメイン名。前段に TLS(transport layer security)を配置するために必要です。
- OpenAI API に対応するモデルバックエンド。ローカルの Ollama、セルフホストの gateway、または有料の key を使用できます。
Octop 自体は軽量です。Python プロセスと SQLite ファイルで構成されています。負荷の大部分はモデルバックエンドが担います。そのため、同じホストでモデルを実行する場合は、モデルに合わせてホストのスペックを決めてください。
curl installer を推奨しない理由
README では、1 行のインストールコマンドが先頭に示されています。
curl -fsSL https://finnie-1258344699.cos.ap-guangzhou.myqcloud.com/octop/install.sh | bash管理対象のサーバーでは、この方法を推奨しません。理由は明確です。このスクリプトはリポジトリに存在しません。Tencent Cloud Object Storage のバケットから提供されています。git tag や commit の対象ではないため、今日のスクリプトと先週のスクリプトを diff できず、変更理由を説明する履歴もありません。明日、バケットが異なる内容を返しても、プロジェクト内にはそれを記録するものがありません。結果をそのまま bash にパイプすると、1 行も読む前にマシン上でスクリプトが実行される点も問題です。
この installer はコンテナではなくホストに書き込みます。uv を使って Python 3.12 を取得し、パッケージマネージャーが把握していない環境を構築するため、後から削除する作業は手動になります。
よりよい方法は 2 つあります。スクリプトを取得して内容を確認してから実行する方法です。30 秒かかりますが、curl -fsSL <url> -o install.sh、less install.sh、bash install.sh の順に実行します。もう 1 つは Docker を使う方法で、このガイドの残りで説明します。PyPI package(pip install octop)は少なくともバージョン付きの artifact なので、特定の release に固定できます。
Docker Compose で Octop をデプロイし、v0.9.19 に固定する
2026 年 8 月時点では、pull できる公開イメージはありません。提供されている Compose ファイルはリポジトリからイメージをビルドするため、バージョンを固定するには git tag を checkout します。これは、ほとんどのセルフホストプロジェクトよりも 1 つ手順が多くなります。たとえば セルフホスト AFFiNE ワークスペースでは、公開イメージの tag を指定するだけで、VPS 上でビルドする必要はありません。以下の clone、checkout、build の手順は、openGym のデプロイガイドで説明しているものと同じです。一度設定したことがあれば、手順の構成は把握できているはずです。
git clone https://github.com/TencentCloud/Octop.git
cd Octop
git checkout v0.9.19このファイルが定義するサービスのうち、重要な部分だけを抜き出すと次のとおりです。
services:
octop:
build:
context: ..
dockerfile: docker/Dockerfile
image: octop:latest
container_name: octop
restart: unless-stopped
ports:
- "${OCTOP_PORT:-8088}:${OCTOP_PORT:-8088}"
volumes:
- ${OCTOP_DATA:-~/.octop}:/data/.octop
environment:
- HOME=/data
- OCTOP_BIND_HOST=0.0.0.0
- OCTOP_PORT=${OCTOP_PORT:-8088}
- OCTOP_DEFAULT_PASSWORD=${OCTOP_DEFAULT_PASSWORD:-octop}
- OCTOP_ADMIN_USERNAME=${OCTOP_ADMIN_USERNAME:-admin}
- OPENAI_API_KEY=${OPENAI_API_KEY:-}build: ブロックに注目してください。image: octop:latest は自分でビルドしたイメージの名前であり、レジストリ参照ではありません。そのため、ここでの latest は直近にビルドしたイメージを指します。データパスはデフォルトに任せず、明示した場所を指定してください。また、初回起動前に管理者アカウントへ実際のパスワードを設定してください。これを docker/.env に記述します。
OCTOP_PORT=8088
OCTOP_ADMIN_USERNAME=admin
OCTOP_DEFAULT_PASSWORD=<a long random password>
OCTOP_DATA=/srv/octop-dataここには、ファイルの他の部分より重要な注意点があります。Compose は YAML 内の ${...} プレースホルダーを展開する目的でのみ docker/.env を読み取ります。そのファイルに追加したキーは、Compose ファイルの environment: にも記載しない限り、コンテナには渡りません。OCTOP_ACCESS_TOKEN_TTL だけを .env に追加しても、何も起こらず、エラーも表示されません。別の方法として、マウントしたデータディレクトリ内の ~/.octop/env に同じキーを記述できます。このファイルは Octop が起動時に読み込みます。Docker Compose の env ファイルと Secret に関するガイドでは、この 2 つの仕組みが同じではない理由を説明しています。
ビルドして起動します。
docker compose -f docker/docker-compose.yml up -d --build
docker compose -f docker/docker-compose.yml ps
curl http://127.0.0.1:8088/api/health正常なインスタンスは、{"status":"ok","version":"..."} でヘルスチェックに応答します。それ以外の場合は、ブラウザーを操作する前に docker compose -f docker/docker-compose.yml logs -f octop を確認してください。
次に、ビルドしたイメージへ意味のある名前を付けます。次の --build によって octop:latest が上書きされるため、名前を付けないと 2 つのイメージを区別できなくなります。
docker image tag octop:latest octop:0.9.19初回起動では octop init が実行され、データボリュームに初期認証情報が書き込まれます。
docker exec -it octop cat /data/.octop/credential.txtデフォルト値は admin / octop です。これらが適用されるのは 初回の初期化時のみ です。これが、頻繁に尋ねられる質問への答えです。コンテナを一度起動した後で OCTOP_DEFAULT_PASSWORD を変更しても、アカウントはすでに存在するため何も変わりません。パスワードはダッシュボードで変更してください。
8088 番ポートを公開しない
上記の ports: 行は、VPS のすべてのインターフェースにバインドします。コンテナを起動した瞬間、ダッシュボードがデフォルトパスワードのまま平文でインターネットに公開されます。Octop 自体の OCTOP_BIND_HOST のデフォルト値は 127.0.0.1 です。Compose ファイルでは、プロセスが自身のネットワーク名前空間の外部からのトラフィックを受け付ける必要があるため、これを 0.0.0.0 に上書きしています。この上書きは正しい設定です。公開ポートが露出の原因です。
docker/docker-compose.yml の ports: 行を編集し、マッピングが loopback だけで待ち受けるようにします。
ports:
- "127.0.0.1:${OCTOP_PORT:-8088}:${OCTOP_PORT:-8088}"単純な override ファイルでこの問題を修正しようとしないでください。Compose は複数のファイルにある ports のリストを置き換えずに連結するため、両方のマッピングが公開され、2 つ目のマッピングのバインドに失敗します。upstream のファイルを変更せずに使いたい場合は、シーケンスに !override タグを付けます。これは、追加ではなく置き換えを行うための公式の方法です。Compose が複数のファイルをマージする方法の説明で、その他のマージ規則も確認できます。
loopback にバインドすると、ファイアウォールで発生する別の問題も解決できます。Docker は公開ポートのルールを nat テーブルに書き込み、ufw が管理するチェーンより前に適用します。そのため、ufw deny 8088 では公開されたコンテナポートを停止できません。127.0.0.1 にバインドしたポートは、ufw の設定にかかわらず外部から到達できません。したがって、これは次善策ではなく、適切な修正方法です。
リバースプロキシでTLSを前段に置く
Caddy は最短の構成です。ACME(自動証明書管理環境)経由で証明書を自動的に取得し、明示的な設定なしでWebSocketをプロキシするためです。
octop.example.com {
reverse_proxy 127.0.0.1:8088
}nginx では追加の設定が必要です。Octop はWebSocket経由でチャットをストリーミングするためです。
server {
listen 443 ssl;
server_name octop.example.com;
ssl_certificate /etc/letsencrypt/live/octop.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/octop.example.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:8088;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
proxy_read_timeout 3600s;
}
}各行にはそれぞれ役割があります。チャットは WS /agents/{id}/chat/ws 上で動作するため、proxy_http_version 1.1 と2つのupgradeヘッダーがないと、nginxはupgrade要求に 400 Bad Request で応答します。ダッシュボードは正常に読み込まれますが、送信したメッセージはすべてページ上にエラーを表示せず、永久に停止します。proxy_buffering off が必要なのは、human-in-the-loopの再開エンドポイントが text/event-stream を返すためです。また、SSE(サーバー送信イベント)がプロキシのバッファーに保持されると、ストリーミングされず、最後にまとめて到着します。proxy_read_timeout は長時間のツール実行に対応します。デフォルトの60秒では、エージェントがタスクの途中で停止し、ログに upstream timed out (110: Connection timed out) が記録されるためです。
プロキシ配下で JWT 認証がどのように動作するか
Octop は Cookie ではなく bearer token で認証します。POST /api/auth/login は {access_token, role, user, ...} を返し、その後のリクエストには Authorization: Bearer <access_token> が含まれます。リバースプロキシにとって、これは都合のよい構成です。Cookie のドメイン、Secure フラグ、誤設定しやすい SameSite ルールがないため、http://127.0.0.1:8088 で動作していたセッションは https://octop.example.com でも同じように動作します。
実際のユーザーを接続する前に、2 つの点を理解しておく必要があります。
WebSocket は URL に token を含めます
エンドポイントは WS /agents/{id}/chat/ws?token=<jwt> です。ブラウザーの JavaScript は WebSocket ハンドシェイクに Authorization ヘッダーを設定できないためです。TLS により、通信中の token は保護されます。ただし、サーバー自身のログからは保護されません。nginx はデフォルトで、クエリ文字列を含む完全なリクエスト行を access_log に書き込みます。そのため、実際のユーザーが使用する有効な token が、サーバー上のプレーンテキストファイルに残ります。引数を除いたパスをログに記録してください。$uri はクエリ文字列がすでに除去された正規化済みのパスです。これを http ブロックに記述し、server から参照します。
log_format octop_noargs '$remote_addr [$time_local] '
'"$request_method $uri $server_protocol" '
'$status $body_bytes_sent';
access_log /var/log/nginx/octop.log octop_noargs;セッション単位のログアウトはありません
OCTOP_ACCESS_TOKEN_TTL のデフォルト値は 86400 です。そのため、ログイン後も token は 24 時間有効です。token を無効化する文書化された方法は octop admin rotate-jwt-secret だけです。この操作は ~/.octop/secrets/jwt_secret に保存された署名鍵をローテーションし、発行済みのすべての token を全ユーザーについて直ちに無効化します。したがって、チームからユーザーが離れた場合は、ユーザーを削除し、secret をローテーションしてから、残りのユーザーに再ログインを依頼します。負担が大きい場合は、有効期間を短縮してください。その際、変数を environment: の一覧だけでなく .env にも追加します。
OCTOP_ACCESS_TOKEN_TTL=28800総当たり攻撃への対策もあります。OCTOP_LOGIN_MAX_ATTEMPTS のデフォルト値は 5 回の失敗、OCTOP_LOGIN_LOCKOUT_SECONDS のデフォルト値は 900 です。そのため、ロックされたユーザーは壊れたインストールを調べるのではなく、15 分待つだけで済みます。Octop は独自のユーザーストアを使用し、v0.9.19 では文書化された OIDC サポートがありません。そのため、実際のシングルサインオンが必要な場合は、認証プロキシを前段に置きます。self-hosted の Authentik サーバーは、その用途に使用できます。
モデルバックエンドを Octop に指定する
プロバイダーはダッシュボードでエージェントごとに設定し、octop provider list で現在の設定を確認できます。Octop には、OpenAI互換 API、DashScope (Qwen)、Ollama 用のプリセットが用意されています。認証情報は、自分の SQLite データベースの providers テーブルに保存されます。選択によって、費用とサーバー外へ送信されるデータが変わります。
Ollama でローカルモデルを使う場合。 データはサーバー外へ出ず、トークン料金の代わりに RAM を消費します。注意が必要なのは、コンテナからホストの Ollama を 127.0.0.1:11434 で利用できない点です。このアドレスはコンテナ自身のループバックを指すためです。サービスにホストゲートウェイのエントリを追加します。
extra_hosts:
- "host.docker.internal:host-gateway"次に、プロバイダーのベース URL を Ollama の OpenAI互換パスである http://host.docker.internal:11434/v1 に設定します。API key フィールドには、空でない任意の文字列を入力します。Ollama はこの値を無視しますが、OpenAI クライアントは空の値では送信しないためです。この構成を使うには、Ollama がループバック以外でも待ち受ける必要があります。つまり、systemd unit の OLLAMA_HOST=0.0.0.0:11434 が必要です。ここが危険な部分です。Ollama には認証機能がないため、パブリック IP の 11434 番ポートを開くと、最初にスキャンした誰でも無料で使えるモデルサーバーになります。Docker のプライベート範囲である sudo ufw allow from 172.16.0.0/12 to any port 11434 proto tcp だけを許可し、それ以外は拒否してください。モデルサイズの目安は VPS で Ollama を実行する、Ollama を使い続けるべきか判断する際の比較は Ollama と vLLM の比較で説明しています。
もう 1 つ、ローカルモデルについて注意があります。Octop のバグに見えますが、実際には違います。エージェントはツールを呼び出して動作します。システムプロンプト、ツール定義、履歴を合わせると、プロンプトは長くなります。Ollama が提供するモデルは、デフォルトのコンテキストウィンドウが比較的小さいため、ツール定義が置かれているプロンプトの先頭部分がウィンドウから外れます。その結果、モデルはツールの呼び出しを停止するか、存在しないツールを生成します。num_ctx を 16k または 32k に増やし、関数呼び出しに適したモデルを選んでください。文の途中で応答が止まる場合は、別の設定である num_predict に関する問題です。回答が途中で切れる場合は、エージェントを疑う前に num_predict の設定箇所と done_reason の内容を確認するとよいでしょう。候補を絞った一覧からではなく、特定のモデルから始めたい場合は、Nemotron 3.5 Lightning を試す価値があります。この解説では、取得する正確な tag、必要な RAM、CPU のみで実用的な速度を維持できるかどうかを説明しています。
セルフホストのゲートウェイを使う場合。 セルフホストの LiteLLM ゲートウェイを Octop と他のサービスの間に配置すると、ベース URL を 1 つに統一できます。ユーザーごとに別の key、利用上限、単一のログも設定できます。Octop の設定を変更せずに、ゲートウェイの背後にあるモデルを切り替えることもできます。
有料 API を使う場合。 品質は最も高くなりますが、明確なトレードオフがあります。会話の内容がサーバー外へ出てプロバイダーに到達するためです。これは、セルフホストを選んだ主な目的と相反します。key は docker/.env に OPENAI_API_KEY として指定します。Compose file がすでにこの値を引き渡します。
どの方式を選んでも、Compose file には OCTOP_LANGFUSE_ENABLED、LANGFUSE_PUBLIC_KEY、LANGFUSE_SECRET_KEY、LANGFUSE_BASE_URL も含まれています。そのため、自分の Langfuse インスタンスに trace を送信し、チャット画面から推測するのではなく、エージェントが実際に行っている処理を確認できます。
ユーザー、ロール、共有エージェントライブラリ
初回起動時に作成される管理者アカウントが、他のユーザーを作成・管理します。各ユーザーには専用のエージェント、ワークスペース、認証情報が割り当てられます。この分離は、ブラウザーが保持するトークンによって維持されます。一方で、誰でも利用できるスキルとサブエージェントの共有プールもあります。これが、家族で運用する価値を生む機能です。1 人が優れた調査エージェントを一度作成すれば、他の人が再構築する必要はありません。
ツールの扱いには注意してください。Octop はツールの承認とシェルコマンドのガードレールを提供しており、どちらも実際に機能します。ただし、シェルコマンドを実行するエージェントは、データボリュームがマウントされた Octop コンテナ内でコマンドを実行します。ガードレールによって、不注意なプロンプトで実行できる操作は制限されます。しかし、ガードレールはサンドボックスの境界ではありません。そのため、シェルアクセスを渡さない相手にはツールの承認を有効にしてください。別の選択肢と比較する場合は、セルフホスト型 AI エージェントの比較記事で、それぞれの扱いを確認できます。
この速さでリリースされるプロジェクトをアップグレードする
The data behind this chart
[
{
"version": "v0.9.16",
"days_since_previous_release": 2
},
{
"version": "v0.9.17",
"days_since_previous_release": 3
},
{
"version": "v0.9.18",
"days_since_previous_release": 1
},
{
"version": "v0.9.19",
"days_since_previous_release": 3
}
]これは、2026 年 8 月 7 日時点でリポジトリから取得したタグの日付です。9 日間で 4 件のタグ付きリリースが公開されており、前回のリリースから最短 1 日の間隔で、v0.9.19 は直前のタグから 3 日後に公開されています。このリリース頻度はプロジェクトにとっては良い兆候ですが、latest を無計画に実行する理由にはなりません。適用する前に変更内容を確認してください。
cd Octop
git fetch --tags
git tag --sort=-creatordate | head
NEW_TAG=$(git tag --sort=-creatordate | head -1)
git log --oneline "v0.9.19..$NEW_TAG"データベースのマイグレーションは起動時に実行されるため、毎回必ず先にバックアップを取得してください。1.0 未満のプロジェクトでは、マイグレーションに失敗した場合の復旧作業も自分で行う必要があります。
docker compose -f docker/docker-compose.yml stop
sudo tar czf octop-backup-$(date +%F).tgz -C /srv octop-data
docker compose -f docker/docker-compose.yml start次に、新しいタグを checkout し、docker compose -f docker/docker-compose.yml up -d --build で再ビルドします。問題が発生した場合、古いタグを checkout して再ビルドすればコードは戻せますが、データベースを戻せるのは tarball がある場合だけです。
この tarball には octop.db、config.json、JWT signing secret、credential.txt が含まれるため、サーバー自体と同じように機密性の高いファイルです。mode 600 を設定し、サーバー外にもコピーを保管してください。より大規模な構成向けには、SQLite の代わりに pgvector 付きの PostgreSQL を実行する docker/docker-compose.postgres.yml もプロジェクトから提供されています。
エラーの種類と表示されるメッセージ
ヘルスチェックが応答しません。 curl http://127.0.0.1:8088/api/health がハングするか、接続を拒否します。docker compose -f docker/docker-compose.yml logs -f octop を確認してください。初回初期化中に終了するコンテナは、通常、データディレクトリに書き込めません。そのため、OCTOP_DATA に設定したパスの所有者を確認してください。
ダッシュボードは読み込まれますが、チャットがハングします。 ページにエラーは表示されず、応答もありません。ブラウザーのコンソールを開き、wss://octop.example.com/agents/.../chat/ws への接続失敗を確認してください。プロキシが upgrade を転送していません。proxy_http_version 1.1 と、Upgrade および Connection ヘッダーを追加してください。
返信全体が数秒遅れて一度に表示されます。 ストリーミングは動作していますが、バッファリングが有効です。proxy_buffering off を設定してください。
bind: address already in use。 8088 をすでに別のプロセスが使用しています。sudo ss -tlnp | grep 8088 でプロセスを特定できます。上書きファイルで元の ports エントリを編集せず、2つ目のエントリを追加した場合も同じ状態になります。
正しいパスワードが拒否されます。 5回連続で間違えると、900秒間ロックされます。再インストールせず、ロックが解除されるまで待ってください。
.env の新しいパスワードが反映されません。 その認証情報が適用されるのは初回初期化時だけです。ダッシュボードで変更してください。
エージェントは応答しますが、ツールを実行しません。 ほとんどの場合、ローカルモデルの問題です。ツール定義に対してコンテキストウィンドウが小さすぎるか、モデルの function calling 対応が不十分です。num_ctx を増やし、ツール利用向けに構築されたモデルを試してください。
FAQ
Octop は Open WebUI の代替になりますか?
Octop が追加する機能が必要な場合に限ります。Open WebUI はモデルの前段に置くチャットインターフェースであり、1 人で使う場合や、信頼できる家庭内で使う場合には十分に機能します。Octop には、管理者ロール付きのアカウント、ユーザーごとのワークスペースと認証情報、切り替え可能な専門エージェントのライブラリがあります。そのため、複数人で 1 台のサーバーを共有しても、履歴を共有せずに済みます。1 つのアカウントで問題ない場合は、Open WebUI のほうがシンプルで、成熟度も大幅に高い選択肢です。
Octop の curl インストールスクリプトを使用すべきでない理由は何ですか?
このスクリプトはリポジトリではなく Tencent Cloud Object Storage バケットから提供されるため、git のタグやコミットでは管理されていません。現在の動作と先週の動作を比較できず、スクリプトを bash にパイプすると、内容を読む前に実行されます。また、パッケージマネージャーの管理外で、独自の Python 3.12 環境をホストにインストールします。スクリプトをダウンロードしてから内容を確認するか、チェックアウトしたタグから Docker Compose でデプロイしてください。
Octop は有料 API の代わりにローカルモデルを使用できますか?
はい。Octop は OpenAI 互換 API に対応しており、Ollama のプリセットも同梱されています。そのため、コンテナに extra_hosts: ["host.docker.internal:host-gateway"] を追加してホストで OLLAMA_HOST=0.0.0.0:11434 を設定すれば、http://host.docker.internal:11434/v1 を接続先に指定できます。Ollama 自体には認証機能がないため、Docker のアドレス範囲からの通信に限定してファイアウォールでポート 11434 を保護してください。Ollama の num_ctx は 16k 以上に設定する必要があります。ツール定義を含むエージェントのプロンプトはデフォルトのコンテキストウィンドウを超えるため、モデルがツール呼び出しを停止することがあります。
リバースプロキシは必要ですか。それともポート 8088 を開放できますか?
プロキシが必要です。Octop に同梱される Compose ファイルは、TLS なしで全インターフェースのポート 8088 を公開します。そのため、パスワードや bearer token が平文でインターネット上を流れることになります。公開ポートを 127.0.0.1:8088:8088 に変更し、証明書を設定した Caddy または nginx を前段に置いてください。nginx を使用する場合は、WebSocket upgrade ヘッダーを転送し、proxy_buffering off を設定してください。設定しないとページは読み込まれても、チャットが応答しない状態になります。
Octop は本番運用に対応していますか?
2026 年 8 月時点では 1.0 未満で、タグ付きリリースを週に数回公開しています。そのため、安定版というより有望な段階のソフトウェアとして扱ってください。正確なタグを固定し、アップグレード前に毎回コミットログを確認し、再ビルド前にデータボリュームをバックアップすれば、家族や小規模な社内チームでの利用には対応できます。latest では実行しないでください。また、現時点では顧客データを保存しないでください。