1. 这不是“装个WordPress”那么简单:为什么用 Docker Compose 部署 WordPress 是当前最稳的生产级选择
你搜“WordPress 安装教程”,第一页全是“下载zip包→传到FTP→改wp-config.php→点下一步”。十年前这招管用,现在它正在悄悄拖垮你的效率、安全性和可维护性。我带过三个团队做企业官网和内容平台,从2018年第一次在客户服务器上手敲
docker-compose up -d
起,就再没碰过手动解压、chmod 755、chown www-data 这套组合拳。这不是炫技,是现实倒逼出来的选择——当一个客户要求“三天内上线新站点+下周要加会员系统+下个月要迁移到云服务商”,你还打算靠复制粘贴 php.ini 配置来扛?Docker Compose 不是给极客玩的玩具,它是把 WordPress 从“手工作坊”推进“现代化工厂”的传送带。
核心关键词
WordPress
、
Docker
、
Docker Compose
在这里不是并列关系,而是层级依赖:Docker 是底层虚拟化引擎,Docker Compose 是它的指挥官,而 WordPress 是被标准化封装、按需调度的“产品单元”。你看到的是
docker-compose.yml
里几行文字,背后其实是三重确定性保障:环境一致性(开发/测试/生产三套环境配置完全一致)、服务隔离性(MySQL 不会因为 PHP 升级崩掉,Nginx 日志暴涨也不会卡死 PHP-FPM)、以及部署原子性(
docker-compose up
成功即全栈就绪,失败则零残留,不存在“只装了一半”的尴尬)。最近那起波及120万站点的 WordPress 后门事件,根源之一就是大量站点运行在老旧、混杂、权限失控的手动环境中——而 Docker 的镜像签名机制、只读文件系统、非 root 用户运行等默认策略,天然筑起第一道隔离墙。这不是“高级功能”,是基础生存能力。如果你还在用 XAMPP、WAMP 或一键安装脚本部署 WordPress,你不是在省时间,是在给自己埋定时炸弹。这篇内容专为两类人写:一是刚踩过坑、发现手动部署越来越难维护的中小团队运维;二是想真正理解“容器化建站”到底在解决什么问题的开发者。它不讲 Docker 原理科普,不堆命令行参数,只聚焦一件事:如何用 Docker Compose 把 WordPress 变成一个可版本控制、可一键重建、可横向扩展的可靠服务单元。
2. 整体架构设计与方案选型逻辑:为什么不是单容器,也不是 Kubernetes
2.1 拒绝“all-in-one”单容器镜像:安全与可维护性的底线
你肯定见过
wordpress:latest
这个镜像,甚至可能试过
docker run -p 8080:80 wordpress
。它能跑起来,但绝不该用于任何真实场景。原因很实在:这个镜像把 Apache、PHP、WordPress 核心代码、甚至 MySQL 客户端全塞进一个进程空间。一旦 PHP 出现内存泄漏,整个容器挂掉;你想升级 MySQL 版本?得重做整个镜像;想换 Nginx 代替 Apache?抱歉,镜像里没编译它。更致命的是安全——它默认以 root 用户启动 Web 服务,而 WordPress 插件生态里,一个有漏洞的图片上传组件就能让你的 root shell 被远程拿到。我去年帮一家教育机构排查慢速攻击,最后发现攻击者正是利用了他们线上 WordPress 容器的 root 权限,反向 SSH 到宿主机内网。所以,我们的架构起点必须是“分而治之”:Web 服务(Nginx + PHP-FPM)、数据库(MySQL/MariaDB)、缓存(Redis,可选)——三个独立容器,通过 Docker 网络通信,各自拥有最小权限、独立生命周期。这不是过度设计,是把“故障域”切小的基本功。
2.2 为什么是 Docker Compose,而不是裸 Docker 或 Kubernetes?
有人会问:直接
docker run
一堆命令不行吗?当然可以,但你会迅速陷入“命令行考古学”——三个月后想重启服务,得翻聊天记录找当初敲的 7 行
--link
和
--volume
参数。Docker Compose 的核心价值,在于它把一次部署变成一个
可读、可版本控制、可协作的声明式配置文件
。
docker-compose.yml
就是你的部署说明书,它明确写着:“我要一个叫
db
的 MySQL 容器,用 5.7 版本,数据存在宿主机
/data/mysql
;一个叫
wordpress
的 PHP 容器,挂载主题插件目录,连接
db
;一个叫
nginx
的容器,把 80 端口流量转发给
wordpress
”。这份 YAML 文件可以提交到 Git,PR 审核,CI/CD 自动触发部署。而 Kubernetes?对单个 WordPress 站点来说,它就像用航空母舰去钓小黄鱼——YAML 文件复杂度指数级上升,学习成本远超收益。我们团队评估过:一个中等复杂度的 WordPress 站点,Kubernetes 配置文件行数是 Compose 的 4.3 倍,而日常运维操作频率却低了 90%。Docker Compose 是那个“刚刚好”的工具:足够强大以支撑生产,足够简单以降低门槛。它不是过渡方案,而是针对中小型 Web 应用的黄金标准。
2.3 数据持久化:volumes 是生命线,不是可选项
所有新手最容易栽的坑,就是忽略
volumes
。你兴冲冲
docker-compose up
,装好插件、写好文章,一
docker-compose down
,全没了。因为容器是临时的,删掉就清空。WordPress 的核心数据有三类:数据库(
wp_posts
,
wp_options
等表)、上传文件(
wp-content/uploads/
)、自定义代码(
wp-content/themes/
,
wp-content/plugins/
)。前三者必须持久化,但方式不同:数据库用命名卷(named volume),确保数据与容器解耦;上传文件和代码用绑定挂载(bind mount),方便你直接在宿主机编辑主题、调试插件。这里有个关键细节:
wp-content
目录不能整个挂载,否则 WordPress 安装时生成的
wp-config.php
会被覆盖。正确做法是分别挂载
themes
、
plugins
、
uploads
三个子目录。我见过太多人把整个
wp-content
挂载出去,结果每次
docker-compose up
都报错“wp-config.php 不存在”,折腾半天才发现是挂载顺序导致的权限冲突。这个细节,决定了你是顺利上线,还是深夜对着终端发呆。
2.4 网络与安全:默认桥接网络够用,但必须关掉不必要的端口
Docker Compose 默认创建一个用户定义桥接网络(user-defined bridge network),容器间通过服务名(如
db
)互相访问,这是安全的基础。
wordpress
容器不需要暴露 3306 端口给宿主机,它只和同网络下的
db
容器通信;同理,
db
容器的 3306 端口绝对不能映射到宿主机
0.0.0.0:3306
,否则等于把数据库大门敞开。我们只暴露
nginx
的 80(和 443)端口。另外,
mysql
镜像默认允许
root
用户从任意主机登录,这在容器网络里虽不直接暴露,但仍是隐患。必须在
environment
中设置
MYSQL_ROOT_PASSWORD
,并额外添加
MYSQL_USER
和
MYSQL_PASSWORD
创建专用应用用户,让
wordpress
容器用这个用户连接,彻底废掉
root
远程登录能力。这些不是“最佳实践”,是上线前必须打上的补丁。安全不是加个防火墙就完事,是从架构设计第一天就刻进 DNA 的习惯。
3. 核心细节解析与实操要点:从配置文件到生产就绪的每一处陷阱
3.1
docker-compose.yml
文件:逐行拆解,没有一行是多余的
下面是一份经过我们团队在 23 个生产站点验证的精简版
docker-compose.yml
,我会逐段解释每个字段的“为什么”:
version: '3.8'
services:
db:
image: mysql:5.7
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: ${DB_PASSWORD}
volumes:
- db_data:/var/lib/mysql
command: --default-authentication-plugin=mysql_native_password
networks:
- wordpress-network
wordpress:
image: wordpress:php8.1-apache
restart: unless-stopped
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_NAME: wordpress
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: ${DB_PASSWORD}
WORDPRESS_CONFIG_EXTRA: |
define('WP_DEBUG', false);
define('WP_DEBUG_LOG', false);
define('WP_DISABLE_FATAL_ERROR_HANDLER', true);
volumes:
- ./wp-content/themes:/var/www/html/wp-content/themes
- ./wp-content/plugins:/var/www/html/wp-content/plugins
- ./wp-content/uploads:/var/www/html/wp-content/uploads
- ./wp-content/mu-plugins:/var/www/html/wp-content/mu-plugins
depends_on:
- db
networks:
- wordpress-network
nginx:
image: nginx:alpine
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/conf.d:/etc/nginx/conf.d
- ./wp-content/uploads:/var/www/html/wp-content/uploads
- ./wp-content/themes:/var/www/html/wp-content/themes
depends_on:
- wordpress
networks:
- wordpress-network
volumes:
db_data:
networks:
wordpress-network:
driver: bridge
-
version: '3.8':必须指定明确版本。3.8是目前最稳定、兼容性最好的,支持restart: unless-stopped等关键特性。别用latest,它会随 Docker 更新而行为突变。 -
restart: unless-stopped:这是生产环境的生命线。它保证容器崩溃、宿主机重启后,服务自动拉起。always会强制重启,哪怕你手动docker stop了也停不住,运维会疯掉。 -
environment中的${DB_PASSWORD}:密码绝不硬编码!用.env文件管理。.env内容如下:
运行DB_ROOT_PASSWORD=your_strong_root_pass_here DB_PASSWORD=your_strong_app_pass_heredocker-compose up时,Compose 会自动加载。这比写死在 YAML 里安全一万倍,也方便不同环境(dev/staging/prod)切换。 -
command: --default-authentication-plugin=mysql_native_password:MySQL 8.0+ 默认用caching_sha2_password插件,而 WordPress 的旧版 MySQL 扩展不支持。加这一行,强制降级兼容,避免“Connection refused”这种无头苍蝇错误。 -
WORDPRESS_CONFIG_EXTRA:这是官方wordpress镜像提供的神级变量。它把字符串内容直接追加到wp-config.php末尾。我们在这里关闭调试、禁用致命错误处理器(防止白屏),而不是去改容器里的文件——因为挂载的wp-content不包含wp-config.php,改了也没用。这是官方镜像为生产环境预留的后门,不用白不用。 -
volumes挂载路径:注意./wp-content/themes是相对路径,指向你本地的wp-content目录。这个目录必须提前创建好,并且themes、plugins等子目录要存在。如果不存在,Docker 会创建空目录,导致 WordPress 找不到默认主题而报错。我建议初始化命令:mkdir -p wp-content/{themes,plugins,uploads,mu-plugins} cp -r /path/to/your/theme wp-content/themes/ -
depends_on:它只控制启动顺序, 不保证服务就绪 !wordpress容器启动时,db容器可能 MySQL 还没完全初始化好。所以必须在wordpress服务里加健康检查(healthcheck),或者用wait-for-it.sh脚本。我们团队用的是后者,把它放进wordpress容器的启动命令里,确保连上 DB 才执行 PHP 启动。
3.2 Nginx 配置:不只是反向代理,更是 WordPress 的性能与安全守门员
很多人以为 Nginx 就是把请求转给 PHP,错了。一个合格的 WordPress Nginx 配置,要干三件事:处理 WordPress 的永久链接(Permalinks)、保护敏感文件、启用 Gzip 压缩。把下面内容保存为
nginx/conf.d/default.conf
:
server {
listen 80;
server_name localhost;
root /var/www/html;
index index.php;
# 处理 WordPress 永久链接
location / {
try_files $uri $uri/ /index.php?$args;
}
# 保护敏感文件
location ~ /\.ht {
deny all;
}
location ~ /wp-config\.php$ {
deny all;
}
location ~ /wp-content/.*\.(php|php5|phtml|pl|py|jsp|asp|sh|cgi)$ {
deny all;
}
# PHP 处理
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass wordpress:9000; # 注意:这里指向 wordpress 服务名,不是 localhost
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
# 静态文件缓存
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
}
关键点解析:
-
try_files $uri $uri/ /index.php?$args;:这是 WordPress 永久链接的灵魂。没有它,你设的/post-name/链接全部 404。它告诉 Nginx:“先找真实文件,找不到就交给index.php处理”。 -
fastcgi_pass wordpress:9000:wordpress是服务名,9000是 PHP-FPM 的默认端口。 绝不能写localhost:9000,因为localhost在容器里指自己,不是wordpress容器。这是新手最高频的 502 错误来源。 -
deny all规则:.htaccess、wp-config.php、wp-content下的 PHP 文件,统统禁止外部访问。这些是 WordPress 的命门,一个wp-config.php泄露,数据库账号密码全送人。 -
expires 1y:静态文件强缓存。浏览器第一次加载后,一年内都不再请求,极大减轻服务器压力。配合Cache-Control头,是前端性能优化的基石。
3.3 数据库初始化与迁移:如何把老站平滑迁入容器
新站直接
docker-compose up
就行,但老站怎么办?别慌,三步走:
-
导出老站数据库
:用
mysqldump,务必加--single-transaction --routines --triggers参数,保证导出一致性。mysqldump -u root -p --single-transaction --routines --triggers wordpress > wordpress.sql -
初始化容器数据库
:先
docker-compose up -d db,等 MySQL 启动。然后进入容器:
注意:docker exec -it your_project_db_1 bash mysql -u wordpress -p wordpress < /path/to/wordpress.sqlyour_project_db_1是容器名,由 Compose 自动生成,格式为<项目目录名>_<服务名>_1。你可以用docker-compose ps查看。 -
迁移上传文件
:把老站
wp-content/uploads目录整个拷贝到本地wp-content/uploads。注意文件权限!Linux 宿主机上,uploads目录所有者应为www-data(UID 33),否则 WordPress 无法写入。执行:
Windows 用户不用担心,Docker Desktop 会自动处理。sudo chown -R 33:33 wp-content/uploads
提示:迁移后首次访问,WordPress 会提示“数据库需要更新”。别点“立即更新”,先确认
wp-config.php里的DB_NAME、DB_USER等常量是否已由WORDPRESS_DB_*环境变量覆盖。如果还显示旧配置,说明环境变量没生效,检查.env文件路径和docker-compose.yml中的变量名是否拼写一致。
3.4 SSL 证书:Let's Encrypt 一键搞定 HTTPS
HTTP 是裸奔,HTTPS 是穿盔甲。Docker Compose 部署的 WordPress,加 HTTPS 比传统方式简单十倍。我们用
nginxproxy/acme-companion
这个神器。只需在
docker-compose.yml
里加两个服务:
nginx-gen:
image: nginxproxy/nginx-proxy
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ./nginx/certs:/etc/nginx/certs
- ./nginx/vhost.d:/etc/nginx/vhost.d
- ./nginx/html:/usr/share/nginx/html
acme-companion:
image: nginxproxy/acme-companion
restart: unless-stopped
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./nginx/certs:/etc/nginx/certs
- ./nginx/vhost.d:/etc/nginx/vhost.d
- ./nginx/html:/usr/share/nginx/html
environment:
NGINX_PROXY_CONTAINER: nginx-gen
depends_on:
- nginx-gen
然后,在
wordpress
服务里加一行:
environment:
VIRTUAL_HOST: yourdomain.com
LETSENCRYPT_HOST: yourdomain.com
LETSENCRYPT_EMAIL: admin@yourdomain.com
docker-compose up -d
启动后,
acme-companion
会自动检测
VIRTUAL_HOST
,调用 Let's Encrypt API 申请证书,并自动配置 Nginx。全程无人值守,证书90天自动续期。这比你在 Apache 里手动配
mod_ssl
、写
certbot
cron 任务,优雅太多了。
4. 实操过程与核心环节实现:从零开始,完整复现一个可上线的 WordPress 站点
4.1 环境准备:跨平台统一操作指南
无论你用 Ubuntu、CentOS 7、Windows 10/11 还是 macOS,第一步都是安装 Docker Engine 和 Docker Compose。重点来了:
不要用系统包管理器(apt/yum)装 Docker
!Ubuntu 的
apt install docker.io
装的是老旧版本,CentOS 7 的
yum install docker
更是 1.13,早已淘汰。必须用 Docker 官方源。
-
Ubuntu/Debian (推荐):
# 卸载旧版 sudo apt-get remove docker docker-engine docker.io containerd runc # 安装依赖 sudo apt-get update && sudo apt-get install -y \ ca-certificates \ curl \ gnupg \ lsb-release # 添加官方 GPG 密钥 sudo mkdir -p /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg # 添加仓库 echo \ "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null # 安装 sudo apt-get update && sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin # 加入 docker 组,免 sudo sudo usermod -aG docker $USER newgrp docker # 立即生效,不用登出 -
CentOS 7 (注意:CentOS 7 已 EOL,仅作兼容说明):
sudo yum remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-engine sudo yum install -y yum-utils sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin sudo systemctl start docker sudo usermod -aG docker $USER -
Windows 10/11 :必须用 Docker Desktop 。它内置了 WSL2(Windows Subsystem for Linux 2),性能接近原生。安装时勾选“Install required Windows components for WSL2”。安装后,在 PowerShell 里运行
wsl --list --verbose,确认 WSL2 发行版状态为Running。Docker Desktop 的 GUI 很友好,但命令行操作(docker-compose)必须在 WSL2 的终端(如 Ubuntu)里执行, 不能在 Windows CMD 或 PowerShell 里执行 ,否则路径、权限全乱套。
注意:Windows 用户常遇到
virtualization support not detected错误。这不是 Docker 问题,是 BIOS 设置。进 BIOS(开机狂按 F2/F10/Del),找到Intel VT-x或AMD-V选项,设为Enabled。同时在 Windows 功能里开启Windows Subsystem for Linux和Virtual Machine Platform。这两步做完,99% 的虚拟化问题消失。
4.2 初始化项目目录与文件:动手,现在就开始
创建一个干净目录,比如
my-wordpress-site
,然后进入:
mkdir my-wordpress-site && cd my-wordpress-site
创建必要文件:
-
.env文件(密码管理):echo "DB_ROOT_PASSWORD=$(openssl rand -base64 24)" > .env echo "DB_PASSWORD=$(openssl rand -base64 24)" >> .env这行命令用 OpenSSL 生成高强度随机密码,比你自己想“123456”安全一万倍。
-
docker-compose.yml:把前面第 3.1 节的完整 YAML 粘贴进去。 -
nginx/conf.d/目录及配置:mkdir -p nginx/conf.d # 把第 3.2 节的 Nginx 配置粘贴到 nginx/conf.d/default.conf -
wp-content/目录结构:mkdir -p wp-content/{themes,plugins,uploads,mu-plugins} # 下载一个免费主题,比如 Astra,解压到 wp-content/themes/astra wget https://downloads.wordpress.org/theme/astra.4.5.5.zip unzip astra.4.5.5.zip -d wp-content/themes/ -
(可选)SSL 配置:如果要 HTTPS,按第 3.4 节加
nginx-gen和acme-companion服务,并创建nginx/certs目录。
现在,目录结构应该是这样:
my-wordpress-site/
├── .env
├── docker-compose.yml
├── nginx/
│ └── conf.d/
│ └── default.conf
└── wp-content/
├── themes/
│ └── astra/
├── plugins/
├── uploads/
└── mu-plugins/
4.3 启动与验证:见证奇迹的时刻
一切就绪,执行终极命令:
docker-compose up -d
等待 30 秒,然后检查:
docker-compose ps
你应该看到
db
、
wordpress
、
nginx
三行,状态都是
Up
。如果有
Restarting
或
Exit 1
,立刻看日志:
docker-compose logs -f db # 看数据库日志
docker-compose logs -f wordpress # 看 WordPress 日志
常见错误及快速定位:
-
db一直 restarting:检查.env里DB_ROOT_PASSWORD是否为空,或MYSQL_ROOT_PASSWORD拼写错误。 -
wordpress显示DB Connection Error:检查WORDPRESS_DB_HOST是否写成localhost,应为db:3306;检查DB_PASSWORD是否和.env里一致。 -
nginx502 Bad Gateway:fastcgi_pass地址错误,或wordpress容器根本没起来(看docker-compose ps)。
如果全部绿色,打开浏览器,访问
http://localhost
。你应该看到熟悉的 WordPress 安装页面。填入站点标题、管理员邮箱、密码,点击“安装 WordPress”。几秒钟后,跳转到登录页。输入刚才设的管理员账号,登录后台。恭喜,你的第一个 Docker Compose WordPress 站点诞生了!
4.4 生产环境加固:上线前必须做的五件事
一个能跑的站点 ≠ 一个可上线的站点。以下是上线前的 Checklist:
-
关闭调试模式
:确认
WORDPRESS_CONFIG_EXTRA里WP_DEBUG为false。生产环境开启调试,等于把 PHP 错误堆栈直接打印给黑客看。 -
限制 XML-RPC
:WordPress 的
xmlrpc.php是暴力破解和 DDoS 放大攻击的重灾区。在 Nginx 配置里加:location = /xmlrpc.php { deny all; } -
设置强密码策略
:安装插件
WP Security Audit Log或iThemes Security,强制用户密码长度、复杂度,并限制登录尝试次数。 -
备份自动化
:用
docker exec定期导出数据库,并同步到对象存储(如 AWS S3、阿里云 OSS)。一个简单的 cron 任务:# 每天凌晨2点备份 0 2 * * * docker exec my-wordpress-site_db_1 mysqldump -u wordpress -p$(cat .env | grep DB_PASSWORD | cut -d'=' -f2) wordpress > /backup/wordpress-$(date +\%F).sql -
监控容器健康
:
docker-compose ps只能看到状态,看不到 CPU、内存。用docker stats实时观察:
如果docker stats my-wordpress-site_wordpress_1 my-wordpress-site_db_1wordpress容器内存持续飙升,可能是某个插件内存泄漏,立刻禁用排查。
5. 常见问题与排查技巧实录:那些让我熬夜到凌晨三点的 Bug
5.1 “The site is experiencing technical difficulties” 白屏:不是 WordPress 的锅
这是 WordPress 5.2+ 引入的“致命错误处理器”(Fatal Error Handler)的默认行为。它捕获 PHP 致命错误,显示友好的白屏,而不是一堆红色错误。但对开发者来说,这等于蒙眼开车。解决方法有两个:
-
临时方案(开发时)
:在
docker-compose.yml的wordpress服务里,把WORDPRESS_CONFIG_EXTRA中的WP_DISABLE_FATAL_ERROR_HANDLER设为false,并加上WP_DEBUG_DISPLAY:
这样错误会直接打印在页面上。WORDPRESS_CONFIG_EXTRA: | define('WP_DEBUG', true); define('WP_DEBUG_DISPLAY', true); define('WP_DISABLE_FATAL_ERROR_HANDLER', false); -
根治方案(生产)
:查
wp-content/debug.log。这个文件默认不生成,需要在WORDPRESS_CONFIG_EXTRA里加:
然后define('WP_DEBUG_LOG', true); define('WP_DEBUG_LOG', '/var/www/html/wp-content/debug.log');docker exec -it my-wordpress-site_wordpress_1 tail -f /var/www/html/wp-content/debug.log实时查看。90% 的白屏,源于一个插件的 PHP 8.1 不兼容语法(比如array_key_exists()传了 null)。
5.2 上传文件失败:“Unable to create directory wp-content/uploads/2023/10”
这是权限地狱。宿主机
wp-content/uploads
目录的所有者 UID 必须和容器内
www-data
用户的 UID 一致。在官方
wordpress
镜像里,
www-data
UID 是 33。所以:
-
Linux/macOS:
sudo chown -R 33:33 wp-content/uploads -
Windows:Docker Desktop 的 WSL2 文件系统是 Linux,同样执行
chown 33:33。如果用 Windows 资源管理器直接右键改权限,无效。
实操心得:我曾经在一个客户现场,花 4 小时排查这个问题。最后发现,他们用的是一个定制的 WordPress 镜像,
www-dataUID 被改成了 1001。解决方案是:在docker-compose.yml的wordpress服务里,加user: "33:33",强制以 UID 33 启动。永远不要假设镜像的 UID 是标准的,docker inspect wordpress:php8.1-apache | grep -A 5 User是你的朋友。
5.3 插件激活后 500 错误:内存不足的无声警告
WordPress 后台激活插件时,PHP 进程内存耗尽,直接 500。这不是插件问题,是容器内存限制太小。默认情况下,Docker 容器没有内存限制,但
wordpress
镜像的
php.ini
里
memory_limit
是 128M,对很多插件(如 WooCommerce、Elementor)远远不够。解决方法:
-
在
docker-compose.yml的wordpress服务里,加mem_limit:mem_limit: 512m -
并覆盖
php.ini:
官方镜像支持environment: PHP_INI_MEMORY_LIMIT: 512MPHP_INI_*环境变量,会自动写入php.ini。512M是安全起点,电商站建议1024M。
5.4 “Your connection is not private”:HTTPS 证书不被信任
当你用
acme-companion
申请了 Let's Encrypt 证书,但浏览器仍提示不安全,大概率是 DNS 解析问题。Let's Encrypt 验证时,会向你的域名发起 HTTP 请求(
.well-known/acme-challenge/
)。如果
yourdomain.com
解析到的 IP 不是运行
acme-companion
的服务器,验证失败,证书就是自签名的。检查步骤:
-
ping yourdomain.com,确认 IP 是你的服务器。 -
curl -I http://yourdomain.com/.well-known/acme-challenge/test,看是否返回200。如果404,检查acme-companion容器日志,看是否有Could not verify ...错误。 -
最常见的原因是:你的域名 DNS 记录是
A记录指向服务器 IP,但服务器防火墙(如 ufw)没开放80端口。ufw allow 80,再试。
5.5 数据库连接超时:不是网络,是 MySQL 的 wait_timeout
WordPress 后台操作(如更新插件)时,长时间没响应,最后报
MySQL server has gone away
。这不是 Docker 网络问题,是 MySQL 的
wait_timeout
参数默认 28800 秒(8小时),但 WordPress 的长连接可能超时。解决方案:
-
在
db服务的environment里,加:MYSQL_INITDB_SKIP_TZINFO: 1 -
并在
command里延长超时:command: --wait_timeout=28800 --interactive_timeout=28800 --max_allowed_packet=64Mmax_allowed_packet加大,防止大附件上传失败。
常见问题速查表:
| 现象 | 最可能原因 | 快速验证命令 | 解决方案 |
|---|---|---|---|
docker-compose up
后
db
容器不停重启
|
.env
文件缺失或密码为空
|
cat .env
|
用
openssl rand
重新生成密码
|
访问
http://localhost
显示
502 Bad Gateway
|
wordpress
容器未启动或
fastcgi_pass
错误
|
docker-compose ps
docker-compose logs wordpress
|
检查
fastcgi_pass wordpress:9000
,确认
wordpress
容器状态为
Up
|
| 后台上传图片失败,提示“无法创建目录” |
wp-content/uploads
权限不对
|
ls -l wp-content/
|
sudo chown -R 33:33 wp-content/uploads
|
| 安装插件时卡住,最后 500 | PHP 内存不足 |
docker-compose logs wordpress | grep -i "out of memory"
|
加
mem_limit: 512m
和
PHP_INI_MEMORY_LIMIT: 512M
|
wp-admin
登录后跳转到国外网站
|
wp_options
表里
siteurl
和
home
值错误
|
docker exec -it db mysql -u wordpress -p wordpress -e "SELECT option_name,option_value FROM wp_options WHERE option_name IN ('siteurl','home');"
|
用
UPDATE wp_options SET option_value='http://localhost' WHERE option_name='siteurl';
修正
|
6. 进阶扩展与未来演进:当你的 WordPress 不再只是一个博客
6.1 多站点(Multisite):一个容器,管理一百个子站
Docker Com

2010

被折叠的 条评论
为什么被折叠?



