目錄
用 Docker Compose 架設 WordPress(含 MySQL)
這一節用 Docker Compose 架一個完整的 WordPress 網站。完成後你會有:
- WordPress(PHP + Apache,官方映像檔
wordpress:7-apache) - MySQL 8.4 資料庫,加上健康檢查,資料庫準備好才啟動 WordPress
- 資料保存在 Volume,容器刪掉重建也不會遺失
- 上傳檔案大小調整為 64 MB
- 需要時才啟動的 phpMyAdmin 管理介面
本節用到的 Compose 語法(depends_on、healthcheck、profiles、.env)在 Compose 入門 與 docker compose 指令 都介紹過。
建立專案
建立一個資料夾 wordpress,放入三個檔案:
wordpress/
├── compose.yaml
├── .env
└── uploads.ini
.env:密碼
MYSQL_ROOT_PASSWORD=change-this-root-password
MYSQL_PASSWORD=change-this-wp-password
請換成你自己的密碼。Compose 會自動讀取同資料夾的 .env,把 compose.yaml 中的 ${MYSQL_PASSWORD} 等變數換成這裡的值。.env 不要提交到 Git。
uploads.ini:上傳大小
WordPress 映像檔預設的 PHP 上傳上限只有 2 MB,上傳稍大的圖片或佈景主題就會失敗。用一個 ini 檔覆寫:
upload_max_filesize = 64M
post_max_size = 64M
memory_limit = 256M
官方 PHP 映像檔會讀取 /usr/local/etc/php/conf.d/ 下所有的 .ini,所以只要把這個檔案掛載進去即可。
compose.yaml
services:
db:
image: mysql:8.4
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
volumes:
- db_data:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "-uroot", "-p${MYSQL_ROOT_PASSWORD}"]
interval: 10s
timeout: 5s
retries: 10
start_period: 30s
restart: unless-stopped
wordpress:
image: wordpress:7-apache
depends_on:
db:
condition: service_healthy
ports:
- "8080:80"
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_NAME: wordpress
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: ${MYSQL_PASSWORD}
volumes:
- wp_data:/var/www/html
- ./uploads.ini:/usr/local/etc/php/conf.d/uploads.ini:ro
restart: unless-stopped
phpmyadmin:
image: phpmyadmin
depends_on:
- db
ports:
- "127.0.0.1:8081:80"
environment:
PMA_HOST: db
profiles: [tools]
volumes:
db_data:
wp_data:
重點說明:
| 設定 | 作用 |
|---|---|
MYSQL_DATABASE / MYSQL_USER / MYSQL_PASSWORD | MySQL 映像檔第一次啟動(資料夾是空的)時,自動建立資料庫與帳號 |
healthcheck | 每 10 秒用 mysqladmin ping 檢查 MySQL 是否可以連線。要寫 -h 127.0.0.1 而不是 localhost,否則初始化還沒完成就會被判定為 healthy,原因見 MySQL |
condition: service_healthy | 等 db 變成 healthy 才啟動 WordPress,避免 WordPress 先起來卻連不到資料庫 |
WORDPRESS_DB_HOST: db | 用服務名稱 db 連線,Compose 的網路會自動解析成 MySQL 容器的 IP |
db_data:/var/lib/mysql | MySQL 的資料存在 Volume |
wp_data:/var/www/html | WordPress 程式、外掛、佈景主題、上傳的媒體存在 Volume |
profiles: [tools] | phpMyAdmin 預設不啟動,加 --profile tools 才會啟動 |
127.0.0.1:8081:80 | phpMyAdmin 只綁定本機,外部連不到 |
MySQL 只在 Compose 內部網路中被 WordPress 存取,所以 db 沒有設定 ports,不對外開放。
啟動
在 wordpress 資料夾中執行:
$ docker compose up -d
[+] up 32/32
✔ Image wordpress:7-apache Pulled 28.0s
✔ Network wordpress_default Created 0.1s
✔ Volume wordpress_db_data Created 0.0s
✔ Volume wordpress_wp_data Created 0.0s
✔ Container wordpress-db-1 Healthy 11.1s
✔ Container wordpress-wordpress-1 Started 11.3s
注意順序:Compose 先建立網路與兩個 Volume,wordpress-db-1 等了 11 秒變成 Healthy 之後,wordpress-wordpress-1 才 Started,這就是 condition: service_healthy 的效果。第一次執行需要下載映像檔,時間會比較久。
確認狀態:
$ docker compose ps
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
wordpress-db-1 mysql:8.4 "docker-entrypoint.s…" db 16 seconds ago Up 16 seconds (healthy) 3306/tcp, 33060/tcp
wordpress-wordpress-1 wordpress:7-apache "docker-entrypoint.s…" wordpress 16 seconds ago Up 5 seconds 0.0.0.0:8080->80/tcp, [::]:8080->80/tcp
db 的 STATUS 顯示 (healthy),而且 PORTS 只有容器內部的 3306/tcp,沒有對應到主機;wordpress 則把主機的 8080 對應到容器的 80。
兩個 Volume 也建立好了,名稱是「專案名稱_Volume 名稱」,專案名稱預設就是資料夾名稱:
$ docker volume ls
DRIVER VOLUME NAME
local wordpress_db_data
local wordpress_wp_data
在瀏覽器完成安裝
打開 http://localhost:8080,第一個畫面是選擇語言。清單中選擇你要的後台語言(例如「繁體中文」),按 Continue。本教學的截圖為了與其他語言版本共用,選擇的是 English (United States)。
接著填寫網站資訊:

| 欄位 | 說明 |
|---|---|
| Site Title | 網站標題,之後可在後台修改 |
| Username | 管理員帳號。不要用 admin,容易被猜中(本範例只是示範) |
| Password | 管理員密碼,WordPress 會顯示強度 |
| Your Email | 管理員 Email,用來接收通知與重設密碼 |
| Search engine visibility | 勾選後會要求搜尋引擎不要收錄,網站還在測試時可以勾選 |
這裡不會出現資料庫設定畫面,因為 WORDPRESS_DB_* 環境變數已經提供了連線資訊,映像檔啟動時自動產生了 wp-config.php。
按 Install WordPress 後,看到 Success 畫面就表示安裝完成:


http://localhost:8080/wp-login.php用剛才設定的帳號密碼登入,就會進入管理後台。歡迎區塊顯示的版本是 7.1.3,也就是 wordpress:7-apache 映像檔當下內含的版本:

前台 http://localhost:8080 已經可以看到預設的 Hello world! 文章:

確認上傳大小限制
到後台 Media → Add Media File,上傳區下方會顯示目前的上限。顯示 Maximum upload file size: 64 MB,表示 uploads.ini 有生效:

如果還是 2 MB,檢查 uploads.ini 的掛載路徑是否正確,修改後要用 docker compose up -d 重建容器(restart 不會套用新設定)。
用 phpMyAdmin 管理資料庫(選用)
phpMyAdmin 設定了 profiles: [tools],平常的 docker compose up -d 不會啟動它。需要時加上 --profile tools:
$ docker compose --profile tools up -d phpmyadmin
[+] up 25/25
✔ Image phpmyadmin Pulled 6.3s
✔ Container wordpress-db-1 Running 0.0s
✔ Container wordpress-phpmyadmin-1 Started 0.6s
指令最後指定 phpmyadmin,只啟動它(以及它依賴的 db,已經在執行中)。
打開 http://localhost:8081,Username 填 root,Password 填 .env 中的 MYSQL_ROOT_PASSWORD:

登入後點左側的 wordpress 資料庫,就能看到 WordPress 建立的 12 個資料表(wp_posts、wp_options、wp_users…):

phpMyAdmin 的連接埠綁定在 127.0.0.1,只有本機能連。如果是遠端伺服器,請用 SSH 通道(ssh -L 8081:127.0.0.1:8081 使用者@伺服器)連線,不要把它開放到公網。用完可以只停掉它:
docker compose --profile tools stop phpmyadmin
資料存在哪裡
| Volume | 內容 |
|---|---|
wordpress_db_data | MySQL 資料庫:文章、頁面、設定、使用者、留言 |
wordpress_wp_data | WordPress 程式、佈景主題、外掛、上傳的媒體(wp-content/uploads) |
兩個都要備份,缺一個都無法完整還原網站。
備份
在專案資料夾中執行。第一步用 mysqldump 匯出資料庫,第二步用一個臨時的 alpine 容器把 wp_data Volume 打包成 tar.gz:
$ docker compose exec -T db sh -c 'mysqldump -uroot -p"$MYSQL_ROOT_PASSWORD" wordpress' > wordpress.sql
mysqldump: [Warning] Using a password on the command line interface can be insecure.
$ ls -lh wordpress.sql && head -n 5 wordpress.sql
-rw-r--r-- 1 root root 880.8K Oct 13 00:22 wordpress.sql
-- MySQL dump 10.13 Distrib 8.4.11, for Linux (x86_64)
--
-- Host: localhost Database: wordpress
-- ------------------------------------------------------
-- Server version 8.4.11
$ docker run --rm -v "$(basename "$PWD")_wp_data:/data:ro" -v "$PWD:/backup" alpine:3.23 tar czf /backup/wp_data.tar.gz -C /data .
$ ls -lh wp_data.tar.gz
-rw-r--r-- 1 root root 33.9M Oct 13 00:22 wp_data.tar.gz
說明:
exec -T:關閉 TTY,輸出才能正確地用>重新導向到檔案。sh -c '... -p"$MYSQL_ROOT_PASSWORD"':用單引號,讓變數在容器內展開(MySQL 容器有這個環境變數),主機不需要知道密碼。[Warning] Using a password on the command line interface can be insecure.是 MySQL 的提醒,寫在 stderr,不會混進wordpress.sql,可以忽略。wordpress.sql開頭是MySQL dump … Distrib 8.4.11,表示匯出成功。$(basename "$PWD")_wp_data會組出 Volume 名稱wordpress_wp_data。如果你的資料夾名稱不同,請用docker volume ls確認。:ro表示唯讀掛載,備份過程不會改到資料。
把 wordpress.sql 和 wp_data.tar.gz 複製到其他機器或雲端儲存,才算真正的備份。
Windows 使用者的備份
PowerShell 不支援 <,Windows PowerShell 5.1 的 > 會把 SQL 檔存成 UTF-16。改成在容器內產生檔案、再用 docker compose cp 複製;打包 wp_data 時直接寫出 Volume 名稱(預設是 資料夾名稱_wp_data):
docker compose exec db sh -c 'mysqldump -uroot -p$MYSQL_ROOT_PASSWORD --result-file=/tmp/wordpress.sql wordpress'
docker compose cp db:/tmp/wordpress.sql wordpress.sql
docker run --rm -v wordpress_wp_data:/data:ro -v "$(pwd):/backup" alpine:3.23 tar czf /backup/wp_data.tar.gz -C /data .
docker compose exec db sh -c 'mysqldump -uroot -p$MYSQL_ROOT_PASSWORD --result-file=/tmp/wordpress.sql wordpress'
docker compose cp db:/tmp/wordpress.sql wordpress.sql
docker run --rm -v wordpress_wp_data:/data:ro -v "${PWD}:/backup" alpine:3.23 tar czf /backup/wp_data.tar.gz -C /data .
docker compose exec db sh -c "mysqldump -uroot -p$MYSQL_ROOT_PASSWORD --result-file=/tmp/wordpress.sql wordpress"
docker compose cp db:/tmp/wordpress.sql wordpress.sql
docker run --rm -v wordpress_wp_data:/data:ro -v "%cd%:/backup" alpine:3.23 tar czf /backup/wp_data.tar.gz -C /data .
還原時反過來:docker compose cp wordpress.sql db:/tmp/restore.sql,再 docker compose exec db sh -c 'mysql -uroot -p$MYSQL_ROOT_PASSWORD wordpress < /tmp/restore.sql'。tar 的打包與解壓縮都在 alpine 容器內進行,不受 Windows 影響。
還原
在新機器(或清空後)放好 compose.yaml、.env、uploads.ini 和兩個備份檔,然後:
# 1. 只啟動資料庫,等它 healthy
docker compose up -d --wait db
# 2. 匯入資料庫
docker compose exec -T db sh -c 'mysql -uroot -p"$MYSQL_ROOT_PASSWORD" wordpress' < wordpress.sql
# 3. 還原 WordPress 檔案到 Volume
docker run --rm \
-v "$(basename "$PWD")_wp_data:/data" \
-v "$PWD:/backup" \
alpine:3.23 sh -c "cd /data && tar xzf /backup/wp_data.tar.gz"
# 4. 啟動全部服務
docker compose up -d
--wait 會等服務變成 healthy 才返回,避免資料庫還沒準備好就開始匯入。.env 中的密碼要和備份時相同,因為 wp-config.php(在 wp_data 中)記錄的是舊的資料庫密碼。
更新
WordPress 核心、佈景主題、外掛可以直接在後台更新,檔案會寫進 wp_data Volume。
要更新映像檔本身(PHP、Apache、MySQL 小版本):
$ docker compose pull
[+] pull 2/2
✔ Image wordpress:7-apache Pulled 0.6s
✔ Image mysql:8.4 Pulled 0.7s
$ docker compose up -d
[+] up 2/2
✔ Container wordpress-wordpress-1 Running 0.0s
✔ Container wordpress-db-1 Healthy 0.5s
pull 下載新版映像檔;up -d 只會重建映像檔有變動的容器。上面的例子映像檔沒有新版本,所以容器維持 Running。
注意事項:
- 更新前先備份。
wordpress:7-apache會跟著 7.x 更新;如果要固定版本,可以寫完整版本號,例如wordpress:7.1.3-apache。wp_data已經有 WordPress 檔案時,映像檔不會覆蓋它們,所以 WordPress 核心版本以後台更新為準。- MySQL 跨大版本(例如 8.0 → 8.4)前,請先閱讀 MySQL 官方的升級說明,不要直接改標籤。
刪除整個環境
練習完要清除,加上 --profile tools 才會連 phpMyAdmin 一起刪除;-v 會刪除 Volume,網站資料會全部消失:
$ docker compose --profile tools down -v
[+] down 6/6
✔ Container wordpress-wordpress-1 Removed 1.5s
✔ Container wordpress-phpmyadmin-1 Removed 1.5s
✔ Container wordpress-db-1 Removed 2.3s
✔ Volume wordpress_wp_data Removed 0.3s
✔ Network wordpress_default Removed 0.2s
✔ Volume wordpress_db_data Removed 0.3s
正式上線注意事項
- 在前面加一個反向代理處理 HTTPS,例如 Nginx、Caddy 或 Traefik,參考 Nginx 靜態網站與反向代理。
- 資料庫不要用
ports對外開放,phpMyAdmin 不要開放到公網。 - 管理員帳號不要用
admin,密碼要夠強。 - 定期自動備份(例如用 cron 執行上面的備份指令),並把備份存到其他機器。
.env不要提交到 Git。
重點回顧
- WordPress 與 MySQL 用 Compose 管理,資料分別存在
db_data與wp_data兩個 Volume。 - MySQL 健康檢查要用
-h 127.0.0.1,避免初始化期間就被判定為 healthy。 - phpMyAdmin 放在 profile 中、只綁定 127.0.0.1。
- 備份要同時包含資料庫與網站檔案,並存到其他機器。
動手練習
練習 1:用一個指令確認 PHP 的上傳上限已經是 64M。
答案
docker compose exec wordpress php -r "echo ini_get('upload_max_filesize');"
輸出 64M。
練習 2:網站要搬到另一台主機,需要帶走哪些檔案?
答案
compose.yaml、.env、uploads.ini,以及兩份備份:wordpress.sql(資料庫)與 wp_data.tar.gz(網站檔案)。在新主機上依本章「還原」的步驟操作。
常見問題
安裝畫面為什麼沒有要我填資料庫設定?
WORDPRESS_DB_* 環境變數已經提供了連線資訊,映像檔啟動時自動產生了 wp-config.php。
上傳檔案時出現超過大小上限?
WordPress 映像檔預設 PHP 上傳上限是 2 MB,用本章的 uploads.ini 調整,修改後用 docker compose up -d 重建容器。
Windows 上怎麼備份?
PowerShell 不支援 <,而且 Windows PowerShell 5.1 的 > 會改變檔案編碼。本章「備份」一節附有在容器內匯出再 docker cp 出來的寫法。
更新於 2026年10月14日