
简介这是一份面向Linux系统管理员、教育技术工作者及Moodle初学者的技术文献系统讲解在Red Hat Linux 9上搭建开源在线教学平台Moodle的完整流程针对低配硬件与开源组件组合给出可落地方案。文档从硬件配置、磁盘分区与软件版本选型入手明确Apache、MySQL、PHP等LAAMP环境组件的安装顺序并重点说明卸载系统自带低版本组件、编译安装依赖库、配置httpd与MySQL、创建数据库及部署Moodle等关键操作与排错思路。资源为1个PDF文件压缩包大小223KB便携易读适合作为安装部署时的参考手册。目前已有164人学习。通过阅读可以获得完整的平台搭建规划、软件包选用清单、分步配置方法及常见问题处理经验适用于学校低成本信息化建设或个人教师快速搭建在线教学空间具有较高的实践指导价值。1. 为什么在 RHEL 9 上搭 Moodle 比你想的更值得做作为一线运维我不会只看标题就推荐 RHEL 9 跑 Moodle 教学平台。实际上Moodle 对操作系统并不挑剔Ubuntu、Debian、openSUSE 都能跑但 RHEL 9 有一个其它发行版比不了的组合优势——稳定、安全、长期维护周期长。RHEL 9 的生命周期到 2032 年意味着一次搭建基础设施层面十年不用动Moodle 本身是学习管理系统LMS里开源方案绝对的老大学校、培训机构、企业内训都在用这两个强生命周期产品叠在一起适合那些不想每年折腾服务器的团队。选 RHEL 9 还有一层现实考虑SELinux 强制模式默认开启、php 8.1 和 MariaDB 10.5 都在官方源里、dnf 包管理器取代了老旧的 yum。这意味着你不需要添加额外第三方源就能把 LAMP 的骨架搭起来对安全合规要求高的政企和教育单位这比编译安装或拉第三方源要省心太多。当然RHEL 9 的“代价”是需要订阅授权开发订阅免费拿这一点和 Debian 系那种完全不要钱的模式有差异但换来的是红帽官方的安全公告和补丁源。这篇笔记会带你顺着标题提到的方向从环境准备、数据库、PHP 扩展到 Moodle 部署和权限加固走完整一遍把我在生产环境里踩过的坑提前标出来。适合谁看正在计划搭在线教学平台、又恰好拿到 RHEL 9 服务器资源的运维或者被领导点名“给学校搭个 Moodle”的一线工程师。2. RHEL 9 基础环境先对齐订阅、仓库和 LAMP 骨架2.1 注册订阅与仓库配置默认源就够用别画蛇添足拿到一台新的 RHEL 9 服务器第一步不是急着装软件而是确认注册状态。未注册的 RHEL 9 机器dnf install会直接报错因为默认仓库baseos、appstream需要授权才能访问。RHEL 9 对开发者提供免费订阅注册后能正常拉包。如果你之前没操作过在终端先执行subscription-manager register --username 你的红帽账号 --auto-attach subscription-manager status第一句注册并自动匹配可用订阅第二句确认状态为Subscribed。然后开启需要的仓库并升级现有包到最新dnf repolist dnf update -y逻辑很简单auto-attach是给机器分配一个可用授权repolist验证你已经能看到 baseos 和 appstream 这两个默认源。这里提醒一句RHEL 9 上的 PHP 和 MariaDB 是从 appstream 源里出的不要手痒去加 EPEL 或 REMI 源来升级 PHP 版本。Moodle 对 PHP 版本要求是有下界没有上界RHEL 9 自带的 PHP 8.1 完全满足 Moodle 4.x LTS 的要求。自定义编译更高版本 PHP 只会让后续维护变得被动每个安全补丁都要自己处理。豆知识RHEL 9 的 dnf 模块化流是dnf module list来查看的PHP 8.1 就是默认流。想看当前 PHP 流版本用dnf module list php确认不要盲目相信网上的第三方源教程。2.2 安装 Apache PHP MariaDB一条命令边界清晰确认订阅没问题后核心组件用一条命令装齐dnf install -y httpd php php-fpm php-mysqlnd php-curl php-zip php-gd php-xml php-mbstring php-intl php-soap php-opcache mariadb-server拆开看这些包各自干什么httpdApache 2.4 Web 服务器RHEL 9 默认跑的是 2.4.53足够支撑 Moodle 的 PHP 应用。php和php-fpmRHEL 9 上 Apache 默认通过 PHP-FPM 而不是 mod_php 来执行 PHP 脚本这个改动从 RHEL 8 开始就是默认路径。php-fpm 独立于 Apache 进程性能隔离更好。php-mysqlndPHP 连接 MariaDB 的驱动Moodle 必须有。php-curl/php-zip/php-gd/php-xml/php-mbstring/php-intl/php-soapMoodle 安装时的 PHP 扩展检查清单里都有名字。php-intl容易被漏漏了会导致 Moodle 安装页直接红字。php-opcachePHP 8.x 里 opcache 默认编译进去了这个包相当于管理入口Moodle 官方也要求 opcache 建议开启。mariadb-serverRHEL 9 里 MySQL 的替代品就是 MariaDB 10.5对 Moodle 来说完全兼容。安装完成后启动服务并设为开机自启systemctl enable --now httpd php-fpm mariadb--now参数表示立即启动并设置开机启动免去两次敲命令。之后用systemctl status httpd php-fpm mariadb抽查三者的运行态如果某个是 failed 状态多半是端口冲突比如 80 被占或 php-fpm 的 socket 权限问题这两个坑后面第 5 章重点说。2.3 SELinux 第一次会面没关它是好事也是麻烦老一批习惯用 CentOS 6 的运维拿到 RHEL 9 的第一反应很可能是setenforce 0然后改/etc/selinux/config把 SELinux 关掉。做 Moodle 部署我建议别关一是 RHEL 9 的安全体系里 SELinux 是核心防线二是 Moodle 只要目录上下文设定正确SELinux 根本不会拦你。平时流水线上会看到 httpd 写不了 Moodle 数据目录的报错十有八九是文件上下文没设对不是 SELinux 的锅。先把服务的 SELinux 布尔值打开后面挂 moodledata 目录时会再强调一遍setsebool -P httpd_can_network_connect_db on setsebool -P httpd_can_network_connect on第一条允许 Apache 进程通过网络访问数据库MariaDB 监听 3306 时必须要开第二条允许 PHP 脚本发起外连例如 Moodle 的插件在线更新。-P参数把改动持久化重启不丢。这两条不做后面要么数据库连不上要么 Moodle 装插件报超时茫茫然查不出原因。3. 数据库初始化与 PHP 参数搭一个 Moodle 满意的底座3.1 MariaDB 安全初始化清掉那些默认的空口令和测试库MySQL 系的数据库装完默认 root 用户是空密码、测试库匿名可访问这在生产环境里属于裸奔。MariaDB 10.5 提供了一个交互式命令来做基础加固跟着跑一遍就行mysql_secure_installation交互过程中会让你设置 root 密码、移除匿名用户、禁止 root 远程登录、删除 test 库。我一般全选 Yes但在设置密码时注意RHEL 9 上这个命令用的是 unix_socket 插件认证即系统 root 用户可以直接通过 socket 身份进 MariaDB。如果你后续习惯用mysql -u root -p登录可能会报错不用慌张这是插件的认证策略——用sudo mysql直接进或者在安装后把 root 切换成密码认证。我的习惯是保留 socket 认证管理端都走 sudo mysql。初始化后创建一个独立账号给 Moodle 用不要拿 root 去跑应用CREATE DATABASE moodle DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE USER moodleuserlocalhost IDENTIFIED BY 一个强度足够的密码; GRANT ALL PRIVILEGES ON moodle.* TO moodleuserlocalhost; FLUSH PRIVILEGES; EXIT;utf8mb4不是可选项。Moodle 4.x 内部大量用 emoji 和四字节字符用老的 utf8 在写入某些特殊符号时会报Incorrect string value错误卡得你怀疑人生。utf8mb4_unicode_ci作为排序规则对英文和中文的排序都算友好。localhost限定只允许从本机连接Moodle 和数据库同机部署时这是最安全的选择也能避开后面 SELinux 的网络连接难题。3.2 PHP 8.1 关键参数内存、上传、时区和 opcacheMoodle 是 PHP 应用里比较吃内存的角色默认的memory_limit 128M在安装主题、跑一些插件时往往会碰壁。PHP-FPM 的配置文件在/etc/php-fpm.d/www.conf和/etc/php.ini我要改的参数集中在后者; /etc/php.ini 关键调优按需修改 memory_limit 256M max_execution_time 180 max_input_time 180 post_max_size 100M upload_max_filesize 100M date.timezone Asia/Shanghai realpath_cache_size 4096K解释一下这些参数memory_limit给 PHP 脚本执行最大内存Moodle 首次安装、生成课程备份文件时都是吃内存大户256M 是起点站点用户多了以后再往上加max_execution_time防止安装插件时卡死导致脚本被杀post_max_size和upload_max_filesize决定单文件上传上限网课视频如果用文件方式直接传1G 视频也传不动100M 起步、做成播放列表更稳当date.timezone必须设置否则 Moodle 安装页会提示 timezone 未设置安装直接中断。改完验证语法并重载php -v systemctl restart php-fpm3.3 php-fpm 与 Apache 的协同socket 还是 TCPRHEL 9 默认 Apache 通过/etc/httpd/conf.d/php-fpm.conf里配置的 FastCGI 代理把 PHP 请求转发给 php-fpm监听地址默认是 unix socket 而非 TCP 端口。这个默认值对单机部署是最优的比 TCP 少一层网络栈开销。不过你需要注意 php-fpm 的运行用户和 Apache 是否一致Moodle 的文件写入依赖统一属主# /etc/httpd/conf.d/php-fpm.conf 中核心指令 FilesMatch \.php$ SetHandler proxy:unix:/run/php-fpm/www.sock|fcgi://localhost /FilesMatch这套机制的坑点在于 php-fpm 的 worker 进程默认以apache用户跑www.conf 里的user apache而服务器上如果存在多个应用目录属主不一致就会出现某个应用能读不能写的怪问题。Moodle 的场景下保持一致最简单web 文件和 moodledata 目录的属主都设成apache:apache这不影响实现上的安全隔离因为 SELinux 依然在框架层把关。修改 www.conf 里的关键行; /etc/php-fpm.d/www.conf user apache group apache listen /run/php-fpm/www.sock listen.owner apache listen.group apache listen.mode 0660listen.mode 0660目的是让 Apache 用户和组有权限访问 socket否则 httpd 会报connect() to unix:/run/php-fpm/www.sock failed。这个错初学者碰到的概率非常高第 5 章再对一次号。4. 部署 Moodle 核心文件下载、目录拆分、权限边界和安装向导4.1 获取发布包用 git 还是用压缩包Moodle 的发布渠道有两个主流做法从 moodle.org 官网下载最新 LTS 压缩包或者git clone官方仓库再切到稳定分支。我一般选前者理由很简单生产环境部署不需要 git 历史压缩包更干净、少一份被入侵时留下的.git目录。Moodle 4.x 最新的 LTS 分支版本从官网拿就行。cd /var/www/html wget https://download.moodle.org/download.php/direct/stable404/moodle-latest-404.tgz tar zxvf moodle-latest-404.tgzwget的下载地址是官方 CDN 重定向如果服务器海外带宽一般下载速度慢可以本地下好再 scp 上去。解压后的目录结构是/var/www/html/moodle之后所有 Moodle 程序代码都放在这个路径下。千万别手一滑把解压出来的文件直接铺到/var/www/html根目录没法儿升级/var/www/html应当是文档根而不是应用目录。4.2 moodledata 目录离开 web 根目录这是铁律Moodle 运行时的数据上传的课程文件、会话缓存、临时文件、缓存全部存放在moodledata目录里它必须不能放在 Web 可访问的范围内。这个不是洁癖不洁癖的问题而是安全问题课程包和用户头像如果可以直接通过 URL 访问等于把私密资源挂在公网上。我统一的落法是和 web 目录并列放mkdir /var/moodledata chown -R apache:apache /var/moodledata chmod 700 /var/moodledata属主设置为apache是因为 PHP-FPM 的进程身份是 apache目录权限 700 代表只有 apache 用户自己可以进。集成到 SELinux 时要给这个目录打上 httpd 能写的上下文semanage fcontext -a -t httpd_sys_rw_content_t /var/moodledata(/.*)? restorecon -Rv /var/moodledatasemanage fcontext添加一条持久化规则restorecon把当前目录的实际标签刷成规则指定值。如果不打这个标签SELinux 会拦截 PHP 写入 moodledata 目录报的错通常是Permission denied但文件权限怎么改都对原因就在上下文。这种“文件权限全是 777 却依然写不进去”的现象是 SELinux 环境下区分老手和新手的分水岭。4.3 config.php 与安装向导配置文件里的三个易错项浏览器访问http://服务器IP/moodle会进入安装向导它在写数据库前会让你配置config.php。实践上我手动把配置文件先写好再跑安装避免用安装器生成时那些隐蔽选项被默认带偏。步骤是先让安装器生成一个初始文件再改还是直接自己写各有偏好。我推荐先跑向导到第二步它会在/var/www/html/moodle下生成config.php雏形然后我们把关键项改掉再继续。但为了少等一圈可以直接用下面这份模板?php // /var/www/html/moodle/config.php unset($CFG); global $CFG; $CFG-dbtype mariadb; $CFG-dblibrary native; $CFG-dbhost localhost; $CFG-dbname moodle; $CFG-dbuser moodleuser; $CFG-dbpass 你设置的数据库密码; $CFG-prefix mdl_; $CFG-dboptions array( dbport 3306, dbschema , dbcollation utf8mb4_unicode_ci, ); $CFG-wwwroot http://你的域名或IP/moodle; $CFG-dataroot /var/moodledata; $CFG-admin admin; $CFG-directorypermissions 02777; require_once(__DIR__ . /lib/setup.php);需要解释的参数dbhost建议填localhost它会自动走 socket 连接比 TCP 的127.0.0.1少一层鉴权和网络开销prefix用默认的mdl_就很好改它能实现一库多应用但维护复杂不建议wwwroot是安装向导里容易埋雷的地方填了 IP 后来换域名会导致页面资源全部加载失败这个是 Moodle 的重定向/静态资源路径依赖跳转不对整个站点就白屏了directorypermissions02777 让 Moodle 自己创建的目录自动带上写权限也是配置向导帮你写好的默认值。dbcollation选utf8mb4_unicode_ci是必须的和建库的排序规则保持一致避免表已经按 utf8 建好、后来要改库的编码造成大量表的 ALTER 操作那才叫灾难。4.4 静默安装命令行安装的好处Moodle 安装向导走浏览器不是唯一路径。生产环境里我更建议直接用 CLI 安装脚本因为你在服务器上能清楚看到每一步错在哪sudo -u apache /usr/bin/php /var/www/html/moodle/admin/cli/install.php \ --wwwroothttp://你的域名/moodle \ --dataroot/var/moodledata \ --dbtypemariadb \ --dbhostlocalhost \ --dbnamemoodle \ --dbusermoodleuser \ --dbpass你的数据库密码 \ --fullname在线教学平台 \ --shortnamemoodle \ --adminuseradmin \ --adminpass初始管理员密码 \ --adminemailadminexample.com \ --agree-license这条命令的作用是绕过 Web 安装向导效果完全一致。sudo -u apache保证 PHP 进程以 web 服务同样的身份执行避免安装出来的文件属主错乱。--agree-license表示接受 GPL 许可协议跳过交互确认。看到脚本输出Success之后访问http://你的域名/moodle就能用 admin 账号登录后台了。CLI 安装的另一层价值是脚本化堡垒机记录、批量部署、无人值守环境都好用。Web 安装向导适合第一次玩、想把每个选项都看清的场景但这套笔记面向的是落地我推荐 CLI 路线走完初始化。4.5 注册 Cron 任务Moodle 的心跳必须每时每刻Moodle 的后台任务课程备份、消息队列、计划任务都是靠 Cron 轮询机制触发的。没有 Cron用户提交的作业不会自动完成评价、备份不会跑、订阅通知不会发。RHEL 9 默认用 systemd timer 或 crontab 都可以我推荐 crontab一行配置cat /etc/cron.d/moodle EOF */1 * * * * apache /usr/bin/php /var/www/html/moodle/admin/cli/cron.php /dev/null 21 EOF每分钟跑一次。Moodle 的 cron 是按需分发轻重任务的一分钟粒度不会给服务器造成压力但能保证实时性。 /dev/null 21丢弃标准输出和错误输出避免 cron 每跑一次就发一封本地邮件。如果你要排查 cron 是否触发把这段从 crontab 里临时去掉输出重定向观察第一次手工执行时的报错。注意apache用户cron 任务以 apache 身份执行是为了和 PHP-FPM 的写权限一致。如果以 root 身份跑了 cron生成的缓存文件会是 root 属主Web 端就报Permission denied。这也是一个极其容易踩的权限隐患。5. 部署期总翻车SELinux、目录权限和 PHP 版本的三处排错笔记5.1 现象一安装向导第二页直接白屏或 500 错误现象浏览器访问/moodle时首页静态资源正常进入安装步骤后 Apache 返回 500或页面空无一物。原因多数时候是 PHP 扩展缺少导致lib/setup.php里某段代码 fatal error。Moodle 安装前会做环境预检如果扩展少得太多向导有红字提示但像php-intl缺失引发的是 fatal error连预检都到不了。我见过装了 RHEL 9 默认 php 后没额外装php-intl、php-soap看日志/var/log/httpd/error_log才定位到Call to undefined function locale_get_default()。解决dnf install -y php-intl php-soap php-opcache php-mbstring php-xml systemctl restart php-fpm装完重跑向导如果仍然 500去/var/log/php-fpm/www-error.log查详情的 PHP fatal error。注意 RHEL 9 的 php-fpm 错误日志默认写到这个路径而不是 Apache 日志里。5.2 现象二一切权限看起来都对但 moodledata 不让写现象ls -ld /var/moodledata确认属主是 apache、权限是 770 或 777PHP-FPM 也以 apache 身份运行但安装脚本持续报“Cannot create directory /var/moodledata/xxx”。原因SELinux 的文件上下文没有打标。SELinux 不看 UNIX 权限位只看httpd_sys_rw_content_t这个安全标签。你用的是mkdir /var/moodledata新建的目录默认标签是default_thttpd 被禁止写入。解决semanage fcontext -a -t httpd_sys_rw_content_t /var/moodledata(/.*)? restorecon -Rv /var/moodledata然后验证标签打上了ls -Z /var/moodledata出现httpd_sys_rw_content_t即正常。这里如果semanage命令不存在说明缺少policycoreutils-python-utils包用dnf install -y policycoreutils-python-utils补上就行。5.3 现象三PHP 版本对不上 Moodle 的检查清单现象安装或升级时后台红字“PHP version 8.0.30 is not supported. Please upgrade to 8.1 or later”。原因RHEL 9 的 appstream 默认把 PHP 8.1 定义为默认流但如果你在系统里额外启用了 module 流比如先装了 8.0 的第三方源或者把 php 模块切到了 8.0就会弹这个警告。解决dnf module list php dnf module reset php dnf module switch-to php:8.1 -y dnf update php* -y systemctl restart php-fpm httpdmodule reset清掉当前模块流的软链接状态switch-to php:8.1让 dnf 把 PHP 系列迁移到 RHEL 官方默认的 8.1 流上。升级完跑php -v和/var/www/html/moodle/admin/cli/check.php双重确认状态。5.4 现象四php-fpm 的 socket 文件找不到Apache 报 503现象启动 httpd 成功但访问 PHP 页面返回 503 Service Unavailablehttpd error_log里写connect() to unix:/run/php-fpm/www.sock failed。原因php-fpm 服务没有启动或者www.conf里监听路径和 Apache 配置里的SetHandler proxy:unix:/run/php-fpm/www.sock对不上。RHEL 9 上如果 PHP-FPM 挂了Apache 不会自动拉起它因为 systemd 单元互相独立。解决systemctl status php-fpm systemctl restart php-fpm ls -l /run/php-fpm/www.sock如果 socket 文件不存在重点检查www.conf里的listen项是否被注释或改了名字。还有一种是/run/php-fpm目录不存在用mkdir -p /run/php-fpm补上并设属主 apache 即可。另外也注意php-fpm的listen.acl_users配置项RHEL 9 默认不是用 ACL 而是用 owner/group 控制权限所以出现权限报错时优先确认listen.mode是 0660 而不是 0666。5.5 现象五上传课程文件时提示超过 post_max_size现象课程讲师上传压缩包文件 150M页面进度条走完提示“文件大小超过限制”。原因Apache 转发到 PHP-FPM 时PHP 侧post_max_size或upload_max_filesize比实际文件小POST 数据在到达 PHP 前就会被拦截。解决改/etc/php.ini里对应两个参数同时确认/etc/httpd/conf.d/php-fpm.conf里没有单独的LimitRequestBody限制这个默认是 0表示不限制但一旦有人配过也会劫持大文件上传。改完systemctl restart php-fpm在 Moodle 后台的“服务器 → PHP 信息”页面刷新查看当前生效值确认不是被php_admin_value覆盖。6. 进阶反向代理终结 PHP 瓶颈用 opcache 和缓存把 Moodle 顶到不卡6.1 Nginx 做前端加速Apache 退到后端跑 PHPRHEL 9 上默认的 Apache 承担静态文件和 PHP 代理没有问题但生产环境流量上来后我习惯在 Apache 前面放一层 Nginx 做静态缓存和 TLS 终结。Nginx 对静态资源的并发处理能力比 Apache 强而且 RHEL 9 官方源里直接有nginx包不需要第三方源dnf install -y nginx systemctl enable --now nginxNginx 配置里需要把 PHP 请求反向代理到 Apache 的 8080 端口而不是直接连 php-fpm。Apache 的 8080 端口监听通过修改/etc/httpd/conf/httpd.conf实现把Listen 80改成Listen 127.0.0.1:8080这样 Apache 只服务本机回环流量外网请求全部由 Nginx 承接# /etc/nginx/conf.d/moodle.conf server { listen 80; server_name 你的域名或IP; root /var/www/html/moodle; index index.php index.html; location / { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } client_max_body_size 100M; }这段配置做了两处关键动作proxy_pass指到后端 Apache 的 8080 端口让 Apache 继续处理 PHP-FPM 的转发逻辑client_max_body_size 100M和 PHP 侧的上传限制对齐避免 Nginx 先于 PHP 拦截大文件。这个拓扑结构的好处是以后想挂 TLS 证书、加 CDN、做静态资源缓存改 Nginx 层就行Moodle 本身不动。6.2 OPcache 参数调优把 PHP 解释开销压下来PHP 8.1 默认开了 opcache但默认参数在生产上偏保守。RHEL 9 的opcache.ini配置在/etc/php.d/opcache.ini核心调优opcache.enable 1 opcache.memory_consumption 128 opcache.interned_strings_buffer 16 opcache.max_accelerated_files 10000 opcache.revalidate_freq 60 opcache.validate_timestamps 1 opcache.enable_cli 1几个参数的作用memory_consumption分配 128M 给 opcache 存编译后的字节码Moodle 这种体量的应用 128M 够用max_accelerated_files10000 是因为 Moodle 核心 插件合起来 PHP 文件数量动不动就大几千个默认 4000 会导致部分文件反复编译revalidate_freq 60每 60 秒检查一次源码变更部署新代码时最多延迟 60 秒生效比关掉校验导致缓存过期不清更稳妥。validate_timestamps 1开启源码修改检测这样升级 Moodle 后重启 php-fpm 之外不用手动清理缓存目录。6.3 验证手段用压测和缓存命中率说话搭完配置心里要有底不能光“感觉变快了”。我的验证手法定成三步第一步确认 PHP 响应时间curl -o /dev/null -s -w TCP:%{time_connect}, 首字节:%{time_starttransfer}, 总耗时:%{time_total}\n http://127.0.0.1/moodle/login/index.php这个命令看的是从发起请求到收到第一个字节的耗时。正常在几十到几百毫秒之间如果超过 2 秒问题大概率在数据库查询或 PHP-FPM 队列等待上而不是网络。第二步压测静态资源与 PHP 动态页的并发差异。用 abApacheBenchhttpd-tools包自带打 100 并发ab -n 1000 -c 100 http://127.0.0.1/moodle/动态页面请求失败率超过 1% 就要往回查 PHP-FPM 的子进程数和超时时间。RHEL 9 默认pm.max_children偏保守可以用pm dynamic、pm.max_children 30起步观察内存占用再调pm.max_requests 500限制单进程处理次数防内存碎片。第三步检查 opcache 命中率。装一个php-opcache配套的管理页不方便直接访问时用命令行确认php -i | grep opcache.hit_rate命中率低于 95% 意味着代码反复编译把memory_consumption加大或检查是不是有插件生成了大量临时 PHP 文件。6.4 备份习惯数据库和 moodledata 分开做恢复才有后悔药讲完性能补最后一个我个人的习惯操作备份。Moodle 的数据分两块数据库和 moodledata 文件目录两者需要同时备份光备份数据库丢了上传的课程文件光备份文件丢了用户记录恢复都是一塌糊涂。落地是写一条 cron 脚本cat /usr/local/bin/moodle-backup.sh EOF #!/bin/bash BACKUP_DIR/var/backups/moodle mkdir -p $BACKUP_DIR mysqldump -u root moodle $BACKUP_DIR/moodle-db-$(date %F).sql tar czf $BACKUP_DIR/moodledata-$(date %F).tar.gz -C /var moodledata find $BACKUP_DIR -mtime 15 -delete EOF chmod x /usr/local/bin/moodle-backup.sh echo 0 2 * * * root /usr/local/bin/moodle-backup.sh /etc/crontabmtime 15 -delete这条是把 15 天前的旧备份清掉防止磁盘被撑爆。mysqldump 备份数据库时如果站点正在跑可能造成短暂锁表负载低的时候没问题。这套习惯我保留了很多年言止于此——希望帮到你。本文还有配套的精品资源点击获取