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 另外提供具備管理員角色的帳戶、每位使用者各自的私有工作區與認證資料,以及專業代理程式庫,讓使用者可依工作需求切換代理程式。這項差異讓一台 VPS 可以服務 5 位使用者,而不只 1 位。
專案位於 github.com/TencentCloud/Octop。它以單一程序提供 Web 儀表板、命令列介面、聊天頻道(Feishu、DingTalk、QQ、Discord、WeCom)及排程工作,所有資料都儲存在 ~/.octop/ 下的單一 SQLite 資料庫中。以下內容均以 2026 年 8 月 5 日發布的標籤 v0.9.19 為基準。如果你仍在決定要使用哪個平台,可在 VPS 上執行的 Open WebUI 替代方案比較 涵蓋更廣泛的選項。
在投入一個晚上的時間之前,有一點需要先說明。撰寫本指南時,Octop 是由供應商的 GitHub 組織發布的 pre-1.0 軟體,截至 2026 年 8 月約有 900 顆星。此後,專案已在 2026 年 9 月 14 日標記 v1.0.0;截至 2026 年 10 月 20 日,最新標籤為 v1.0.2。這是 2026 年 10 月 18 日發布的穩定版本,此前曾連續發布多個 1.0.2 beta 標籤,儲存庫目前約有 10,400 顆星。以下步驟是以 v0.9.19 為基準撰寫,尚未在 1.x 上重新測試。專案變更快速,版本號碼已反映這點;本文不保證升級路徑穩定。請固定使用特定標籤、閱讀變更記錄,並保留備份。
開始前的準備
- 一台執行 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
v0.9.19 隨附的 Compose 檔案會從儲存庫建置映像,因此本指南所說的固定版本,是指切換至 git 標籤。專案確實也有發布映像。v0.9.19 的程式碼樹已包含 docker-publish.yml 工作流程;該流程於 2026 年 7 月 15 日在 v0.9.8 中加入,會針對每個 v* 標籤建置映像,並推送至 Docker Hub。截至 2026 年 10 月 20 日,專案也會發布至 GitHub 的容器登錄區(docker pull ghcr.io/tencentcloud/octop:1.0.2)。不過,從已切出的標籤建置仍是更嚴格的固定方式,因為這會完全依照你檢視過的程式碼進行編譯,而不是信任登錄區中的標籤。這比多數自架專案要求的步驟多一項;例如 自架 AFFiNE 工作區 只會固定至已發布的映像標籤,不會在 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 是你自行建置的映像名稱,不是登錄區參照,因此這裡的 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 環境檔案與 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正常運作的執行個體會以類似 {"ok":true,"started_at":...,"db":...,"users_loaded":0,"agents_running":0} 的 JSON 物件回應健康檢查。若回應內容不同,請先查看 docker compose -f docker/docker-compose.yml logs -f octop,再操作瀏覽器。
現在請為剛建置的映像設定具有辨識性的名稱,因為下一個 --build 會覆寫 octop:latest,之後你將無法分辨兩者:
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}"不要嘗試使用一般的覆寫檔案修正。Compose 會串接多個檔案中的 ports 清單,而不是取代清單,因此最後會同時發布兩個對映,並導致第二個對映繫結失敗。若要保留上游檔案不變,請在該序列上使用 !override 標籤。這是文件所述、用來取代而非附加的方法。Compose 合併多個檔案的說明涵蓋其餘合併規則。
繫結至 loopback 也能解決防火牆可能遇到的問題。Docker 會將發布連接埠的規則寫入 nat table,位置在 ufw 管理的 chains 之前,因此 ufw deny 8088 不會阻止已發布的容器連接埠。在 Docker Engine 28.0.0 或更新版本中,繫結至 127.0.0.1 的連接埠無論 ufw 的設定為何,都無法從外部連線。這就是它是正確修正方式,而不是次佳方案的原因。較舊的 Engine 版本允許相同 L2 網段上的主機,例如供應商交換器上的其他機器,連線至發布到 localhost 的連接埠。因此,請執行 docker version;若伺服器回報低於 28 的版本,請進行升級。
使用反向代理處理 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 /api/agents/{id}/chat/ws,因此若缺少 proxy_http_version 1.1 和兩個升級標頭,nginx 會以 400 Bad Request 回應升級嘗試:儀表板可以正常載入,但你傳送的每則訊息都會永久停住,頁面上也不會顯示錯誤。proxy_buffering off 很重要,因為人機協作續接端點會傳回 text/event-stream;若 SSE(伺服器傳送事件)被代理伺服器放在緩衝區中,內容會在最後一次成批送達,而不是以串流方式傳送。proxy_read_timeout 用於涵蓋長時間執行的工具操作,因為 60 秒的預設值會在代理程式完成工作前中斷執行,並記錄 upstream timed out (110: Connection timed out)。
反向代理後的 JWT 驗證行為
Octop 使用 bearer token 驗證,而不是 cookie。POST /api/auth/login 會傳回 {access_token, role, user, ...},之後的請求會攜帶 Authorization: Bearer <access_token>。對反向代理而言,這是好消息:不必處理 cookie domain、Secure flag 或 SameSite 規則,因此在 http://127.0.0.1:8088 上正常運作的工作階段,在 https://octop.example.com 上也會以相同方式運作。
在讓實際使用者使用前,請先了解以下兩項影響。
WebSocket 會在 URL 中攜帶 token。 端點是 WS /api/agents/{id}/chat/ws?token=<jwt>,因為瀏覽器 JavaScript 無法在 WebSocket handshake 設定 Authorization header。TLS 能保護傳輸中的 token,但無法防止 token 出現在您自己的日誌中:nginx 預設會將完整請求列(包括 query string)寫入 access_log,因此實際使用者的有效 token 會出現在伺服器上的純文字檔案中。請記錄不含參數的路徑。$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 的簽署金鑰,並立即使所有尚未到期的 token 失效。對所有使用者皆然。因此,當有人離開團隊時,處理順序為:刪除該使用者、輪替 secret,然後通知其餘使用者重新登入。若這樣的處理過於繁重,可以縮短有效期限,但請記得同時將該變數加入 environment: 清單及 .env:
OCTOP_ACCESS_TOKEN_TTL=28800Octop 已處理暴力破解: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_ENABLED、LANGFUSE_PUBLIC_KEY、LANGFUSE_SECRET_KEY 與 LANGFUSE_BASE_URL,因此您可以將 traces 傳送至自己的 Langfuse instance,直接查看 agents 實際執行的內容,而不是只根據 chat window 猜測。
使用者、角色與共用代理程式庫
首次開機建立的 admin 帳號負責建立及管理其他帳號。每位使用者都有自己的代理程式、工作區與認證資訊,而這些隔離由瀏覽器持有的 token 維持。除此之外,系統還提供所有人都能使用的共用技能與子代理程式庫。這項功能正是適合家庭使用的原因:一個人建立好研究代理程式後,其他人不必重新建立。
使用工具時請務必小心。Octop 提供工具核准與 shell 指令防護,兩者都確實有效;但執行 shell 指令的代理程式,會在掛載資料磁碟區的 Octop 容器內執行這些指令。防護機制能限制不慎撰寫的提示詞所造成的影響,但不是 sandbox 邊界。因此,對於不會交付 shell 使用權限的人,請保持工具核准功能開啟。如果你正在與其他選項比較,自架 AI 代理程式總覽會比較各方案的處理方式。
升級如此快速發布的專案
此圖表背後的資料
[
{
"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 中的 tag 日期,統計截至 7 August 2026。4 個帶有 tag 的版本在 9 天內發布,最短間隔只有 1 天;而 v0.9.19 則是在前一個 tag 後 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"先確認 $NEW_TAG 實際指向的內容,再切換到該版本,因為此專案會將 v1.0.2b9 這類 beta 版本與穩定版本一併建立 tag。截至 20 October 2026,最新 tag 是穩定版 v1.0.2,發布於 18 October 2026;從 v0.9.19 升級時會跨過 14 September 2026 發布的 v1.0.0,因此變更日誌很長,值得仔細閱讀。
每次都先建立備份,因為資料庫 migration 會在啟動時執行。對於發布如此快速的專案,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.db、config.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/api/agents/.../chat/ws 失敗的訊息。代理程式沒有轉送升級要求。加入 proxy_http_version 1.1,以及 Upgrade 和 Connection 標頭。
整段回覆延遲數秒後一次出現。 串流功能正常,但啟用了緩衝。設定 proxy_buffering off。
bind: address already in use。 已有其他程序占用 8088。sudo ss -tlnp | grep 8088 可找出該程序。若你在 override 檔案中新增第二個 ports 項目,而不是編輯原本的項目,也會出現這個結果。
正確的密碼遭到拒絕。 連續 5 次輸入錯誤會觸發 900 秒的鎖定。請等待鎖定解除,不要重新安裝。
.env 中的新密碼沒有生效。 這些憑證只會在首次初始化時套用。請在儀表板中變更密碼。
代理程式會回覆,但始終不會執行工具。 幾乎總是本機模型的問題:context window 太小,無法容納工具定義,或模型不擅長 function calling。調高 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,即可運作。請將防火牆的 port 11434 限制於 Docker 的位址範圍,因為 Ollama 本身沒有驗證機制。預期需要將 Ollama 的 num_ctx 提高至 16k 或更高,因為包含工具定義的代理程式提示會超出預設 context window,模型之後就會停止呼叫工具。
我需要反向代理,還是可以直接開放 port 8088?
你需要反向代理。Octop 隨附的 Compose 檔案會在所有介面發布 8088,且未啟用 TLS,因此密碼與 bearer token 會以明文穿越網際網路。請將發布的 port 改為 127.0.0.1:8088:8088,並在前方設定 Caddy 或 nginx 與憑證。使用 nginx 時,請轉送 WebSocket upgrade 標頭並設定 proxy_buffering off,否則頁面雖然會載入,聊天功能卻會無聲地無法回應。
Octop 已經適合正式環境嗎?
截至 August 2026,Octop 尚未達到 1.0,且每週發布數個 tagged release。它在 14 September 2026 標記 v1.0.0,之後陸續發布多個 1.0.2 beta tag,並於 18 October 2026 發布穩定版 v1.0.2。發布速度仍然很快,因此應將它視為具潛力的軟體,而不是已經成熟穩定的方案。如果固定使用明確的 tag、每次升級前閱讀 commit log,並在每次重建前備份 data volume,家庭或小型內部團隊可以使用。請勿在 latest 上執行,也暫時不要在其中放置客戶資料。