02:當 Docker 說再見的第九次:NAS 上的陣亡循環
「當你的 Docker 容器第 9 次對你說再見,你會開始思考人生。」
上一篇提到,我成功讓 OpenClaw 的容器用 sleep infinity 活了下來。但這只是「活著」,不是「能用」。
接下來的 12 小時,我經歷了:
- 9 次容器陣亡
- 3 次 PowerShell 崩潰
- 無數次的「無法辨識」
這是一段關於「為什麼 NAS 上跑 AI Agent 這麼難」的血淚史。
陣亡 #1-#3:MODULE_NOT_FOUND 的三種姿態
陣亡 #1:entrypoint 設定錯誤
凌晨 1 點,我嘗試修正 docker-compose.yml:
services:
moltbot:
entrypoint: ["node"]
command: ["/app/gateway"]
啟動。
Error: Cannot find module '/app/gateway'
「嗯,因為 /app/gateway 不是 node 模組,是一個不存在的檔案。」
陣亡 #2:command 只寫 gateway
改成:
entrypoint: ["moltbot"]
command: ["gateway"]
啟動。
Usage: moltbot <command> [options]
Container exited with code 0
「它又顯示 help 選單了。」
陣亡 #3:npx 找不到執行檔
再改:
command: npx moltbot gateway
啟動。
could not determine executable to run
「npx 說它不知道要執行什麼。」
這三次陣亡的共同點:我在猜路徑。
我不知道 OpenClaw 的實際執行檔在哪,只能從錯誤訊息裡拼湊。
陣亡 #4:Permission Denied(權限地獄的開端)
好,既然 Docker 內部的路徑這麼複雜,我決定先進到容器裡手動執行:
docker exec -it moltbot-gateway sh
cd /app
ls -la
看到檔案列表:
drwxr-xr-x 2 root root 4096 Jan 28 00:00 dist
drwxr-xr-x 2 root root 4096 Jan 28 00:00 node_modules
-rwxr-xr-x 1 root root 1234 Jan 28 00:00 package.json
「都是 root 權限⋯⋯應該沒問題吧?」
然後我嘗試執行:
node dist/index.js gateway
結果:
Error: EACCES: permission denied, open '/app/workspace/.openclaw/gateway.db'
「???」
「我明明是 root,為什麼會 permission denied?」
後來我發現,問題出在 volume 掛載。
我的 docker-compose.yml 裡有:
volumes:
- ./workspace:/app/workspace
而在 Synology 上,這個 ./workspace 目錄的擁有者是 UID 1026(我的 NAS 帳號)。
但 Docker 容器裡的 process 是用 UID 1000 或 root 在跑。
權限不匹配。
第五課:在 NAS 上跑 Docker,權限問題是第一道關卡。
陣亡 #5-#7:Windows PowerShell 的三連擊 💔
此時我開始懷疑:「是不是 NAS 環境太複雜了?」
於是我決定先在 Windows 上測試,至少拿到一個能用的 setup-token。
打開 PowerShell,輸入:
npm install -g moltbot
added 1 package in 1s
done ✨
「好!」
然後:
moltbot setup-token
moltbot : 無法辨識 'moltbot' 詞彙是 Cmdlet、函數、指令檔或可執行程式的名稱。
請檢查名稱拼字是否正確,如果包含路徑的話,請確認路徑是否正確,然後再試一次。
「?????」
陣亡 #5:PowerShell 找不到全域安裝的指令
陣亡 #6:npx 的「無法判斷」
好,那用 npx:
npx moltbot setup-token
could not determine executable to run
「npx 也不行???」
陣亡 #7:手動找到執行檔,但參數消失了
此時我開始手動翻 npm 的全域安裝路徑:
$npmRoot = npm root -g
ls "$npmRoot\moltbot"
找到了 dist/index.js。
好,直接執行:
node "$npmRoot\moltbot\dist\index.js" setup-token
結果:
hello, moltbot
「⋯⋯」
「然後呢?」
沒有然後了。
程式印了一句 hello, moltbot,然後就結束了。
它沒有接收到 setup-token 參數。
這三次陣亡的共同點:Windows 的 npm 全域安裝 + PowerShell 的路徑解析 = 災難。
凌晨 2 點:「對的森林,但走錯了路徑」
此時我停下來,重新梳理問題:
- Docker 容器裡的 entrypoint 設定不對
- NAS 的權限問題(UID 1026 vs 1000)
- Windows 的 npm 全域安裝找不到指令
- npx 無法判斷執行檔
- 手動執行時參數無法傳遞
每個問題單獨看都有解法,但全部加在一起,我根本不知道該先解決哪一個。
這種感覺就像:
「你知道家在前面,但一直在隔壁社區繞圈圈。」
早上 8 點:sleep infinity 維護模式的荒謬
經過一夜的折騰,我決定採用一個⋯⋯非常蠢的策略:
讓容器活著,什麼都不做,然後手動進去執行指令。
services:
moltbot:
image: ghcr.io/molt-bot/moltbot:latest
command: sleep infinity # 讓它活著,只是活著
volumes:
- ./workspace:/app/workspace
environment:
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
然後:
docker exec -it moltbot sh
cd /app
export ANTHROPIC_API_KEY=sk-ant-...
node dist/index.js gateway
這次⋯⋯成功了!🎉
OpenClaw Gateway starting...
✓ Pairing code: ABC-123-XYZ
Listening on http://localhost:3000
「終於!」
但這個方法的問題是:
- ❌ 每次容器重啟都要手動執行
- ❌ 無法用 systemd 或 cron 自動化
- ❌ 沒有 restart policy
- ❌ logs 不會自動收集
這不是「部署」,這是「維護模式」。
但至少,容器活著了。
中午 12 點:陣亡 #8 與 #9
就在我以為「至少有個能跑的版本」的時候⋯⋯
陣亡 #8:healthcheck 修正設定後連線中斷
我嘗試加上 healthcheck 設定:
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
結果 Gateway 重新啟動,然後 WebUI 顯示:
disconnected (1008): pairing required
「???我剛剛才 pairing 過!」
原來 healthcheck 導致容器重啟,清空了認證資訊。
我需要重新執行:
openclaw pairing approve web ABC-123-XYZ
陣亡 #9:瀏覽器沙盒的最後一根稻草
好,pairing 完成了,我嘗試在 OpenClaw 裡執行一個簡單的 web search。
Error: Failed to launch browser
Error: Browser closed with signal SIGTRAP
「又來了。」
這是 Chrome/Playwright 在 Docker 容器裡的經典問題。
要解決,需要:
- 安裝完整的 Chrome 依賴(libX11, libgbm, libasound...)
- 設定
--no-sandboxflag - 可能還需要
--disable-dev-shm-usage
而這些,在 Synology DSM 的 Docker 環境裡⋯⋯非常難搞。
下午 1 點:我放棄了(暫時)
看著螢幕上的錯誤訊息,我做了一個決定:
「也許 NAS 不是最適合的平台。」
不是說 DS920+ 效能不夠,而是:
- Docker 網路設定複雜
- 權限問題層出不窮
- 瀏覽器沙盒需要完整 Linux 環境
- HTTPS 憑證(Telegram/Discord Webhook 強制要求)
- Port forwarding 設定
每一項都能解決,但全部加在一起,投入的時間成本已經超過「買一台 Mac Mini」了。
更重要的是:
我只是想要一個能用的 AI Agent,不是想研究 Docker 底層原理。
陣亡統計:9 次容器之死
讓我們回顧一下這 9 次陣亡:
#1 — entrypoint 路徑錯誤
- 錯誤:
MODULE_NOT_FOUND: /app/gateway - 解法:改用正確的執行檔路徑
#2 — command 參數未傳遞
- 錯誤:
Usage: moltbot <command> - 解法:明確指定
gateway
#3 — npx 找不到執行檔
- 錯誤:
could not determine executable - 解法:使用完整路徑
#4 — 權限問題(UID 不匹配)
- 錯誤:
EACCES: permission denied - 解法:設定
user: "1026:1026"
#5 — Windows PowerShell 找不到全域指令
- 錯誤:
無法辨識 'moltbot' 詞彙 - 解法:重啟 PowerShell 或用完整路徑
#6 — npx 在 Windows 上失效
- 錯誤:
could not determine executable - 解法:放棄 npx,手動執行
#7 — 參數未傳遞給程式
- 錯誤:
hello, moltbot(然後就結束了) - 解法:找到正確的 CLI entry point
#8 — healthcheck 導致重啟後認證清除
- 錯誤:
disconnected (1008): pairing required - 解法:重新執行 pairing approve
#9 — 瀏覽器沙盒無法啟動
- 錯誤:
Browser closed with signal SIGTRAP - 解法:安裝完整依賴或改用雲端平台
9 次陣亡,9 種不同的死法。
但每一次,都讓我更了解 OpenClaw 的運作方式。
教訓:「可以跑」不等於「能順利跑起來」
DS920+ 的硬體規格完全足夠跑 OpenClaw。
問題不在硬體,在於:
- Docker 環境的複雜度:NAS 的 Docker 不等於一般 Linux 的 Docker
- 權限管理:DSM 的 UID/GID 跟容器內部的權限不匹配
- 瀏覽器沙盒:需要完整的 GUI 依賴,不是所有 Docker 環境都有
- HTTPS/Webhook:需要公開的 SSL 憑證,純內網不夠
每一項單獨看都能解決,但全部加在一起,投入的時間成本已經不划算。
下集預告:策略轉折
在陣亡 9 次後,我開始思考:
「也許我不該堅持『純本地部署』。」
「也許,雲端 + 本地的混合架構才是最佳解。」
於是我發現了 Zeabur, 一個提供一鍵部署 OpenClaw 的 PaaS 平台。
下一篇,我們會聊:
- 為什麼放棄純 NAS 不代表放棄本地運算
- 「雲地協作」架構的誕生
- Zeabur 的曙光與新的挑戰
《從陣亡循環到雲地協作:策略轉折》
敬請期待 🐾