CClara轻量论坛系统

PHP 环境迁移指南:从宝塔到 Docker 容器化部署

wbcm
wbcm 见习用户见习用户
发布于 2026-11-08 23:37 ·3 浏览 ·3 回复
内容摘要

介绍将宝塔面板上的 PHP 站点 Clara BBS 迁移到 Docker 的完整流程,包括盘点 PHP 版本与扩展、用 mysqldump 导出数据库并打包站点文件、编写 Dockerfile 安装扩展,以及用 docker-compose 编排 PHP、Nginx 和 MySQL,并提醒保持同版本、使用 utf8mb4 导出以避免返工和中文乱码。

学完这篇,你能把跑在宝塔面板上的 PHP 站点(以 Clara BBS 为例)连代码带数据库搬进 Docker 容器,并且知道迁移过程中哪些地方最容易出事。

第一步:先在宝塔侧把东西盘清楚

Docker 迁移不是"复制粘贴",先把家底列出来,缺一样后面都得返工。

  1. PHP 版本:宝塔「网站 → 站点 → 设置 → PHP 版本」看一眼。Clara BBS 支持 PHP 7.4–8.5,尽量在容器里用同版本,跨大版本升级留到迁移完成之后再做,别一次动两个变量。
  2. PHP 扩展:同页面「扩展」列表截图。这个系统实际会用到的通常是 pdo_mysql、gd、mbstring、fileinfo、curl、exif、zip,开了 Redis 缓存的话再加 redis。
  3. 站点文件:/www/wwwroot/你的站点目录,重点是上传目录和安装时生成的数据库配置文件。
  4. 数据库:mysqldump 导出,别用宝塔的"备份"按钮直接拿 zip,统一用 SQL 文件最省事。
mysqldump -u root -p --single-transaction --default-character-set=utf8mb4 库名 > /www/backup/clara_$(date +%F).sql
cd /www/wwwroot/你的站点目录 && tar czf /www/backup/clara_files.tar.gz .

注意:一定要加 --default-character-set=utf8mb4,否则中文帖子标题和正文可能在导入后变问号,这类乱码回滚起来很痛苦。

第二步:写 Dockerfile 装扩展

Clara BBS 无框架纯 PHP、不需要 Composer、也没有编译缓存,这对容器化是巨大利好——不用 composer install、不用预热缓存,代码目录挂载进去就能跑。唯一要自己动手的是扩展。

FROM php:8.2-fpm-alpine
RUN apk add --no-cache libpng-dev libjpeg-turbo-dev freetype-dev \
 && docker-php-ext-configure gd --with-freetype --with-jpeg \
 && docker-php-ext-install pdo_mysql gd exif \
 && pecl install redis && docker-php-ext-enable redis

构建:docker build -t clara-php:8.2 .

第三步:docker-compose 编排四件套

services:
  php:
    build: .
    volumes:
      - ./www:/var/www/html
    restart: always
  nginx:
    image: nginx:alpine
    ports: ["80:80", "443:443"]
    volumes:
      - ./www:/var/www/html
      - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
    depends_on: [php]
  db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: 换成长密码
      MYSQL_DATABASE: 库名
    volumes: ["./mysql:/var/lib/mysql"]
    restart: always
  redis:
    image: redis:alpine
    restart: always

nginx.conf 里 fastcgi_pass php:9000;——容器之间用服务名互访,不要再写 127.0.0.1。

注意:上传目录必须单独封死 PHP 执行,否则图片马能直接跑起来:

> location ~* /(uploads|data)/.*\.(php|phtml|php5)$ { deny all; }
> 

第四步:导数据、改配置、跑起来

docker compose up -d
docker compose exec -T db mysql -uroot -p密码 库名 < /www/backup/clara.sql
tar xzf /www/backup/clara_files.tar.gz -C ./www

然后把站点里保存数据库连接信息的那个配置文件打开,把 host 从 127.0.0.1 改成 db,Redis 的 host 改成 redis。密码用第二步 compose 里设的那个。

权限也要对:php:8.2-fpm-alpine 里跑的是 www-data,UID 是 82。

chown -R 82:82 ./www

第五步:验证与计划任务

先用 IP 或临时域名访问,重点看四件事:首页能否打开、发一帖能否成功、附件能否上传、后台能否登录。这四项过了再切正式域名。系统保存即生效、无需清缓存,所以改配置不用重启容器,改完刷新即可,只有动了扩展才需要 docker compose restart php。

计划任务这块,Clara BBS 支持前台访问懒触发,也有 /cron 精准入口。流量起来后建议在宿主机加 crontab,而不是塞进容器:

* * * * * curl -s https://你的域名/cron > /dev/null

注意:别把域名解析切过去之后才发现 HTTPS 没配——这个系统的环境体检会检查协议层和安全响应头,迁移完去后台点一次「环境体检」,比肉眼排查快得多。另外源站 IP 变了,Nginx 的证书路径、伪静态规则都要跟着搬,别只搬了代码。

小结

  • 迁移前先盘点:PHP 版本、扩展列表、站点文件、数据库 SQL,四样缺一不可。
  • 这套系统无框架、无 Composer、无编译缓存,容器化只需处理扩展,用官方 php:8.2-fpm-alpine 自己装就行。
  • 容器间用服务名通信,127.0.0.1 在 compose 里是错的。
  • 上传目录必须在 Nginx 层禁掉 PHP 执行。
  • 计划任务放宿主机调 /cron,别放容器里跟业务抢资源。
  • 先 IP 验证再切域名,切完跑一次后台环境体检。
本文转载自 Clara轻量论坛系统,原文地址:https://www.leleweb.cn/thread-1120.html
转载请注明出处,版权归原作者所有。
—/ 5暂无评分
还没有评分,来打第一分吧

全部回复 3

不知不觉
不知不觉 见习用户见习用户 1楼 2026-11-08 23:42

整体路子对,但按这份配置直接搬过去大概率踩三个坑:**容器内 www-data 的 UID 和宝塔的 www 对不上、PHP 官方镜像默认上传上限只有 2M、容器里把 Redis/MySQL 地址填成 127.0.0.1**——这三个先补上再切流量。

扩展和 php.ini:php:8.2-fpm-alpine 官方镜像已自带 mbstring/fileinfo/curl,不用重复装;但 zip 得自己来(apk add libzip-dev && docker-php-ext-install zip),附件解压、部分插件会用到。另外挂一个 php.ini 进容器,把 upload_max_filesize / post_max_size 调到 30M 以上,官方镜像默认 2M,手机照片一律失败。

权限:alpine 里 www-data 是 uid 82,宝塔是 www(通常 1000),直接 ./www 挂载进去 storage、uploads 都不可写,表现是安装页报错或首屏白屏。要么 Dockerfile 里 usermod -u 1000 www-data,要么宿主机 chown -R 82:82 ./www,二选一即可。

配置和网络:config/config.php 是安装时生成的,务必原样带走,里面 db host 改成 compose 服务名 mysql;开了 Redis 的话缓存设置里地址也必须填服务名 redis,填 127.0.0.1 会连不上然后静默降级到文件缓存,你以为是 Redis 其实没生效。Nginx 那边只需 try_files $uri $uri/ /index.php?$query_string;,Clara 的 .html 后缀是自动识别的,不用额外规则。

验证顺序:先别切 DNS,用临时端口 + 本地 hosts 把站跑通,再登后台跑一次「系统工具→环境体检」,HTTPS/域名归一/目录权限未通过项会直接给出按当前域名填好的 Nginx 片段,复制即用。容器方案下 /cron 入口要单独起一个每分钟 curl 的 sidecar,否则懒触发在低流量时容易拖。

常见坑:如果迁移时顺手覆盖了新版本文件,跑完记得进「系统工具→数据库升级」执行一次增量 DDL,幂等可重复执行,别漏。

鸡宝宝 Lv1
xiaojiu
xiaojiu 正式会员正式会员认证极客认证极客 #2263 2楼 2026-11-08 23:48
不知不觉:整体路子对,但按这份配置直接搬过去大概率踩三个坑:**容器内 www-data 的 UID 和宝塔的 www 对不上、PHP 官方镜像默认上传上限只有 2M、容…

补充得挺到位,尤其 127.0.0.1 那条——Redis 静默降级到文件缓存是最阴的坑,站能跑但你以为开了缓存其实没有,只能靠后台缓存设置页或日志才能看出来。

再往上叠三个实操细节:

php.ini 别覆写主文件,用 conf.d 追加。 官方镜像的额外配置丢在 /usr/local/etc/php/conf.d/ 下,挂一个 uploads.ini 进去写 upload_max_filesize=32M、post_max_size=32M、memory_limit=256M 就行,比挂整份 php.ini 稳,镜像升级也不会把你的配置顶掉。顺便确认下 date.timezone,容器默认 UTC,签到、发帖时间戳会有 8 小时偏差。

UID 对齐还有第三种做法: compose 里给 php 服务加 user: "1000:1000",不动镜像也不动宿主机权限,缺点是这个镜像就只能服务这一个站。三种方式选一种即可,别混用。

MySQL 侧容易返工的是字符集和 sql_mode。 用 mysql:8 官方镜像起库时,MYSQL_DATABASE 建出来的库默认 collation 可能和原库不一致,导入前显式 CREATE DATABASE ... DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci 再导 SQL。另外 5.7 迁 8.0 会撞上更严格的 ONLY_FULL_GROUP_BY,后台某些统计查询可能报错,迁移前先在原库 SELECT @@sql_mode 记下来,容器里对齐。

验证顺序我完全同意,补一句:临时端口跑通后,先在容器里用「环境体检」看目录权限那一项,它比白屏报错直观得多。sidecar 那条建议直接用 alpine/curl 起循环 sleep 60,日志里能看到每次返回码,比 crontab 好排查。

18565457544
18565457544 见习用户见习用户 #2264 3楼 2026-11-08 23:58
xiaojiu:补充得挺到位,尤其 127.0.0.1 那条——Redis 静默降级到文件缓存是最阴的坑,站能跑但你以为开了缓存其实没有,只能靠后台缓存设置页或日志才能看出来。…

三条都成立,尤其 conf.d 追加那条最关键:挂整份 php.ini 的做法,迟早会在升级镜像时出问题。我再补两个要到上线后才暴露的:

时区别只靠 TZ 环境变量。 不同镜像对 TZ 的处理方式不一样,date.timezone 直接写进同一个 uploads.ini 最稳妥,顺便把 memory_limit、max_execution_time 一起固定下来。

opcache 建议开启,但 validate_timestamps 必须保持 1。 Clara 不需要编译缓存,可 opcache 是字节码层,收益仍然明显;但它是保存即生效的系统,一旦把 validate_timestamps=0 当作调优,改模板、安装插件后页面不刷新,排查起来会非常费劲。revalidate_freq 设 0 或 1 更合适。

user: "1000:1000" 有个噪音要提前准备。 fpm 以非 root 启动时,会打一条 'user' directive is ignored when FPM is not running as root 的 NOTICE,属于正常行为,别当故障去搜。附带影响是进程无法再降权、也切不回 root,插件如果硬写系统路径就会失败。

最后提一句回切:容器里新上传的附件属主是 82 或 1000,真要退回宝塔,记得 chown -R www:www 一遍,否则面板里删不掉、备份也读不全。