我使用 Vagrant 進行本地網站開發已多年,原本並無意轉向 Docker 平台;但隨著 AI 技術的興起,我決定嘗試一下。以下是我的一份實戰紀錄:將 loyalent.wordpress.test 與 staging-blocksy.woodwood.test 從 Vagrant(VVV)遷移到 Docker Desktop,使用 Cursor 遷移兩個 WordPress 網站, 以及一路上除錯的完整過程。
Table of Contents
目標
起點是熟悉的本地 WordPress 環境:VVV(Varying Vagrant Vagrants) 在 Windows 上運行兩個客戶網站:
loyalent.wordpress.test— Polylang、qTranslate 遷移歷史、Blocksy 子主題staging-blocksy.woodwood.test— Blocksy 測試站,附完整外掛套件
目標是在 G:\vvv\project-local 建立現代化架構:
project-local/
traefik/compose.yml # 共用反向代理
loyalent/
app/public_html/ # WordPress 程式碼
db/ # MariaDB 持久化資料
nginx/ # 各站點專屬 Web 伺服器設定
compose.yml
staging-blocksy.woodwood.test/
...相同結構...Code language: PHP (php)
設計原則:
- 每個網站一個 Compose 檔案
- 共用外部網路(
traefik_shared)供 Traefik 路由 - 維持
app/、db/、nginx/分離 - 保留 VVV 自動 bootstrap 行為(外掛、主題、自訂初始化腳本)
第一階段:規劃(第一天)
檢視 Vagrant 設定
在撰寫任何 YAML 之前,先讀取兩個 VVV 網站目錄與 config.yml,了解必須保留的內容:
| 網站 | 網域 | 特殊行為 |
|---|---|---|
| loyalent | loyalent.wordpress.test | Polylang site |
| staging-blocksy | staging-blocksy.woodwood.test |
架構決策:是否保留 Nginx?
早期就遇到一個關鍵問題:在 Traefik 後方,各站點的 Nginx 還有必要嗎?
答案:有必要,至少對這次遷移而言。
VVV 使用 Nginx 處理 WordPress 重寫規則、靜態資源快取,以及轉發到 PHP-FPM。搭配 wordpress:php8.2-fpm 時,仍需要某個元件終止 HTTP 並代理到 9000 埠。Traefik 負責主機路由;Nginx 負責 WordPress 語意。
另一種做法——wordpress:apache,由 Traefik 直接路由到 WordPress——較簡單,但會偏離 VVV 的模型。
計畫內容
共定義六項待辦:
- 各站點資料夾結構
- Compose 檔案(
db、wordpress、nginx、Traefik 標籤) - 從
vvv-init.sh移植的 bootstrap 腳本 - 從 VVV 範本轉換的 Nginx 設定
- Dev Container 設定
- 啟動驗證
第二階段:實作(第二天上午)
建置內容
共用 Traefik 堆疊(traefik:v3.3):
- 80 埠供 HTTP 路由
- 8080 埠供儀表板
- Docker provider,
exposedbydefault=false
各站點堆疊包含:
mariadb:10.11+ 健康檢查wordpress:php8.2-fpmnginx:alpine搭配 Traefik 標籤bootstrap服務(profiletools)供 WP-CLI 初始化dev服務供 Dev Containers 使用
Bootstrap 腳本將 VVV 佈建流程轉為 Docker:
- 等待資料庫 → 下載 WordPress →
wp-config→ 安裝或還原 SQL - 依
.env安裝外掛/主題 - 站點專屬 hooks(loyalent 的 Polylang 遷移)
WordPress 檔案以 robocopy 從 VVV 複製(loyalent 約 12 MB,staging 更大)。
第三階段:除錯馬拉松(第二天下午)
我嘗試在“詢問模式”(ask mode)下使用 Agent,並進行手動除錯。結果,「簡單遷移」在這裡變成數小時的除錯。
錯誤 1:Docker 守護程序未執行
failed to connect to the docker API at npipe:////./pipe/dockerDesktopLinuxEngine
解法: 啟動 Docker Desktop、啟用 WSL 2,等待鯨魚圖示穩定。
錯誤 2:Vagrant 無法啟動 — 8080 埠衝突
Traefik 儀表板與 VVV 都要使用 8080。
解法: 在 vagrant up 前於 Traefik 執行 docker compose down。
錯誤 3:Vagrant SSH 卡住
VM 在跑,但 2222 埠的 SSH 一直無法完成。
替代方案: 從 VirtualBox 主控台直接匯出資料庫,或使用磁碟上既有的 SQL 備份。


從VirtualBox 主控台直接匯出資料庫 (Windows Explorer)
錯誤 4:過期的 Docker 網路

network cc562749a6e0… not found
解法: 關閉所有堆疊、docker network prune、重建 traefik_shared,再以 --force-recreate 啟動。
錯誤 5:120 秒後資料庫仍未就緒
Bootstrap 等待 MariaDB 逾時——但 MariaDB 其實是健康的。
根本原因: wp db check 會對既有資料表執行 mysqlcheck。在空資料庫上永遠失敗。
解法: 將健康檢查改為:
wp db query “SELECT 1″ –path=”$WP_PATH”
錯誤 6:DB_HOST 仍是 localhost
遷移後的 wp-config.php 指向 localhost;在容器內這代表容器本身,而非 db 服務。
解法: wp config set DB_HOST db:3306
錯誤 7:Blocksy Companion 安裝衝突
Destination folder already exists: blocksy-companion-pro/
解法: 偵測已遷移的進階版外掛目錄並啟用,而非重新安裝;設定 WP_CLI_CACHE_DIR=/tmp/wp-cli-cache。
錯誤 8:Traefik 404/網站無法連線
多個問題疊加:
loyalent堆疊沒有 nginx 容器(只有 wordpress + db)traefik_shared網路標籤不一致(external: true與 compose 建立衝突)- Windows 上 Traefik v3.3 Docker provider 探索問題
解法:
- 確保每個站點堆疊都有 nginx
- 一致地將網路標為
external: true - 將 Traefik 升級至 v3.6.2
- 加上明確的 router → service 標籤
錯誤 9:loyalent 壞掉,staging 正常
根本原因: 資料庫中作用中主題為 twentytwentyfive,但複製後主題目錄不完整。
解法: 啟用 blocksy-child,將 WPCACHEHOME 從 /srv/www/loyalent/... 改為 /usr/local/lsws/wordpress/...。
錯誤 10:登入帳密錯誤
Bootstrap 建立了新的 admin/password。VVV 的真實使用者從未匯入。
解法: 從 G:\vvv\vvv-local\database\sql\backups\ 匯入 loyalent.sql(約 12 MB),並執行 HTTPS → HTTP 的 search-replace。
第四階段:與正式環境一致(第三天)
更新外掛時出現 FTP 提示
更新 Yoast SEO 時 WordPress 要求 FTP 帳密。
原因: Windows 綁定掛載的檔案 + 未定義 FS_METHOD。
解法(兩站):
define(‘FS_METHOD’, ‘direct’);
define(‘FS_CHMOD_DIR’, 0775);
define(‘FS_CHMOD_FILE’, 0664);
維護模式卡住
Briefly unavailable for scheduled maintenance.
原因: 瀏覽器更新失敗後殘留的 .maintenance 檔案。
解法: 刪除 .maintenance,改以 WP-CLI 更新。
staging 頁尾文字錯誤
| 環境 | 頁尾 |
|---|---|
| VVV | Copyright © 2026 – by Lim |
| Docker | Copyright © 2026 – WordPress Theme by CreativeThemes |
原因: Bootstrap 啟用了父主題 blocksy,覆蓋了存放自訂器設定的 blocksy-child。
解法: 啟用 blocksy-child、從 .env 清除 INSTALL_THEMES=blocksy,並在安裝主題之後執行 site hooks。
與正式站(woodwood.xyz)的頁首/CSS 不一致
比對 Docker staging 與正式站後發現:
- 約 1,100 筆過期 URL — 資料庫中的
woodwood.xyz、https://、/srv/www/...路徑 - LiteSpeed Cache — CDN 指向無法連線的
cdn.woodwood.xyz;JS/CSS 延遲載入破壞首屏 - 缺少 Blocksy 動態 CSS — 快取清除後未重新產生
global.css(約 22 KB)
已套用修正:
- 對所有舊 URL 執行 search-replace
- 在本地 Docker 停用 LiteSpeed Cache
- 重新產生
wp-content/uploads/blocksy/css/global.css - 設定
WP_DEBUG_DISPLAY false以隱藏 PHP 8.2 棄用通知
結果: 頁首雙色漸層(#DFE9F3 → 白)、膠囊形主按鈕、卡片版面與正式站一致。
最終架構

啟動順序:
# 1. hosts 檔案(一次性)
echo "127.0.0.1 loyalent.wordpress.test" >> /c/Windows/System32/drivers/etc/hosts
echo "127.0.0.1 staging-blocksy.woodwood.test" >> /c/Windows/System32/drivers/etc/hosts
# 2. Traefik
cd /g/vvv/project-local/traefik && docker compose up -d
# 3. 各站點
cd /g/vvv/project-local/loyalent
docker compose up -d
docker compose --profile tools run --rm bootstrapCode language: PHP (php)
經驗教訓
1. 遷移的核心是資料庫,檔案相對簡單
複製 public_html 很直接。沒有 VVV 的 MariaDB 匯出檔,就會得到全新 WordPress:錯誤使用者、空的自訂器設定、缺少內容。在拆除 Vagrant 前務必匯出資料庫。
2. wp db check 不是連線測試
在空資料庫上會永遠失敗。請用 wp db query "SELECT 1" 檢查就緒狀態。
3. 主題自訂器設定在子主題裡
會強制安裝父主題的 bootstrap 腳本會默默抹掉你的設計。Site hooks 必須在安裝主題之後執行,並明確啟用 blocksy-child。
4. 快取外掛在本地行為不同
CDN URL 指向正式環境的 LiteSpeed Cache 會在 Docker 上弄壞 CSS/JS。本地開發請停用或重新設定。
5. Blocksy 動態 CSS 是檔案,不只是 transient
雙色頁首來自 wp-content/uploads/blocksy/css/global.css。只清 transient 而不重新產生此檔案,頁首會變成純白。
6. Windows 綁定掛載需要 FS_METHOD=direct
否則 wp-admin 更新外掛會退回不存在的 FTP 提示。
7. Vagrant 與 Docker 的埠衝突很實在
8080(Traefik 儀表板)、80(HTTP)、2222(Vagrant SSH)——事先規劃哪個堆疊佔用哪些埠。
交付成果
| 產物 | 用途 |
|---|---|
traefik/compose.yml | 共用反向代理 |
*/compose.yml | 各站 WordPress 堆疊 |
*/nginx/default.conf | WordPress Nginx 規則 |
*/app/scripts/bootstrap.sh | 等同 VVV 的佈建流程 |
*/app/scripts/site-hooks.sh | 站點專屬修正(DB 匯入、主題、CSS) |
*/.devcontainer/devcontainer.json | VS Code Dev Containers |
README.md | 安裝與操作手冊 |
兩個網站最終在 Docker 上運行,由 Traefik 路由,VVV 資料已還原,視覺上與正式環境一致——經過約兩天的規劃、實作與系統性除錯。
本文整理了我將開發環境由 VVV 遷移至 Docker 平台的過程與探索,點擊此處可查看其他相關分享成果。
