Dokploy 新手上路 FAQ:從一次實作中整理的 10 個基礎問題

這不是 step-by-step 教學,是「你真的動手做會問出來的」那 10 個基礎問題,一題一題把底層機制講清楚。Port 到底有幾種、跨機器怎麼接、Invalid origin 在擋什麼、Cloudflare Tunnel 為什麼不用開 port、2FA 跟 CF Access 差在哪——看完這篇,Dokploy 上手時不會一頭霧水。

Dokploy 新手上路 FAQ:從一次實作中整理的 10 個基礎問題

前幾天從零架設了一個 Dokploy + Cloudflare Tunnel + Traefik 的自架服務平台。過程中我問了一堆「看起來很笨但真的卡在那裡」的問題。

這篇不是 step-by-step 教學,是把這些問題的底層原理講清楚——每一題我當下真的停下來問過,看完你下次動手就不用再卡。

排序從淺到深,建議順著讀。


Q1|「這個 API token 已經沒用了」是什麼意思?token 不是會過期嗎?

當時的對話:設定完 Cloudflare Tunnel 後,我被告知「這個 API token 已經沒用了,可以刪掉」。我的反應是「啊?它壞了?」

短答:不是壞了,是任務完成,用不到了

完整解釋:兩種憑證的區別

做這類設定時,常常會同時用到兩種完全不同的憑證,新手很容易搞混。

憑證 用途 生命週期
API Token(短期用) 讓自動化腳本(或 AI)幫你改設定、建資源 做完就該刪
服務 Token(長期用) 讓一個常駐服務持續運作,例如 cloudflared 連接 tunnel 永久留著

建 Cloudflare Tunnel 這個流程裡:

你建 API Token
  → AI 用 API Token 建立 Tunnel
  → API 回傳一組「Tunnel 連接 Token」(JWT)
  → cloudflared 服務拿這個 Tunnel Token 連線
  → 設定完成,API Token 已經沒用了,可以刪

之後 cloudflared 常駐運作,靠的是 Tunnel Token(已經寫在 systemd unit 裡),不再需要 API Token。

為什麼要刪

  • 減少外洩面(對話記錄、截圖、剪貼簿都可能留下)
  • API Token 權限通常很大(能改 DNS、刪 zone settings),留著是風險

口訣:API Token 是鑰匙,用完還給保全;服務 Token 是員工識別證,員工上班要一直帶。


Q2|Dokploy 部署 whoami,會把主機的 port 80 / 3000 占用掉嗎?

當時我超擔心部署了什麼服務會把 Dokploy 自己那個 3000 吃掉。

短答:不會。除非你特別設定,容器的 port 跟主機的 port 是完全分開的。

完整解釋:Docker port 有三種,搞混就卡死

這是新手第一大地雷:

Port 名稱 位置 誰看得到
主機 published port 主機的 0.0.0.0:xxx 整個區域網路、公網(如果你開了防火牆)
容器內部 port 容器裡 process 監聽的 port 只有 Docker 網路裡的其他容器
Traefik 路由 port Traefik 在 Docker 網路裡連去的 port Traefik 自己,當仲介

一般 Dokploy + Traefik 架構,只有 Traefik 自己 publish 主機 port(80、443),其他所有服務容器只在 Docker 內部網路裡活動

外網 → 主機:80(Traefik)Docker 網路 → whoami:80(容器內部)
               ↑ publish           ↑ 完全沒碰主機 port
Code language: CSS (css)

實戰確認

# 誰在聽主機 port 3000?
sudo ss -tlnp '( sport = :3000 )'

# 應該只會看到一個 docker-proxy(代表 Dokploy 自己)
# whoami 容器不會出現,因為它沒 publish 到主機
Code language: PHP (php)
# 看 Docker 容器有沒有 publish port
docker ps --format "table {{.Names}}\t{{.Ports}}"

# Dokploy/Traefik:  0.0.0.0:80->80/tcp, 0.0.0.0:3000->3000/tcp
# whoami 容器:      80/tcp              ← 沒前面那坨「0.0.0.0:xxx->」
Code language: PHP (php)

0.0.0.0:→ 這坨,就是沒佔用主機 port


Q3|可以部署第二個 whoami 嗎?它們會打架嗎?

我問過「如果我要再部署一個 whoami 可以嗎」。

短答:可以,只要給它不同的子網域就好,數量無上限。

完整解釋:Traefik 按 Host header 路由

Traefik 不管誰在哪個 port、哪個容器——它看的是 HTTP 請求的 Host header:

瀏覽器要求 whoami.itsmygo.ukTraefik 查規則:Host(`whoami.itsmygo.uk`) → whoami 容器
瀏覽器要求 whoami2.itsmygo.ukTraefik 查規則:Host(`whoami2.itsmygo.uk`) → whoami2 容器
Code language: CSS (css)

兩個容器跑同樣的 image、同樣監聽 80,完全不會打架——因為它們在 Docker 網路裡是兩個獨立 service,Traefik 知道誰是誰。

為什麼 wildcard DNS 讓這變超方便

Cloudflare DNS 設了 *.itsmygo.uk 之後,任何子網域的流量都會送到你的 Dokploy 那台。你只要:

  1. Dokploy 裡建一個應用、綁 domain
  2. 不用再碰 Cloudflare,立刻生效

數量限制只在你的硬體資源。

不能做什麼

  • 同一個 Host 綁到兩個服務 → Traefik 會任選一個,另一個吃不到流量
  • 同一個 Host + 同一個 path 綁多個 → 同上

要讓兩個服務共用同一個 host,要用 path 區分:api.xxx.uk/v1 → service A,api.xxx.uk/v2 → service B。


Q4|Dokploy 裡的 Domain 分頁那個「Container Port」到底要填多少?

這個問題大家一開始都會填錯。

短答:填容器裡 process 聽的那個 port,不是主機的 port。

完整解釋

這個欄位告訴 Traefik:「送到這個網域的請求,要打到容器內部哪個 port?」

每個 image 有它的「慣用 port」:

服務 它在容器裡聽哪個 port Container Port 欄位就填
whoami 80 80
nginx 80 80
大多數 node/next/nuxt app 3000 3000
Python FastAPI / Flask(預設 uvicorn) 8000 8000
Go app 慣例 8080 8080
Spring Boot 8080 8080

怎麼查? 三種方法:

  1. 查 image 的 Dockerfile 有沒有 EXPOSE xxx
  2. 看官方 docs
  3. 先 deploy、去看 logs 的 “Listening on port xxx”

實戰確認

Traefik 內建 dashboard API,可以直接看它的 runtime config:

docker exec dokploy-traefik wget -qO- http://localhost:8080/api/http/services | python3 -m json.tool
Code language: JavaScript (javascript)

找到你那個服務,會看到:

{
  "name": "app-xxx-service",
  "loadBalancer": {
    "servers": [{"url": "http://app-xxx:80"}]  ← 這個 80 就是你填的 Container Port
  }
}
Code language: JSON / JSON with Comments (json)

Q5|每台 Dokploy 遠端伺服器都要裝 cloudflared 嗎?

我有兩台機器(.217 跟 .10),一開始想著是不是兩台都要裝一套 tunnel。

短答:不是每台都要。先想清楚「這台機器上的服務要不要公網直接訪問」。

完整解釋:兩種機器的定位

機器 角色 需要 cloudflared?
前台機(.217) 跑有公網 URL 的東西(前端、給瀏覽器打的 API) ✅ 要
後台機(.10) 跑後端服務(DB、Redis、Queue、worker、不對外的內部 API) ❌ 不用

理由:後端服務本來就不該被瀏覽器直接打到。它們只跟「前台機上的容器」溝通。既然沒人從外面打,就不需要 tunnel、不需要 domain、不需要 SSL。

後端放後台機的好處

  • 資源隔離:DB 掛了不會拖累前台網站
  • 安全:DB 從頭到尾只在 LAN 內,外面摸不到
  • 簡單:不用為它操心 domain、SSL、tunnel 這些

Q6|那前台(.217)怎麼打到後台(.10)的 DB?

短答:用 LAN IP + published port

完整解釋:Dokploy 遠端伺服器的本質

Dokploy 的「遠端伺服器」不是把 .10 加入 .217 的 Docker Swarm 當 worker。它們是兩台獨立的 Docker 主機,Dokploy 透過 SSH 分別管理。

這代表:

  • .217 上的容器不能service name 直接叫 .10 上的容器(兩邊不在同一個 overlay network)
  • 要溝通,得透過.10 的 LAN IP + 一個它主動公開的 port

實戰做法

假設 Postgres 部署在 .10:

  1. 在 Dokploy .10 的 Postgres 應用,Advanced → Ports 分頁加:
    • Published Port: 5432
    • Target Port: 5432
    • Protocol: tcp
    • Publish Mode: host(重要!這個選項才會綁到 .10 的 LAN IP,而不是只在 Swarm ingress 網路內)
  2. 在 .217 上的 API 容器,設環境變數:

就這樣。API 從 .217 直接連 192.168.50.10:5432,走 LAN,速度超快。

安全提醒

Published port 等於把 DB 開在 LAN 上,所以:

  • 家用路由器別把 5432 打洞到公網
  • 密碼還是要夠強(內網不是安全保證,萬一有設備被打穿就裸奔)

進階選項(想用 service name 而不是 IP)

  • Tailscale / WireGuard:在兩台機器上架個 overlay 網路,服務可以互相用主機名呼叫
  • Dokploy Cluster Mode:把兩台真的加入同一個 Swarm,共用 overlay

家用 / 個人 side project,LAN IP + published port 就夠用,清楚又好懂。


Q7|登入 Dokploy 面板出現「Invalid origin」是什麼意思?

我把 Dokploy 面板對外開成 dokploy.itsmygo.uk 之後,登入時跳這個錯。

短答:網站的「可信任來源白名單」沒包含你現在用的網址。

完整解釋:瀏覽器跨站保護

現代 web 框架(Dokploy 用 Better Auth、Next.js 也有類似機制)都會在登入、改密碼、任何敏感操作時檢查:

這個請求是從我信任的網址發出來的嗎?

這是為了擋 CSRF 攻擊——壞人做一個假網站,偷偷叫你的瀏覽器對真實網站發請求(你之前登入過,還有 cookie)。如果不檢查來源,這種攻擊就成立。

所以 Dokploy 有一個 trustedOrigins 白名單。一開始只有 http://192.168.50.217:3000 這種被預設,新加的公網網域不在名單上,就被擋。

怎麼修

Dokploy 的白名單存在 Postgres 的 user.trustedOrigins 欄位。用 SQL 加進去:

-- 連進 Dokploy 的 postgres 容器
UPDATE "user"
SET "trustedOrigins" = array_append(
  COALESCE("trustedOrigins", ARRAY[]::text[]),
  'https://dokploy.itsmygo.uk'
)
WHERE NOT ('https://dokploy.itsmygo.uk' = ANY(COALESCE("trustedOrigins", ARRAY[]::text[])));
Code language: PHP (php)

然後有個大坑:這個白名單有 30 分鐘記憶體快取,改完要重啟 Dokploy 才會立刻生效。見下一題。


Q8|Dokploy 容器要重啟,直接 docker restart 不行嗎?

短答:不行,會搞壞 Swarm 的 DNS,導致 502。正確做法是 docker service update --force

完整解釋:Docker Swarm 跟單機 Docker 的差別

Dokploy 用的是 Docker Swarm mode(一種內建的容器叢集技術),不是單機 docker run。在 Swarm 裡:

  • service 是「我要跑幾個 X container」的聲明(抽象層)
  • task / container 是實際跑起來的那幾個(具體實例)
  • Swarm 會給每個 service 一個穩定的 DNS 名字(例:dokploy),其他容器用這個名字找它

當你 docker restart <container_id>:

  • 直接戳了那個具體 container
  • Swarm 不知道你幹嘛,overlay 網路的 DNS 來不及更新
  • 結果:Traefik 想找 dokploy 這個 DNS 名,直接 NXDOMAIN

正確做法:

docker service update --force dokploy

這會讓 Swarm 正常地停掉舊 container、起一個新的,DNS 自動更新,外部無感。

怎麼看哪些是 Swarm service

docker service ls

有列出來的就是 Swarm service,重啟用 service update。沒列出來、只在 docker ps 看得到的,用 docker restart 才可以。

容器名字的差別

  • 單機 Docker:你給什麼就叫什麼(例:whoami-test)
  • Swarm service:會自動加後綴,像 dokploy.1.21wg341ibgejo2788zohbjuzu(service名.副本編號.task ID)

看到 .1.xxx 這種格式就是 Swarm,永遠用 docker service 操作。


Q9|Cloudflare Tunnel 為什麼不用開 port、沒有公網 IP 也行?

整個架構最神奇的地方。

短答:因為連線方向是從你家出去,不是從外面打進來。

完整解釋:反向 Tunnel 的原理

傳統部署:

外網 → 你家防火牆(打洞) → 你的伺服器
      ↑ 這一步需要公網 IP、需要開 port、需要動路由器

Cloudflare Tunnel:

你的伺服器 → 主動連線到 Cloudflare Edge → 保持 websocket-like 的長連線
              ↑ 這是「出去」的流量,家用路由器預設放行

用戶 → Cloudflare Edge → 從剛才那條長連線丟下來 → 你的伺服器

也就是說,cloudflared 啟動時主動拜託 Cloudflare 建立連線。之後所有外面來的流量,Cloudflare 從這條連線「倒著丟」給你。

為什麼這樣超安全

  • 你家路由器完全不用開任何進站 port
  • 你的伺服器完全沒暴露在公網(攻擊者連 IP 都掃不到)
  • 所有流量先經過 Cloudflare → DDoS 保護、WAF、Bot 管理全自動開啟
  • 內網 IP 變了也沒差(動態 DSL、cellular)

實戰確認

# cloudflared 在幹什麼
sudo systemctl status cloudflared

# 會看到類似:
# Registered tunnel connection ... ip=198.41.200.113 location=tpe01 protocol=quic
# Registered tunnel connection ... ip=198.41.192.37  location=khh01 protocol=quic
# ↑ 你的機器連去 Cloudflare 的 edge 節點,不是反過來
Code language: PHP (php)
# 確認 HTTP 流量真的走 CF
curl -I https://whoami.itsmygo.uk
# 看 response header:
# server: cloudflare
# cf-ray: xxxxx-SIN   ← CF edge 節點代號
# cf-cache-status: DYNAMIC
Code language: PHP (php)

Q10|Dokploy 2FA 跟 Cloudflare Access,差在哪?要選哪個?

短答:兩個一起用。角色不一樣。

完整解釋:兩道不同位置的鎖

想像你的管理面板像一間房:

保護機制 鎖在哪 擋什麼
Dokploy 2FA (TOTP) 房間裡的保險箱 密碼外洩,但沒你手機的人進不來
Cloudflare Access 社區大門 根本不讓人走進你家巷子

單獨用各自的侷限

只有 Dokploy 2FA:

  • 全世界的機器人都看得到你的 Dokploy 登入頁
  • 他們會持續掃、刷密碼、測 0-day 漏洞
  • 2FA 能擋住登入,但擋不住漏洞爆發那天

只有 Cloudflare Access:

  • 大門守得很好,但進門之後 Dokploy 本身如果只有密碼沒有 2FA,萬一密碼外洩就完蛋

疊起來的登入流程

  1. 打開 dokploy.itsmygo.uk
  2. Cloudflare Access 擋第一關:要求 Google SSO 或 email PIN
  3. 通過 → 看到 Dokploy 登入頁
  4. Dokploy:填帳號密碼
  5. Dokploy 2FA:填手機 app 的 6 位數 TOTP
  6. 進入

日常登入體感:Google 已登入 → 1 秒通過 CF → 填 Dokploy 密碼 → 填 TOTP → 進去。多做的就是最後那個 TOTP 6 位數,對日常幾乎無感,安全大升。

建議

個人站、小團隊、家用:

  • 一定要:Dokploy 2FA(5 分鐘設定)
  • 強烈推薦:Cloudflare Access + Google SSO(10 分鐘設定,免費 ≤50 人)

結語

這十個問題我全部當下都問過。不是因為文件沒寫,是因為現場的直覺跟文件的抽象說法對不上——你得真的 sudo ss -tlnp 看到那個 port、真的 docker ps 看到容器,才會把文件的內容對到現實。

所以這類「自己架一套」的任務,最有效的學法不是先讀完所有文件。是:

  1. 丟一個具體的目標(我要讓 whoami.xxx.uk 可以從外面打)
  2. 動手,卡住就問「為什麼」
  3. 每個為什麼都挖到底

看完這篇,下次你卡在同類問題,至少知道該看哪裡、該怎麼測。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *