WordPress 博客从宿主机 LNMP 迁移至 Docker

作者:司陌笙

环境:阿里云 ECS / Alibaba Cloud Linux 3

标签:Docker、Zabbix、排错、阿里云、运维学习

一、为什么要迁移

原博客直接部署在宿主机上,Nginx、PHP、MariaDB 混合安装。随着运维需求增加(服务器上还运行了 Zabbix 监控等),手动管理多个服务变得混乱。Docker 化之后每个服务独立隔离,升级、备份、迁移都更加清晰可控。

二、迁移前的环境

宿主机原环境

  • OS:Alibaba Cloud Linux 3
  • Web:Nginx(手工安装)
  • PHP:7.4.33
  • Database:MariaDB 10.5
  • WordPress 根目录:/usr/share/nginx/html

Docker 目标架构

lnmp-nginx (nginx 官方镜像, 端口 80)
    └── FastCGI ── lnmp-php (wordpress:php7.4-fpm, 端口 9000)
                        └── TCP 3307 ── lnmp-mysql (mariadb:10.5)

数据卷:

宿主机目录容器内挂载用途
/data/lnmp/www/var/www/htmlWordPress 代码
/data/lnmp/mysql/var/lib/mysql数据库持久化

三、迁移步骤

1. 启动 MariaDB 容器

docker run -d –name lnmp-mysql \
  –network lnmp-net \
  -p 3307:3306 \
  -v /data/lnmp/mysql:/var/lib/mysql \
  -e MYSQL_ROOT_PASSWORD=123456 \
  mariadb:10.5

进入容器创建数据库和用户:

CREATE DATABASE wordpress;
CREATE USER ‘wpuser’@’%’ IDENTIFIED BY ‘WpPass@123’;
GRANT ALL PRIVILEGES ON wordpress.* TO ‘wpuser’@’%’;
FLUSH PRIVILEGES;

导入原有博客的 SQL 备份:

docker exec -i lnmp-mysql mysql -uroot -p123456 wordpress < blog_db.sql

2. 启动 PHP-FPM 容器

docker run -d –name lnmp-php \
  –network lnmp-net \
  -v /data/lnmp/www:/var/www/html \
  wordpress:php7.4-fpm

3. 启动 Nginx 容器

docker run -d –name lnmp-nginx \
  –network lnmp-net \
  -p 80:80 \
  -v /data/lnmp/www:/var/www/html \
  -v /data/lnmp/nginx/conf.d:/etc/nginx/conf.d \
  nginx

Nginx 的 default.conf 关键配置:

server {
    listen 80;
    server_name _;
    root /var/www/html;
    index index.php index.html;

    location / {
        try_files $uri $uri/ /index.php?$args;
    }

    location ~ \.php$ {
        fastcgi_pass lnmp-php:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME /var/www/html$fastcgi_script_name;
        include fastcgi_params;
    }
}

注意:fastcgi_pass 指向的是容器名称 lnmp-php,因为三个容器在同一个 Docker 网络中,可以通过容器名互相通信。


四、踩坑排错全记录

问题 1:访问出现 WordPress 安装页面

现象:浏览器打开 IP 进入 WordPress 安装向导,而不是已有博客的首页。

原因:从宿主机复制的 WordPress 文件中缺少 wp-config.php,只有示例文件 wp-config-docker.php。

解决

cp /data/lnmp/www/wp-config-docker.php /data/lnmp/www/wp-config.php


问题 2:数据库连接失败 (localhost 陷阱)

错误配置

define(‘DB_HOST’, ‘localhost’);   // 错误

在 Docker 架构中,WordPress 运行在 lnmp-php 容器中,数据库在 lnmp-mysql 容器中。localhost 指的是容器自身,而不是另一台”机器”。

正确配置

define(‘DB_HOST’, ‘lnmp-mysql’);  // 使用 Docker 容器名


问题 3:数据库权限 “Access denied for user ‘wpuser’@‘localhost’”

原因:原宿主机 MariaDB 中,用户 wpuser 只有 @localhost 的权限。Docker 容器间访问是通过 TCP,来源 IP 不是本地,需要 @’%’ 远程权限。

解决:在 lnmp-mysql 容器中执行:

CREATE USER ‘wpuser’@’%’ IDENTIFIED BY ‘WpPass@123’;
GRANT ALL PRIVILEGES ON wordpress.* TO ‘wpuser’@’%’;
FLUSH PRIVILEGES;


问题 4:HTTP 500 Error – 本次迁移的核心难题

现象:所有页面返回 HTTP 500,浏览器显示”当前无法使用此页面”。

排查过程

docker logs lnmp-php –tail 50

关键报错:

PHP Warning:  Unknown: failed to open stream: No such file or directory in Unknown on line 0
PHP Fatal error:  Unknown: Failed opening required ‘/usr/share/nginx/html/wordfence-waf.php’

根因分析

  1. 宿主机上 WordPress 安装在 /usr/share/nginx/html/
  2. Docker 容器中 PHP 的工作目录是 /var/www/html/
  3. 原环境安装的 Wordfence 安全插件通过 .user.ini 文件强制加载 WAF 防火墙
  4. .user.ini 中的 auto_prepend_file 写死了宿主机的绝对路径

; Wordfence WAF
auto_prepend_file = ‘/usr/share/nginx/html/wordfence-waf.php’
; END Wordfence WAF

PHP 启动时解析 .user.ini,发现该文件不存在,直接报 Fatal Error,后续所有请求都返回 500。

修复

# 删除包含错误路径的 .user.ini
rm -f /data/lnmp/www/.user.ini

# 重启 PHP 容器
docker restart lnmp-php


问题 5:WP Super Cache 插件路径残留

现象:500 问题解决后,PHP 日志仍有 Warning:

PHP Warning:  include(): Failed opening ‘/usr/share/nginx/html/wp-content/plugins/wp-super-cache/wp-cache-base.php’

原因:和 Wordfence 同样的问题——插件 wp-super-cache 的 advanced-cache.php 和 wp-cache.php 中写入了宿主机的绝对路径。

修复

# 全局搜索所有包含旧路径的 PHP 文件
grep -rn ‘/usr/share/nginx/html’ /data/lnmp/www/ –include=’*.php’ -l

# 批量替换为容器内路径
grep -rn ‘/usr/share/nginx/html’ /data/lnmp/www/ –include=’*.php’ -l \
  | xargs sed -i “s|/usr/share/nginx/html|/var/www/html|g”

# 重启 PHP 容器
docker restart lnmp-php


五、最终的 wp-config.php 配置

define(‘DB_NAME’, ‘wordpress’);
define(‘DB_USER’, ‘wpuser’);
define(‘DB_PASSWORD’, ‘WpPass@123’);
define(‘DB_HOST’, ‘lnmp-mysql’);       // 容器名,不是 localhost
define(‘DB_CHARSET’, ‘utf8mb4’);
define(‘DB_COLLATE’, ”);


六、迁移完成后的容器状态

容器镜像状态
lnmp-nginxnginx运行中
lnmp-phpwordpress:php7.4-fpm运行中
lnmp-mysqlmariadb:10.5运行中

所有页面正常返回 HTTP 200,后台登录、文章查看、评论显示均正常。


七、经验总结

  1. Docker 迁移不等于简单复制文件。容器内的目录结构与宿主机不同,任何写死绝对路径的配置都会失效。
  2. localhost  Docker 中不是万能的。容器间通信需要使用容器名或 Docker 网络别名,localhost 只代表容器自身。
  3. WordPress 插件可能悄悄写死路径。Wordfence 通过 .user.ini 注入 auto_prepend_file,WP Super Cache 在 advanced-cache.php 中写死绝对路径。迁移后应当全局搜索旧路径,确认没有残留。
  4. 500 错误的排查优先级:先看 PHP 容器的日志 docker logs <php_container>,而不是盯着 Nginx 配置。Nginx 只是透传 upstream 的错误。
  5. 数据库备份是迁移的前提。确保有完整的 SQL 导出文件,迁移中数据库一旦出问题可以快速回滚。
  6. 推荐使用 docker-compose 统一编排。三个容器、网络、卷的配置可以写在一个 docker-compose.yml 中,启动、停止、重启一条命令搞定,避免手动管理容器间的依赖关系。

本次迁移完成,WordPress 从宿主机 LNMP 切换至 Docker 容器化运行,后续升级 PHP 版本、更换 Nginx 镜像版本都只需一条命令即可完成。

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注