作者:司陌笙
环境:阿里云 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/html | WordPress 代码 |
| /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’
根因分析:
- 宿主机上 WordPress 安装在 /usr/share/nginx/html/
- Docker 容器中 PHP 的工作目录是 /var/www/html/
- 原环境安装的 Wordfence 安全插件通过 .user.ini 文件强制加载 WAF 防火墙
- .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-nginx | nginx | 运行中 |
| lnmp-php | wordpress:php7.4-fpm | 运行中 |
| lnmp-mysql | mariadb:10.5 | 运行中 |
所有页面正常返回 HTTP 200,后台登录、文章查看、评论显示均正常。
七、经验总结
- Docker 迁移不等于简单复制文件。容器内的目录结构与宿主机不同,任何写死绝对路径的配置都会失效。
- localhost 在 Docker 中不是万能的。容器间通信需要使用容器名或 Docker 网络别名,localhost 只代表容器自身。
- WordPress 插件可能悄悄写死路径。Wordfence 通过 .user.ini 注入 auto_prepend_file,WP Super Cache 在 advanced-cache.php 中写死绝对路径。迁移后应当全局搜索旧路径,确认没有残留。
- 500 错误的排查优先级:先看 PHP 容器的日志 docker logs <php_container>,而不是盯着 Nginx 配置。Nginx 只是透传 upstream 的错误。
- 数据库备份是迁移的前提。确保有完整的 SQL 导出文件,迁移中数据库一旦出问题可以快速回滚。
- 推荐使用 docker-compose 统一编排。三个容器、网络、卷的配置可以写在一个 docker-compose.yml 中,启动、停止、重启一条命令搞定,避免手动管理容器间的依赖关系。
本次迁移完成,WordPress 从宿主机 LNMP 切换至 Docker 容器化运行,后续升级 PHP 版本、更换 Nginx 镜像版本都只需一条命令即可完成。