公司官网用的是 PbootCMS,服务商到期要换云,或者要把测试站搬到正式服务器。看起来不过是“复制文件 + 导数据库”两件事,但每次迁移总会冒出各种毛病:首页能开、内页全 404;后台进得去、登录验证码出不来;栏目页面打开是 Nginx 404 而不是 CMS 的 404;图片全裂。这些问题九成不是 PbootCMS 本身的问题,而是伪静态规则没配、数据库配置没改、目录权限没给对。
本文按“准备 → 搬程序 → 搬数据 → 改配置 → 配伪静态 → 权限加固 → 验证”的顺序,给出一套可完整复用的 PbootCMS 迁移流程。命令以 CentOS 7/8、AlmaLinux、Ubuntu 20.04/22.04 通用为前提,PHP 版本以 7.4 / 8.1 为例,不同版本路径请按实际调整。
一、迁移前:先摸清现状并做好备份
很多人上来就打包文件,结果漏了数据库或漏了附件。第一步是把老环境的“资产清单”列清楚。
1.1 确认关键信息
# 1. PHP 版本与已装扩展(新环境必须一致或更高) php -v php -m | grep -E 'gd|curl|openssl|mbstring|mysqli|pdo_mysql|pdo_sqlite|fileinfo|sqlite3' # 2. Web 服务器类型与版本 httpd -v 2>/dev/null || nginx -v # 3. MySQL 版本(SQLite 站点跳过) mysql -V # 4. 站点根目录与容量 du -sh /data/www/pboot/* du -sh /data/www/pboot # 5. 确认 PbootCMS 用的数据库类型:看配置文件 cat /data/www/pboot/config/database.php
1.2 备份三件套
# 程序文件(保留权限、软链、时间戳) cd /data/www && tar czf /backup/pboot_$(date +%F).tar.gz pboot # 数据库(MySQL) mysqldump -uroot -p --single-transaction --default-character-set=utf8mb4 \ --routines --triggers pbootdb | gzip > /backup/pboot_db_$(date +%F).sql.gz # SQLite 站点:数据库就是文件,必须和业务文件一起备份(通常在 data/ 目录) ls -lh /data/www/pboot/data/*.db cp -a /data/www/pboot/data /backup/pboot_data_$(date +%F) # 别忘配置文件本身 cp -a /data/www/pboot/config /backup/pboot_config_$(date +%F)
提醒:备份完成后,务必用 tar tzf 备份包 | wc -l 抽查一遍能否正常解出,没验过完整性就不算备份。
二、新环境准备:PHP 扩展一个都不能少
PbootCMS 对 PHP 版本要求不高(5.4 以上即可运行),但缺扩展会直接白屏或功能异常。常见必备扩展:
| 扩展 | 缺失时的症状 | 安装示例(Ubuntu) |
|---|---|---|
| mysqli 或 pdo_mysql | 数据库连接失败、安装向导报错 | apt install php8.1-mysql |
| pdo_sqlite / sqlite3 | SQLite 版站点无法读写数据 | apt install php8.1-sqlite3 |
| gd | 验证码图片无法显示、缩略图生成失败 | apt install php8.1-gd |
| curl | 在线更新、远程接口调用失败 | apt install php8.1-curl |
| mbstring | 中文截取乱码、后台部分功能异常 | apt install php8.1-mbstring |
| fileinfo | 上传附件校验失败 | apt install php8.1-fileinfo(通常内置) |
| openssl | HTTPS 请求、邮件发送失败 | 一般默认已安装 |
# CentOS / AlmaLinux 系列(含 Remi 源)
yum install -y nginx php php-fpm php-mysqlnd php-gd php-mbstring php-curl php-sqlite3
systemctl enable --now nginx php-fpm
# Ubuntu / Debian 系列
apt update && apt install -y nginx php8.1-fpm php8.1-mysql php8.1-gd \
php8.1-mbstring php8.1-curl php8.1-sqlite3
systemctl enable --now nginx php8.1-fpm
# 核对 PHP-FPM 运行用户,后面配权限要用
grep -nE '^\s*(user|group)\s*=' /etc/php/8.1/fpm/pool.d/www.conf
ps aux | grep php-fpm | grep -v grep | awk '{print $1}' | sort -u
三、迁移程序文件
推荐 rsync,可断点续传、保留权限,大附件目录也不怕中断重来。
# 先 dry-run 预览,确认目标路径没写错 rsync -avzHP --dry-run -e 'ssh -p 22' root@老机IP:/data/www/pboot/ /data/www/pboot/ # 正式同步(-a 保留权限属主软链,-P 断点续传+进度) rsync -avzHP -e 'ssh -p 22' root@老机IP:/data/www/pboot/ /data/www/pboot/ # 若老机无法直连:先在老机打包,再传包 # 老机:tar czf /tmp/pboot.tgz -C /data/www pboot # 新机:scp root@老机IP:/tmp/pboot.tgz /tmp/ && tar xzf /tmp/pboot.tgz -C /data/www
同步后核对一致性——用文件总数和总体积对账,是发现“漏拷”最省事的办法:
# 两台机器上分别执行,数字应完全一致 find /data/www/pboot -type f | wc -l du -sb /data/www/pboot # 重点核对这几个目录是否齐全 ls /data/www/pboot # 正常应看到:index.php admin.php config/ core/ apps/ template/ static/ data/ runtime/
四、迁移数据库
4.1 MySQL 版
# 老机导出(务必指定 utf8mb4,避免中文乱码/表情丢失) mysqldump -uroot -p --single-transaction --default-character-set=utf8mb4 \ --routines --triggers pbootdb | gzip > /tmp/pboot.sql.gz # 新机建库(字符集必须一致) mysql -uroot -p -e "CREATE DATABASE pbootdb DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;" mysql -uroot -p -e "CREATE USER 'pboot'@'localhost' IDENTIFIED BY '强密码'; GRANT ALL ON pbootdb.* TO 'pboot'@'localhost'; FLUSH PRIVILEGES;" # 导入 zcat /tmp/pboot.sql.gz | mysql -uroot -p --default-character-set=utf8mb4 pbootdb # 校验:表数量与本机的前缀是否一致(PbootCMS 常见前缀为 ay_) mysql -uroot -p -e "USE pbootdb; SHOW TABLES;" | wc -l mysql -uroot -p -e "USE pbootdb; SHOW TABLES LIKE 'ay_%';" | head -20
4.2 SQLite 版
# SQLite 没有导入导出,直接拷 .db 文件即可,但必须确认源文件没有处于写状态
ls -lh /data/www/pboot/data/
cp -a /data/www/pboot/data/*.db /backup/
# 完整性检查
php -r '$d=new PDO("sqlite:/data/www/pboot/data/pbootcms.db"); var_dump($d->query("select count(*) from ay_content")->fetchColumn());'
五、修改配置文件
PbootCMS 的数据库连接信息在 config/database.php,站点域名与路径相关配置在 config/config.php。凡是写死的域名、绝对路径都要在这里和数据库里改。
# 查看并修改数据库连接配置
cat /data/www/pboot/config/database.php
# 典型内容(按实际情况修改 host / user / passwd / dbname)
return array(
'database' => array(
'type' => 'mysqli', // mysqli / pdo / sqlite
'host' => 'localhost', // 同机用 localhost 或 127.0.0.1
'user' => 'pboot',
'passwd' => '强密码',
'port' => '3306',
'dbname' => 'pbootdb',
'dbprefix' => 'ay_', // 表前缀,必须与老库一致
)
);
# 查找所有写死的老域名 / 老 IP / 老绝对路径
grep -rnE 'old-domain\.com|[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' \
/data/www/pboot/config /data/www/pboot/template | head -30
# 数据库里也要查(站点配置常写在数据表中)
zcat /tmp/pboot.sql.gz | grep -oE 'https?://[a-zA-Z0-9./_-]*(old-domain|老域名)[a-zA-Z0-9./_-]*' | sort | uniq -c | head
优先用后台改:登录后台后,在“系统设置 → 参数配置 / 站点信息”里直接改域名,比改数据库安全。只有后台进不去时才考虑直接改库,且改前必须备份。
六、伪静态配置(PbootCMS 迁移的头号坑)
PbootCMS 的栏目页、内容页都是“友好 URL”(如 /about/、/news/12.html),这些地址在磁盘上并不真实存在,必须由 Web 服务器把请求转发给 index.php。转发规则没配,所有内页就是 404。
6.1 Nginx 规则
server {
listen 80;
server_name www.example.com;
root /data/www/pboot;
index index.php index.html index.htm;
access_log /var/log/nginx/pboot.access.log;
error_log /var/log/nginx/pboot.error.log;
# PbootCMS 伪静态核心规则:文件/目录不存在时,交给 index.php 处理
location / {
if (!-e $request_filename) {
rewrite ^(.*)$ /index.php?p=$1 last;
}
}
# 后台入口(若后台文件名保持 admin.php,此段可省略,但建议加上更稳妥)
location /admin/ {
if (!-e $request_filename) {
rewrite ^/admin/(.*)$ /admin.php?p=$1 last;
}
}
location ~ \.php$ {
fastcgi_pass unix:/run/php/php8.1-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_connect_timeout 5s;
fastcgi_read_timeout 60s;
}
# 安全:禁止访问敏感目录
location ~* ^/(config|core|data|runtime|apps)/.*\.(php|db|sql)$ {
deny all;
}
# 静态资源加速
location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff2)$ {
expires 30d;
access_log off;
}
}
也可以使用更现代的 try_files 写法,效果等价且性能更好(少了 if 判断):
location / {
try_files $uri $uri/ /index.php?p=$uri&$args;
}
注意:if 指令在 location 中配合 rewrite ... last 是 Nginx 官方认可的安全用法,不必过度担心;两种写法任选一种,不要同时写两套,否则会出现路由冲突。
6.2 Apache 规则对照
| 场景 | Apache(.htaccess) | Nginx |
|---|---|---|
| 前端路由转发 | RewriteRule ^(.*)$ index.php?p=$1 [QSA,PT,L] | rewrite ^(.*)$ /index.php?p=$1 last; |
| 前置条件 | RewriteCond %{REQUEST_FILENAME} !-f / !-d | if (!-e $request_filename) 或 try_files |
| 生效方式 | 放在站点根目录 .htaccess,自动生效 | 必须写进 server 块并 nginx -s reload |
| 是否需模块 | 需开启 mod_rewrite 且 AllowOverride All | 无需额外模块 |
| 常见失效原因 | AllowOverride None,.htaccess 被忽略 | 规则写在错误的 server/location,或未 reload |
从 Apache 迁到 Nginx 时,最容易忘的就是这一步:.htaccess 不会被 Nginx 读取,必须手工翻译成 Nginx 规则。
# 改完一定要校验语法并平滑加载
nginx -t
systemctl reload nginx
# 验证:内页应返回 200,而不是 Nginx 的 404
curl -s -o /dev/null -w "%{http_code}\n" http://www.example.com/about/
curl -s -o /dev/null -w "%{http_code}\n" http://www.example.com/news/12.html
七、权限、安全与验证清单
7.1 目录权限
# 假设 PHP-FPM 运行用户为 www-data(CentOS 常见为 nginx)
chown -R www-data:www-data /data/www/pboot
find /data/www/pboot -type d -exec chmod 755 {} \;
find /data/www/pboot -type f -exec chmod 644 {} \;
# 需要写入的目录(上传、缓存、SQLite 数据目录)
chmod -R 775 /data/www/pboot/data /data/www/pboot/runtime /data/www/pboot/static/upload
# 以 Web 用户身份验证写权限
sudo -u www-data touch /data/www/pboot/runtime/test.txt && echo "可写" || echo "不可写"
rm -f /data/www/pboot/runtime/test.txt
# CentOS 的 SELinux 别忘了
getenforce
semanage fcontext -a -t httpd_sys_rw_content_t '/data/www/pboot/(data|runtime)(/.*)?'
restorecon -Rv /data/www/pboot
7.2 安全加固建议
- 修改后台入口文件名:把
admin.php改成不易猜的名字(如manage_a7f3.php),并同步修改 Nginx 里的转发规则,能挡掉绝大多数扫描。 - 禁止外网访问
config/、core/、data/、runtime/下的脚本与.db文件。 - 后台加 IP 白名单(Nginx
allow / deny)或 HTTP Basic 认证,做第二道防线。 - 删除根目录下的
install相关安装入口(若存在),防止被二次安装。 - 站点上线前把
display_errors设为 Off,错误写日志。 - 不要给任何目录开 777;775 已经足够。
location /admin/ {
allow 203.0.113.0/24; # 办公网出口
deny all;
try_files $uri $uri/ /manage_a7f3.php?p=$uri&$args;
}
7.3 迁移后验证清单
- 首页、栏目页、内容页、标签页逐个 curl,状态码应为 200。
- 后台登录页可打开,验证码图片能正常显示(gd 扩展是否装好的试金石)。
- 登录后台,在“系统设置 → 站点信息”里确认域名已改为新域名。
- 上传一张测试图片,确认能上传且前台能显示。
- 发一篇测试文章,确认能保存并能在前台访问。
- 检查模板目录
template/是否完整,首页样式是否正常(CSS/JS 是否 404)。 - 对比新老首页 HTML 的 MD5,除统计代码外应基本一致。
- 检查附件目录文件数是否与老站一致。
- 看
tail -f /var/log/nginx/pboot.error.log有无 Permission denied、No such file 等错误。 - 老域名做 301 跳转到新域名,并在站长平台提交改版。
八、常见问题速查
| 现象 | 原因 | 处理 |
|---|---|---|
| 首页正常,内页全部 Nginx 404 | 伪静态规则未配置或未 reload | 加 rewrite 规则,nginx -t && systemctl reload nginx |
| 后台验证码不显示 | gd 扩展缺失,或 session/runtime 目录不可写 | 装 php-gd;给 runtime 目录写权限 |
| 登录后立刻跳回登录页 | session 目录权限、域名变化导致 cookie 失效 | 清理浏览器 cookie;检查 /var/lib/php/sessions 权限 |
| 页面空白无任何输出 | PHP 报错被隐藏,或 opcache 缓存了旧路径 | 查 php error_log;重载 php-fpm 清空 opcache |
| 数据库连接失败 | config/database.php 账号密码/库名不对 | 核对配置;确认 MySQL 用户权限 |
| 中文变问号或乱码 | 导入时字符集不是 utf8mb4 | 重新按 utf8mb4 导出导入;核对表字符集 |
| 图片裂图(404/403) | 附件未拷贝、权限不对、或页面仍指向老域名 | 补同步 upload 目录;查权限;替换数据库中的老域名 |
| 样式丢失、页面裸奔 | static/ 或 template/ 未完整迁移 | 比对文件数与体积,补 rsync |
小结
PbootCMS 迁移的技术门槛不高,难点在于“不要漏项”。把流程固化成三句口诀会好记很多:文件用 rsync -a 拷、数据库用 utf8mb4 导、伪静态必须重写并 reload。剩下的权限、后台入口改名、IP 白名单属于安全加固,顺手一起做掉。
避坑清单:
- 千万不要只拷程序不拷附件,用
find | wc -l和du -sb对账,不信肉眼。 - SQLite 站点没有“导数据库”这一步,直接拷
data/*.db文件即可,很多人反而找不到。 - 表前缀(常见
ay_)必须与老库保持一致,否则会提示表不存在。 - Apache 的
.htaccess在 Nginx 下完全无效,必须手工翻译。 - 后台入口务必改名,不改名的 PbootCMS 站点几乎必然被扫描爆破。
- 迁移完成后老域名要做 301,并把 robots.txt、sitemap 一并检查。
- 整个迁移过程中始终保持老机运行,确认新站完全正常再切换 DNS。
关键词回顾:PbootCMS 迁移、服务器迁移教程、config/database.php、Nginx 伪静态 rewrite、index.php?p=、目录权限、SELinux。
企业QQ咨询




