SSD Nodes Learn Hosting plans →
指南 Matt Connor作者: Matt Connor · 已更新 2026-08-30

Octop 自行代管:Docker Compose 多使用者 AI 助理

以 Ubuntu 24.04 VPS 和 Docker Compose 固定 v0.9.19 tag 部署 Octop,實現使用者隔離、OpenAI 相容模型後端與 TLS,並說明為何不應使用 curl 安裝程式。

Octop 是什麼,以及為什麼要自行代管

Octop 是供家庭或小型團隊使用的自行代管 AI 助理。相較於單純的聊天前端,選擇自行代管 Octop 的原因在於,它能讓不同使用者彼此隔離。Open WebUI 提供模型前方的瀏覽器介面。Octop 另外提供具備 admin 角色的帳戶、每位使用者各自的私有工作區與憑證組,以及專業代理程式庫。每位使用者都能依工作需求切換代理程式。這項差異讓一台 VPS 能服務五位使用者,而不只一位。

此專案位於 github.com/TencentCloud/Octop。它以單一程序提供 Web 儀表板、命令列介面、聊天頻道(Feishu、DingTalk、QQ、Discord、WeCom)與排程工作,所有資料都由 ~/.octop/ 下的單一 SQLite 資料庫支援。以下內容均以 5 August 2026 發布的 v0.9.19 tag 為基準。如果你仍在不同平台之間評估,可在 VPS 上執行的 Open WebUI 替代方案比較涵蓋更廣泛的選項。

在投入一個晚上的時間之前,有一點必須先說明。Octop 是由供應商的 GitHub 組織發布的 pre-1.0 軟體,截至 August 2026 約有 900 顆 stars。它的開發速度很快,版本號也反映了這點;本文不保證升級路徑穩定。請固定使用 tag、閱讀變更記錄,並保留備份。

開始前的準備

  • 一台執行 Ubuntu 24.04 且已安裝 Docker Engine 與 Compose plugin 的 VPS。不熟悉 Compose?請先閱讀 VPS 的 Docker Compose 基礎
  • git,因為您將 checkout release tag,而不是 pull image。
  • 一個指向該 VPS 的網域名稱,因為您需要在前方提供 TLS(傳輸層安全性)。
  • 一個支援 OpenAI API 的模型後端:本機 Ollama、自架 gateway,或付費金鑰。

Octop 本身很輕量。它是一個 Python 程序和一個 SQLite 檔案。負載主要來自模型後端。因此,如果您計畫在同一台主機上執行模型,請依模型需求選擇主機規格。

我們不建議使用 curl 安裝程式

README 開頭提供單行安裝指令:

curl -fsSL https://finnie-1258344699.cos.ap-guangzhou.myqcloud.com/octop/install.sh | bash

對於重要的伺服器,我們不建議使用這個安裝方式,原因很明確:該腳本不在儲存庫中。它是由 Tencent Cloud Object Storage bucket 提供。它不受 git tag 或 commit 管理,因此您無法比較今天的腳本與上週的差異,也沒有歷史紀錄可說明變更內容。明天 bucket 可能提供不同的內容,而專案中不會留下任何紀錄。直接將結果串接至 bash,也表示機器會在您讀過腳本內容前就執行它。

此外,這個安裝程式會直接寫入主機,而不是寫入容器。它使用 uv 取得 Python 3.12,並建立套件管理器完全不知情的環境,因此日後移除時必須手動處理。

有兩個更好的選項。先取得腳本、閱讀內容,再執行它,只需花費 30 秒:先執行 curl -fsSL <url> -o install.sh,再執行 less install.sh,最後執行 bash install.sh。另一個選項是使用 Docker,這也是本指南其餘內容採用的方式。PyPI 套件(pip install octop)至少是可指定版本的成品,您可以將它固定在特定 release。

使用 Docker Compose 部署 Octop,固定至 v0.9.19

截至 August 2026,尚未提供可拉取的已發布映像。隨附的 Compose 檔案會從儲存庫建置映像,因此固定版本代表需要切換至對應的 git tag。這比大多數自架專案多一個步驟,因為例如自架 AFFiNE 工作區會固定使用已發布的映像 tag,且完全不會在 VPS 上進行建置。以下的複製、切換與建置流程,與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 是你自行建置的映像名稱,不是 registry 參照,因此這裡的 latest 代表最近一次編譯的內容。請將資料路徑明確設定為固定位置,不要交由預設值處理,並在第一次啟動前為管理員帳戶設定實際密碼。將以下內容放入 docker/.env

OCTOP_PORT=8088
OCTOP_ADMIN_USERNAME=admin
OCTOP_DEFAULT_PASSWORD=<a long random password>
OCTOP_DATA=/srv/octop-data

這裡有一個比檔案其餘部分都更值得注意的陷阱。Compose 只會讀取 docker/.env,用來替換 YAML 中的 ${...} 佔位符。你加入該檔案的金鑰,不會傳入容器,除非它也列在 Compose 檔案的 environment: 下方。只將 OCTOP_ACCESS_TOKEN_TTL 加入 .env 完全不會生效,而且不會顯示任何錯誤。另一種方式,是將相同的金鑰寫入掛載資料目錄中的 ~/.octop/env,Octop 會在啟動時載入該檔案。Docker Compose 中 env 檔案與 secrets 的指南說明了這兩種機制為何不同。

建置並啟動:

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,屆時將無法分辨兩者:

docker image tag octop:latest octop:0.9.19

第一次啟動會執行 octop init,並將初始認證資訊寫入資料 volume:

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,因為程序必須接受來自自身 network namespace 外部的流量。這項覆寫是正確的。真正造成暴露的是發布的連接埠。

編輯 docker/docker-compose.yml 中的 ports: 行,讓對應只監聽 loopback:

    ports:
      - "127.0.0.1:${OCTOP_PORT:-8088}:${OCTOP_PORT:-8088}"

不要嘗試使用一般的 override 檔案修正這個問題。Compose 會串接多個檔案中的 ports 清單,而不是取代它們,因此最後會同時發布兩個對應,並導致第二個對應繫結失敗。若要保留上游檔案不變,請在該序列使用 !override 標籤。這是文件所述、用來取代而非附加內容的方法。Compose 合併多個檔案的說明涵蓋其餘合併規則。

繫結至 loopback 也能解決防火牆可能遇到的問題。Docker 會將發布連接埠的規則寫入 nat table,位置在 ufw 管理的 chains 之前,因此 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 和兩個 upgrade 標頭,nginx 會以 400 Bad Request 回應升級要求:儀表板可以正常載入,但你傳送的每則訊息都會永遠停住,頁面上也不會顯示錯誤。proxy_buffering off 很重要,因為 human-in-the-loop resume endpoint 會回傳 text/event-stream;如果 SSE(伺服器傳送事件)暫存在代理緩衝區中,就會在最後一次性送達,而不是以串流方式傳送。proxy_read_timeout 可涵蓋長時間的工具執行,因為 60 秒的預設值會讓代理程式在工作中途停止,並在日誌中記錄 upstream timed out (110: Connection timed out)

Proxy 後方的 JWT 驗證方式

Octop 使用 bearer token 進行驗證,而不是 cookie。POST /api/auth/login 會傳回 {access_token, role, user, ...},後續請求則會攜帶 Authorization: Bearer <access_token>。對反向代理而言,這是好消息:不必處理 cookie domain、Secure 旗標或 SameSite 規則,因此在 http://127.0.0.1:8088 上可正常運作的工作階段,在 https://octop.example.com 上也會以相同方式運作。

在讓實際使用者使用前,請先了解以下兩項影響。

WebSocket 會在 URL 中攜帶 token。 端點為 WS /agents/{id}/chat/ws?token=<jwt>,因為瀏覽器 JavaScript 無法在 WebSocket handshake 中設定 Authorization header。TLS 可保護 token 在傳輸過程中的安全,但無法防止 token 出現在您自己的日誌中:nginx 預設會將完整的 request line(包括 query string)寫入 access_log,因此實際使用者可用的 token 會以明文留在伺服器上的檔案中。請記錄不含 arguments 的路徑。$uri 是已移除 query string 的標準化路徑,因此請將以下內容放在 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 小時內都有效。唯一有文件記載的失效方式是 octop admin rotate-jwt-secret;此操作會輪替儲存在 ~/.octop/secrets/jwt_secret 的 signing key,並立即使所有尚未失效的 token 對所有使用者失效。因此,當有人離開團隊時,處理順序為:刪除使用者、輪替 secret,然後通知其餘使用者重新登入。如果這個做法負擔過重,請縮短有效期間,並記得同時將變數加入 environment: 清單與 .env

OCTOP_ACCESS_TOKEN_TTL=28800

Octop 已處理暴力破解:OCTOP_LOGIN_MAX_ATTEMPTS 預設為 5 次失敗,OCTOP_LOGIN_LOCKOUT_SECONDS 預設為 900,因此遭鎖定的使用者只需等待 15 分鐘,而不是誤以為安裝損壞。Octop 使用自己的使用者儲存區,截至 v0.9.19 沒有文件記載的 OIDC 支援;如果需要真正的單一登入,請在其前方放置驗證代理伺服器,這正是 自架 Authentik 伺服器的用途。

指定 Octop 的模型後端

Provider 會在 dashboard 中依 agent 設定,而 octop provider list 會顯示目前的設定。Octop 提供 OpenAI-compatible APIs、DashScope (Qwen) 與 Ollama 的預設設定,憑證會儲存在您自己的 SQLite database 的 providers table 中。這項選擇會影響您的費用,以及哪些資料會離開伺服器。

使用 Ollama 的本機模型。資料不會離開伺服器,您消耗的是 RAM,而不是 tokens。最容易出錯的連線細節是:container 無法透過 127.0.0.1:11434 連到 host 上的 Ollama,因為該位址是 container 自己的 loopback。請在 service 中加入 host gateway entry:

    extra_hosts:
      - "host.docker.internal:host-gateway"

接著將 provider base URL 設為 http://host.docker.internal:11434/v1,這是 Ollama 的 OpenAI-compatible path,並在 API key 欄位填入任意非空字串。Ollama 會忽略這個欄位,但 OpenAI clients 不會傳送空白的 API key。Ollama 也必須監聽 loopback 以外的位址,才能使用這項設定,也就是在其 systemd unit 中設定 OLLAMA_HOST=0.0.0.0:11434。這是其中的風險:Ollama 沒有 authentication,因此公開 IP 上開放 11434 後,第一個掃描到它的人就能免費使用您的 model server。只允許 Docker 的 private range sudo ufw allow from 172.16.0.0/12 to any port 11434 proto tcp,並拒絕其他來源。在 VPS 上執行 Ollama 說明 model sizing,而 Ollama 與 vLLM 的比較 說明 Ollama 何時不再適合作為 server。

另外提醒一項本機模型的問題。它看起來像是 Octop 的 bug,但實際上不是。Agent 會透過呼叫 tools 運作,而 system prompt、tool definitions 與 history 組成的 prompt 可能很大。Ollama 提供的 models 預設 context window 通常不大,因此 prompt 開頭的內容會超出 window;tool definitions 正是在這個位置。接著,model 會停止呼叫 tools,或自行捏造不存在的 tools。請將 num_ctx 提高至 16k 或 32k,並選擇確實擅長 function calling 的 model。回覆在句子中途停止是相反的問題,使用的是另一項設定 num_predict。因此,如果回答遭到截斷,請先檢查 num_predict 的設定位置,以及 done_reason 顯示的內容,再判斷問題是否出在 agent。若您希望直接從特定候選 model 開始,而不是先查看 shortlist,Nemotron 3.5 Lightning 值得嘗試。該文章也提供確切的 tag、所需的 RAM,以及僅使用 CPU 時是否能維持足夠效能。

使用自架 gateway。 在 Octop 與其他服務之間加入自架的 LiteLLM gateway,即可取得單一 base URL、每位使用者獨立的 key、支出限制與單一 log。您也能在不修改 Octop 的情況下,替換 gateway 後方的 model。

使用付費 API。 品質最佳,但必須接受明確的取捨:對話內容會離開您的伺服器並傳送至 provider,而這正是自架服務原本要避免的大部分問題。請將 key 以 OPENAI_API_KEY 的形式放入 docker/.env;Compose file 已經會將其傳入。

無論選擇哪一種方式,Compose file 也會帶入 OCTOP_LANGFUSE_ENABLEDLANGFUSE_PUBLIC_KEYLANGFUSE_SECRET_KEYLANGFUSE_BASE_URL,因此您可以將 traces 傳送至自己的 Langfuse instance,直接查看 agents 實際執行的內容,而不是只根據 chat window 猜測。

使用者、角色與共用代理程式庫

首次開機建立的 admin 帳號負責建立及管理其他帳號。每位使用者都有自己的代理程式、工作區與認證資訊,而這些隔離由瀏覽器持有的 token 維持。除此之外,系統還提供所有人都能使用的共用技能與子代理程式庫。這項功能正是適合家庭使用的原因:一個人建立好研究代理程式後,其他人不必重新建立。

使用工具時請務必小心。Octop 提供工具核准與 shell 指令防護,兩者都確實有效;但執行 shell 指令的代理程式,會在掛載資料磁碟區的 Octop 容器內執行這些指令。防護機制能限制不慎撰寫的提示詞所造成的影響,但不是 sandbox 邊界。因此,對於不會交付 shell 使用權限的人,請保持工具核准功能開啟。如果你正在與其他選項比較,自架 AI 代理程式總覽會比較各方案的處理方式。

升級發布如此頻繁的專案

ChartDays between Octop releases, v0.9.16 to v0.9.19 (repository tags, 7 August 2026)
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
  }
]

以下是 repository 中的標籤日期,統計截至 7 August 2026。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"

每次都先備份,因為資料庫 migration 會在啟動時執行,而 pre-1.0 專案的 migration 失敗後,必須由你自行處理復原:

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

接著切換到新的 tag,並使用 docker compose -f docker/docker-compose.yml up -d --build 重新建置。如果發生問題,切回舊 tag 並重新建置即可還原程式碼,但只有 tarball 能還原資料庫。

該 tarball 包含 octop.dbconfig.json、JWT signing secret 及 credential.txt,敏感程度與伺服器本身相同。將權限設為 mode 600,並在主機外保留一份副本。較大型的安裝環境也可以使用專案提供的 docker/docker-compose.postgres.yml,改用 PostgreSQL 搭配 pgvector,而不是 SQLite。

錯誤模式與對應訊息

健康檢查沒有回應。 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 的連線失敗。代理伺服器未轉送升級要求。加入 proxy_http_version 1.1,以及 UpgradeConnection 標頭。

整段回覆延遲數秒後一次出現。 串流正常,但啟用了緩衝。設定 proxy_buffering off

bind: address already in use 8088 已被其他程序占用。sudo ss -tlnp | grep 8088 可找出占用者。如果你在 override 檔案中新增第二個 ports 項目,而不是編輯原有項目,也會出現這個結果。

正確的密碼遭到拒絕。 連續 5 次輸入錯誤會觸發 900 秒的鎖定。請等待鎖定解除,不要重新安裝。

.env 中的新密碼沒有生效。 這些認證資料只會在首次初始化時套用。請在儀表板中變更密碼。

代理程式會回覆,但始終不執行工具。 幾乎都是本機模型的問題:內容視窗太小,無法容納工具定義,或模型不擅長函式呼叫。提高 num_ctx,並改用針對工具使用所建構的模型。

FAQ

Octop 能取代 Open WebUI 嗎?

只有在你需要 Octop 新增的功能時才適合。Open WebUI 是模型前端的聊天介面,對單一使用者或彼此信任的家庭而言,已能妥善完成這項工作。Octop 提供具管理員角色的帳戶、每位使用者獨立的工作區與認證資訊,以及可切換的專用代理程式庫,因此多人可以共用一台伺服器,而不必共用同一份歷史記錄。如果單一帳戶已能滿足需求,Open WebUI 是較簡單且成熟許多的選擇。

為什麼不應使用 Octop 的 curl 安裝腳本?

該腳本是由 Tencent Cloud Object Storage bucket 提供,而不是來自 repository,因此不受任何 git tag 或 commit 管理。你無法比較它今天執行的內容與上週是否相同;將它直接傳給 bash 會在你讀取內容前就執行。它也會在主機上以自有的 Python 3.12 環境安裝,脫離你的套件管理器。請先下載並閱讀腳本,或從已 checkout 的 tag 使用 Docker Compose 部署。

Octop 可以使用本機模型,而不是付費 API 嗎?

可以。Octop 支援 OpenAI 相容 API,並提供 Ollama 預設設定,因此將它指向 http://host.docker.internal:11434/v1,再將 extra_hosts: ["host.docker.internal:host-gateway"] 加入容器並在主機上設定 OLLAMA_HOST=0.0.0.0:11434 後即可運作。請將防火牆限制為僅允許 Docker 的位址範圍存取 11434 埠,因為 Ollama 本身沒有驗證機制。預期需要將 Ollama 的 num_ctx 調高至 16k 或更高,因為包含工具定義的代理程式提示會超出預設上下文視窗,模型隨後便會停止呼叫工具。

我需要反向代理嗎?還是可以直接開放 8088 埠?

你需要反向代理。Octop 隨附的 Compose 檔案會在所有介面發布 8088 埠,且未啟用 TLS,因此密碼與 bearer token 會以明文傳輸至網際網路。請將發布的埠號改為 127.0.0.1:8088:8088,並在前方配置 Caddy 或 nginx 及憑證。使用 nginx 時,請轉送 WebSocket upgrade 標頭並設定 proxy_buffering off,否則頁面雖然會載入,聊天卻會無聲無息地沒有回應。

Octop 適合用於正式環境嗎?

截至 August 2026,Octop 尚未達到 1.0 版,每週仍發布數個標記版本,因此應將它視為具潛力但尚未穩定的軟體。如果你固定使用精確 tag、每次升級前閱讀 commit log,並在每次重新建置前備份資料 volume,將它用於家庭或小型內部團隊仍可行。請勿在 latest 上執行,也不要暫時存放客戶資料。