Moodle生产环境部署全链路:从空白机器到公网稳定运行
1. 先想清楚再动手:Moodle 生产环境部署的整体设计
Moodle 生产环境部署这件事,网上的教程大多停在"能装起来"这一层,装完之后页面能打开,作者就收工了。但你真把它放到教学场景里跑,几百号人同时点开一门课的测验,或者期末集中提交作业,问题就全冒出来了:白屏、502、上传卡死、登录跳转死循环、定时任务报警。我从十年前第一次在实验室的旧工作站上装 Moodle,到后来给几个教学团队搭过从几十人到几千人规模的实例,踩过的坑足够写一本小册子。这篇东西不讲"什么是 LMS"这种教科书内容,只讲一件事:Moodle 生产环境部署从一台空白机器到公网能正常访问、能扛住真实流量,中间的每一个决策怎么做、为什么这么做。
先把定位说清楚。Moodle 是开源学习管理系统,一套 PHP 写的 Web 应用,配上数据库和文件存储,就能对外提供课程、作业、测验、成绩、讨论区这些教学功能。这套部署流程适合谁?适合单位内部想把教学资源收拢到自己手里的信息化人员,适合需要做二次开发所以必须掌握完整部署链路的开发者,也适合个人想搭一个长期可用的学习站点、不想受第三方平台功能限制的实践者。如果你只是想试玩两天,官方有现成的托管方案,不必折腾。但凡你打算长期跑、数据要自己攥着、可能要接校内账号体系或者定制插件,那这篇文章的每一步你都绕不开。
整篇内容我按真实施工顺序组织:先定方案和规格,再铺系统底座,然后装主体,接着打通公网访问,最后做性能与运维调优,末尾给一份故障速查表。中间会穿插大量"为什么这么选"的解释和参数计算过程,你能直接照着抄,也能理解背后的道理从而自己改。
1.1 版本选型:为什么我不建议新手追最新版
Moodle 的版本节奏是每年两个大版本,其中带有长期维护标记的版本维护周期通常是普通版本的两倍以上。这个区别在演示环境毫无意义,在生产环境就是生死线:普通版本发布后大约一年就不再收安全补丁,你的站点要么被迫频繁升级,要么带着已知漏洞在公网上裸奔。所以我给自己的规矩是,生产环境只上长期维护版本,普通版本留给测试环境做前瞻验证。
PHP 版本同样不能随手挑。Moodle 从 4.x 开始对 PHP 的最低要求一路抬升,早期 4.x 要 PHP 8.0,后续版本要求 8.1、8.2 甚至 8.3。选 PHP 的原则是"踩在官方支持区间中段"——最老的版本虽然能跑,但缺新特性、性能也差一截;最新版本虽然写在支持列表里,但生态里的第三方扩展和插件未必跟得上,遇到报错你连搜都搜不到。实践下来,把 PHP 定在官方支持的中间那个小版本最舒服。
数据库这边,MySQL 8.0 和 MariaDB 10.6 以上都是常见选择。我个人的偏好是 MariaDB,原因很朴素:同样的硬件配置下它的内存占用略低一点,配置文件的写法也更宽容,对小规模站点更友好。但如果你的运维团队已经有成熟的 MySQL 监控体系,那就别为了这点差异折腾,统一到 MySQL 8.0 更好维护。存储引擎必须是 InnoDB,字符集必须 utf8mb4,这一点没有商量余地——Moodle 要存中文、日文、各种表情符号,utf8 三字节字符集会在某些输入上直接截断报错。
注意:安装前务必确认版本组合在官方文档的支持矩阵里。我见过有人用不匹配的 PHP 小版本硬装,装完了跑得挺好,一次小版本升级之后整站挂掉,回滚发现是某个扩展的行为变了。版本矩阵不是建议,是护栏。
1.2 硬件规格与并发估算:别拍脑袋买机器
"Moodle 要多大配置"这个问题被问了一万遍。我的回答永远是:先算,再买。算法的骨架是这样的——Moodle 的负载大头在 PHP 进程,每个 PHP-FPM 工作进程在处理一个请求时会占用一定的常驻内存,经验值是 60 到 90 MB,取决于装载的插件数量和 PHP 版本。你预估的并发请求数,乘以单进程内存,就是这个站点需要的 PHP 侧内存下限。
举个具体的:一个 500 人规模的班级,高峰时段大约三成的人同时在线,也就是 150 人。一个人浏览课程页面时,浏览器会并发发起好几个请求(页面、图片、样式、Ajax),但绝大多数请求几十毫秒就结束了,真正同时被 PHP 处理的平均只有个位数,突发时可能到二三十。按 30 个并发进程算,每进程 80 MB,PHP 侧要 2.4 GB。再加上系统本身、数据库缓冲池、Redis,一台 4 核 8G 的机器足够起步。反过来,如果你面对的是 3000 人同时参加在线考试,那并发进程数要按两三百算,这时候单机就危险了,得上负载均衡加独立数据库。
磁盘是最容易被忽视的一项。系统盘 40 GB 只是起步,Moodle 的数据目录会随着课程资料、学生提交的作业附件、录屏文件快速膨胀。我的经验公式是:预估的用户数 × 每人每年 500 MB 到 1 GB,再留一倍冗余。存储类型上,系统盘和数据库用 SSD 是硬性要求,机械盘跑 InnoDB 会让每一次写操作都变成慢查询。
| 规模档位 | 在线人数峰值 | 推荐配置 | PHP-FPM 进程数 | 备注 |
|---|---|---|---|---|
| 试用 / 小组 | 20 以内 | 2 核 4G | 15 | 单机全包 |
| 院系级 | 100 到 300 | 4 核 8G | 40 到 60 | 单机全包 + Redis |
| 全校级 | 1000 以上 | 8 核 16G 起 | 100 以上 | 建议应用与数据库分离 |
| 考试高峰 | 瞬时 2000+ | 多台应用节点 | 按压测定 | 必须做压测再定 |
1.3 目录规划:一次做对,后面省一年运维
我把这套目录结构当模板用了很多年,强烈建议你也照这个来:代码放/var/www/moodle,数据目录放/var/moodledata,两者绝对不能是同一个父目录下的兄弟关系,更不能把数据目录放到 Web 根目录里面。这不是洁癖,是安全底线。Moodle 的数据目录里存的是学生上传的作业、课程备份文件、缓存文件,一旦这个目录能被 Web 直接访问,等于把所有学生的提交公开挂在网上。
数据目录还必须是独立的一块盘或者独立分区,原因有两个:一是备份策略不同,代码可以重装,数据不能丢;二是容量增长不可控,独立分区能防止某个学生上传一个超大附件把系统盘撑爆导致整机宕机。我见过一次事故,某人把数据目录放在系统盘,一门课的教师批量导入了几十个高清课件,磁盘满,MySQL 直接拒绝写入,整站 502 了两小时。
Web 服务运行用户统一用www-data(Debian 系)或nginx(RHEL 系),代码目录归属这个用户,权限 755 目录 / 644 文件;数据目录同样归属这个用户,但权限要 770 甚至更高,确保只有运行用户能读写。这套划分定下来,后面所有权限相关的坑基本上就规避掉了。
2. 系统底座:把地基打得能扛住三年
很多人把系统初始化当成走过场,装完系统就直奔安装包。但生产环境的稳定性,八成来自这半小时的准备工作。这一节讲的东西看起来枯燥,但每一条都是从事故现场总结出来的。
2.1 系统初始化与安全基线
第一件事是更新系统并锁定软件源。刚开的机器自带的软件包版本往往落后好几个月,直接装 PHP 和数据库会埋下隐患。更新完做一次重启,确保内核也同步到位,然后立刻设置时区、同步时间。时间这事听着无关紧要,实际上 Moodle 的定时任务、作业截止时间、测验计时、日志排序全都依赖系统时间,时间漂移几分钟就可能导致学生明明按时提交却被判超时,这类投诉最难解释。
第二件事是创建专用运行账户和交换分区。云主机默认常常没有 swap,内存一旦被缓存撑满,内核直接触发 OOM 杀掉 PHP-FPM 主进程,表现就是整站突然 502。加一块等于物理内存一半的 swap,能在突发流量时提供缓冲,虽然慢但不会死。同时把系统的文件描述符上限调高,Moodle 在高峰期会打开大量连接,默认的 1024 很容易不够。
第三件事是防火墙。原则是默认拒绝,按需放行:对外只开 80 和 443,SSH 端口改成非默认并限制来源,数据库端口、Redis 端口、PHP-FPM 端口一律只监听本机回环地址。这一条我强调得比较多,因为见过太多实例把 3306 直接暴露在公网,靠一个弱密码撑着。数据库配置里把bind-address设成127.0.0.1,Redis 配置里设bind 127.0.0.1并加密码,两个动作加起来不到两分钟,能挡掉绝大多数自动化扫描。
提示:装完系统后先做一次快照。这不是偷懒,是给自己留退路。后面任何一步搞崩了,回滚快照比逐条排查快得多,尤其是在你不熟悉的发行版上。
2.2 PHP 与扩展的搭配:少一个扩展就是一次白屏
Moodle 对 PHP 扩展的依赖清单比较长,安装时如果漏装,表现往往不是明确的报错,而是安装向导跑到某一步突然白屏,或者后台某个功能点进去 500。核心必装的是这几类:数据库驱动(mysqli 或 pdo_mysql)、图像处理(gd)、国际化(intl)、多字节字符串(mbstring)、XML 处理(xml、xmlrpc、dom、simplexml)、网络请求(curl)、压缩(zip)、加密(openssl、sodium)、以及 SOAP 和 bcmath。如果要接单位账号体系,还得加 ldap。
装完扩展,php.ini的调优才是重点。有几个参数不改,后面一定会出问题:
max_input_vars:默认 1000,Moodle 的课程设置表单字段动辄上千,不改会导致保存时静默丢字段,你点了保存,回头一看设置没生效,查半天以为是权限问题。memory_limit:给到 512M。备份课程、生成报表、导入题库这些操作都很吃内存。upload_max_filesize与post_max_size:按你的业务定,教学场景建议 200M 起。这两个必须和 Nginx 的client_max_body_size完全一致,三处任意一处偏小都会导致大文件上传失败,而且报错信息通常含糊得让人抓狂。max_execution_time:300 秒。课程备份、批量导入这类长任务需要时间。- OPcache:必须开,
memory_consumption给 128M,max_accelerated_files给到 10000 以上。Moodle 的文件数量很多,默认的 2000 会让缓存频繁失效,性能收益大打折扣。
还有一个容易被忽略的:date.timezone要在 php.ini 里显式设成你所在时区,而不是靠代码里写。PHP 在没有设置时会给出警告,某些版本下甚至影响日期计算的正确性。
2.3 Nginx 与 PHP-FPM 的通信配置
Web 服务器我选 Nginx,理由是它在处理静态资源和大量并发连接时资源占用更低,而 Moodle 的页面里有大量 CSS、JS、图片。配置思路上有三块必须做对。
第一块是 URL 重写。Moodle 的很多功能路径是"看起来像目录"的形式,比如后台管理路径,如果没有正确的重写规则,访问这些地址会 404,而首页却正常,这种"一半正常一半报错"的现象最迷惑人。核心规则是让所有不存在的路径都落到index.php上并保留查询串,同时把带路径信息的 PHP 请求正确拆分。整套规则照官方模板改是最稳妥的,别自己发明。
第二块是 PHP-FPM 的进程池。进程池的pm模式选dynamic,然后按前面算出的进程数设定max_children,start_servers给最大值的四分之一,min_spare_servers给八分之一,max_spare_servers给三分之一。pm.max_requests设 500,让进程定期回收,防止内存泄漏累积。request_terminate_timeout设成比 PHP 的max_execution_time稍大,避免长任务被 FPM 提前杀掉。
第三块是缓冲与超时。Nginx 到 FPM 的fastcgi_read_timeout要给到 300 秒以上,否则页面渲染慢一点就直接 504。fastcgi_buffers适当调大,能减少磁盘临时文件的写入。静态资源单独加一段 location,设置长缓存时间并开启 gzip,这一条对首屏速度的提升非常明显,尤其是课程页面上几十个图标和样式文件的情况。
配置写完后不要急着 reload,先用nginx -t检查语法,再 reload。我吃过一次亏,配置里少了个分号,reload 失败但旧进程还在跑,我以为生效了,调了半天发现改的东西根本没加载。
3. 数据库与主体安装:把 Moodle 真正落地
前面都是准备,这一节才是真正把 Moodle 装到机器上。安装过程本身不算复杂,但有几个决策点如果选错,后面改起来很麻烦。
3.1 数据库的字符集与参数调优
建库这一步,字符集和排序规则必须一次设对:字符集 utf8mb4,排序规则 utf8mb4_unicode_ci。为什么不用默认的?因为默认排序规则在不同版本里可能是 utf8mb4_0900_ai_ci,它对某些语言的排序行为和 Moodle 的预期不完全一致,而且一旦建库时选错,后面改要导出重建,几千张表的重建能让你通宵。
数据库用户要给足权限但只给这个库的权限,别图省事用 root。连接方式上,我建议用127.0.0.1而不是localhost。原因在于 PHP 的 mysqli 在遇到localhost时会尝试走 Unix socket,而 socket 路径在不同发行版和不同 PHP 版本下可能不一致,一旦对不上,报错信息是"无法连接数据库",但你在命令行用同样的账号密码却能连上,排查起来非常费神。写死127.0.0.1走 TCP,行为确定。
参数调优的核心就一个:innodb_buffer_pool_size。这是 InnoDB 的缓存池,设成物理内存的 50% 到 60%,能让绝大部分读操作走内存。一台 8G 的机器,如果数据库和应用同机,给 2G 到 3G 比较合适,剩下的留给 PHP 和系统。另外把max_allowed_packet提到 64M,课程备份恢复、大题库导入都会用到;innodb_flush_log_at_trx_commit保持默认的 1,除非你能接受崩溃时丢数据,生产环境不要动它。
3.2 代码落地与权限设置
下载安装包、解压到/var/www/moodle,然后把整个目录的属主改成 Web 运行用户。权限我一般设成目录 755、文件 644,数据目录 770。这里有个细节:Moodle 需要往代码目录里写东西吗?基本不需要,只有升级和装插件时会写。所以代码目录保持只读权限对安全性更好,升级时临时放开再收回。
然后是数据目录,把它建在独立分区上,属主设为运行用户,权限 770,并在挂载参数里加上noexec和nosuid。noexec这一条尤其值得加:万一有人通过某个上传漏洞把可执行文件塞进数据目录,noexec能直接废掉它的执行能力。这是一个成本极低、收益很高的加固动作。
注意:创建数据目录后,不要手动往里面塞任何东西。Moodle 首次安装时会自己初始化目录结构和缓存,你提前放文件反而可能干扰初始化。空目录交出去就行。
3.3 安装方式的选择与关键参数
Moodle 提供网页向导和命令行两种安装方式。网页向导适合第一次接触的人,能直观看到每一步在做什么;命令行方式适合可复现的部署,一条命令带参数跑完,不会漏项,也方便写进自动化脚本。我的做法是:先在测试环境用网页向导走一遍,弄清每一步到底在配什么,正式环境用命令行安装。
命令行安装的关键参数包括:站点地址(这个后面单独讲,是最容易出错的一项)、数据目录路径、数据库类型与连接信息、站点全称和简称、管理员账号密码,最后加非交互确认。站点简称要短,因为它会出现在页面标题和邮件里;站点全称可以长一点。管理员账号别用 admin 这种默认名,密码用强口令,安装完成后第一时间改掉。
安装过程跑完,还有两件事必须马上做:一是把运行账号的 crontab 配上,每分钟执行一次定时任务脚本;二是在后台把"计划任务"页面打开,确认没有红字警告。定时任务没跑起来的话,Moodle 的邮件发不出去、成绩不会更新、备份不会自动执行,而这些故障在页面上往往没有明显提示,等你发现时已经积压了一堆任务。
3.4 安装后立刻要做的五件事
第一,改管理员密码并开启二次验证。第二,进后台把"调试信息"关掉,安装时如果开过就把开关收回。第三,配置邮件发送方式,Moodle 的默认发信方式依赖本机邮件服务,大多数云主机没有配置,结果就是注册验证邮件、密码重置邮件全部石沉大海。用 SMTP 方式填好服务器、端口、账号、加密方式,然后点测试发一封。第四,设置站点时区和默认语言,装上简体中文语言包。第五,把自动备份关掉或者调成低频率,很多人的磁盘被自动备份吃满就是这么来的。
4. 打通往公网的路:域名、证书与地址一致性
到这一步,机器上已经跑起来一个能通过内网 IP 访问的 Moodle。但"可外网访问"这件事,坑比前面所有环节加起来还多。
4.1 域名解析与端口放行的检查顺序
顺序很重要:先确认解析生效,再确认端口通,最后才改配置。解析这块没什么技巧,加一条 A 记录指向服务器公网 IP,然后用dig或nslookup反复查,确认返回的就是你期望的地址。有时候本地缓存没刷新,你查到的还是旧记录,会误判成"解析没生效"。多渠道验证一下比较快。
端口这块,公网访问失败十次里有六次是防火墙。要在云平台的安全组里放行 80 和 443,同时主机自身的防火墙也要放行。两层都放行才通。验证方式是换个网络环境(比如用手机流量)访问一下,能通再继续。这里有个小技巧:先在 Nginx 里配一个最简单的静态页测试,通了再上 Moodle 配置,这样出问题能立刻判断是网络层还是应用层。
4.2 证书申请与 HTTPS 配置要点
生产环境必须上 HTTPS,不只是因为浏览器会标"不安全",更因为 Moodle 的登录、测验答题都涉及凭据和答题数据。证书现在获取成本很低,用自动化的证书工具配好,设置成到期前自动续期即可。
配置上有几个点要注意。一是强制跳转:所有 HTTP 请求 301 到 HTTPS,别留混合访问的口子。二是 TLS 版本只留 1.2 和 1.3,关掉老的协议版本。三是证书链要完整,有些工具生成的证书文件只含站点证书不含中间证书,浏览器在某些环境下会报证书错误,用fullchain文件就没问题。四是续期后要能自动 reload,否则证书过期了站点还在用旧的,用户看到的就是一片红。
4.3 站点地址一致性:一个字符都不能错
这是整个部署过程里最经典的坑,必须单独拿出来说。Moodle 把站点根地址写在配置里,页面上生成的所有链接、表单提交地址、静态资源地址、跳转目标,全都基于这个值。它必须和用户在浏览器地址栏里输入的完全一致:协议一致(https 就是 https)、域名一致(带不带 www 是两个域名)、端口一致、路径一致(装在子目录就带子目录)。
不一致会发生什么?轻则样式和脚本加载不出来,页面素得像上个世纪的网页;重则登录后跳转死循环,你输入账号密码点登录,转一圈又回到登录页;再重则表单提交被判为跨站请求全部失败,学生点提交作业后毫无反应。这几种现象都极难从错误提示里看出来,因为提示本身是误导性的。
判断方法很简单:打开浏览器开发者工具看控制台,如果有大量资源加载失败、报的是错误的域名或协议,那就是这个问题。修法也简单,改配置里的地址,然后清一次缓存。但注意,改完地址后如果站点有缓存层,要一并清掉,否则旧的地址还会从缓存里被吐出来。
提示:装了前置网关或负载均衡的架构下,还有额外一层坑——应用看到的是内网地址、请求头里带的是 HTTPS,如果不告诉应用"你是被外部 HTTPS 访问的",它仍然认为自己跑在 HTTP 上,于是继续生成 HTTP 链接,于是继续死循环。配置文件里有两个开关专门处理这种情况,去官方文档的配置章节找,按说明打开即可。
5. 上线前的性能与运维调优
站点能访问了,但这只是"能用"。要让它"长期好用",还得再花半天做几件事。
5.1 定时任务与后台队列
定时任务的频率是每分钟一次,用运行用户的 crontab 添加,别用 root。用 root 跑会创建一堆所有者错误的缓存文件,后续升级和清理都会报权限错。脚本执行的输出重定向到日志文件,方便出问题时回看。
除了定时任务本身,还要关注"临时任务"队列。Moodle 里很多耗时操作不会即时执行,而是丢进队列等定时任务来处理,比如批量发通知、生成报表、处理大文件。如果队列积压,用户会觉得"操作成功了但没反应"。后台有一个队列状态页面,能看到积压数量和最老任务的等待时间,正常情况下这个数字应该很小,持续增长说明定时任务没跑够频繁或者有任务卡死。
5.2 缓存配置:把性能提升一个档
Moodle 有一套缓存体系,默认用数据库和文件做存储,性能一般。生产环境建议接 Redis,做三件事:做缓存存储、做会话存储、做锁机制。会话放 Redis 之后,多台应用节点共享会话成为可能,也避免了文件会话在高并发下的锁竞争。
配置方法是往配置文件里加几行,声明缓存存储的地址和端口,然后在后台的缓存管理页面把各个缓存映射到新存储上,最后清缓存。做完之后最直观的变化是首页加载时间明显下降,后台操作也不再一顿一顿。Redis 一定要设密码并只监听本机,这一点前面提过,但值得再说一次。
5.3 文件上传与长任务的参数对齐
大文件上传失败是运维工单排行榜第一名。原因永远是那几个参数不一致:PHP 的上传上限、PHP 的 POST 上限、Nginx 的请求体上限,任何一个偏小都会失败。三个值设成一样大,比如都是 200M,问题就没了。改完之后要重启 PHP-FPM 和 reload Nginx,只改一处不重启是不会生效的。
长任务(课程备份、题库导入、报表导出)还需要充足的执行时间和内存。如果这些操作总是在进行到一半时挂掉,先看 PHP 的错误日志,十有八九是超时或内存耗尽。把max_execution_time和memory_limit调大,同时把 Nginx 的读超时同步调大。
5.4 备份策略:备份不是拷贝一次文件
备份要分成两部分:数据库和数据目录。数据库用逻辑备份工具,加一致性快照参数避免锁表;数据目录用增量同步工具,或者干脆用文件系统快照。两部分必须在同一个时间点备份,否则恢复出来会出现数据库里有记录、文件却找不到的情况。
我推荐的节奏是:每天增量备份数据目录,每周全量备份数据库,备份文件异地存一份。恢复演练每季度做一次,很多人备份了三年从没恢复过,真出事那天才发现备份文件是空的或者损坏的。演练的方法很简单,找一台干净的测试机,用备份完整还原一次,能登录、能打开课程、能下载一个学生提交的作业,就算通过。
6. 故障速查表:那些年我在深夜排查过的问题
下面这张表是我自己攒的,按症状索引,遇到问题先查这里,能省掉大量瞎猜的时间。
| 症状 | 最可能的原因 | 排查入手点 |
|---|---|---|
| 整站 502 | PHP-FPM 没起来或进程池打满 | 看 FPM 状态、错误日志、内存余量 |
| 页面 500 白屏 | PHP 致命错误 / 权限不对 | 临时开调试看具体报错、查数据目录权限 |
| 首页正常,后台 404 | URL 重写规则缺失 | 检查 Nginx 的 try_files 配置段 |
| 登录后跳回登录页 | 站点地址与实际访问地址不一致 | 对比配置里的地址与地址栏 |
| 样式和图标全丢 | 静态资源 404 或被拦截 | 开发者工具看资源请求状态 |
| 大文件上传失败 | 三处请求体上限不一致 | 逐项对比并重启服务 |
| 邮件发不出 | 本机邮件服务未配置 | 切到 SMTP 方式并测试发信 |
| 定时任务一直报警 | crontab 用户错误或频率不足 | 用运行用户执行一次看输出 |
| 提交作业无反应 | 表单跨站校验失败 | 检查地址一致性与网关请求头 |
| 磁盘缓慢增长直到满 | 日志、缓存、自动备份堆积 | 看目录占用排行 |
6.1 白屏和 500 的排查方法
Moodle 默认把错误信息藏起来,页面只给一个白屏或者笼统的 500。排查第一步是临时打开调试输出,往配置文件里加两行,把调试级别调到开发者级、允许显示错误,然后复现问题,具体报错就出来了。找到问题后立刻把这两行删掉,绝对不要在生产环境长期开着,报错信息里可能包含路径、SQL 语句甚至配置片段,暴露出去是安全隐患。
如果开了调试还是白屏,说明错误发生在更早的阶段,去看 PHP-FPM 的错误日志和 Nginx 的错误日志。日志里通常会写明是"PHP 解析错误"还是"权限被拒绝"。权限问题最常见的是数据目录属主不对——比如你用 root 跑过一次命令行脚本,生成了 root 所有的缓存文件,之后 Web 用户就写不进去了。处理办法是把数据目录的所有权重新交还给运行用户。
6.2 登录跳转死循环的定位思路
这个问题我在不同项目里遇到过至少五次,每次都是配置层面的地址不一致。定位方法:打开开发者工具的网络面板,点一次登录,看请求的跳转链路,哪一跳回到登录页,那个地址和你的实际地址差在哪,一眼就能看出来。常见差异是少了 www、协议是 http 而访问是 https、多了或少了末尾斜杠。
还有一种情况是浏览器缓存了旧的重定向。清空站点 cookie 和缓存再试一次,如果好了,说明就是陈旧数据的问题。这也提醒我们,改站点地址这类操作最好在维护窗口做,改完通知所有人清缓存,否则会有一批用户持续报"登不上去"。
6.3 恢复与迁移中的注意事项
迁移站点比新装还容易翻车,因为你要同时迁代码、数据、文件和配置,四样里任何一样版本不一致就会出问题。我的做法是:先在新机器上按原样装好同版本的运行环境,把代码和数据目录同步过去,导入数据库,然后只改配置文件里的三处——站点地址、数据目录路径、数据库连接信息,其余一律不动。改完清缓存,如果打不开再回头查日志。
这里有个细节:数据目录里的缓存文件是带路径信息的,如果新旧机器的路径不一样,缓存会失效甚至报错。稳妥的做法是迁移时先把缓存目录清空,让它在新机器上重建。另外,迁移后要跑一次全站的文件校验(后台有相关工具),能查出哪些文件缺失或损坏。
6.4 几条不写在文档里的经验
不要在周五下午升级。这不是迷信,是统计结论。升级出问题的概率是一回事,出问题后有没有人陪你一起处理是另一回事。
插件少装。每个插件都是一份未知代码,都可能在下一次升级时变成不兼容项,都可能成为安全入口。真的需要,先在测试环境里跑一两周。
日志要轮转。Nginx、PHP、Moodle 自身都会写日志,不配置轮转的话,一年之后你会发现磁盘被几百 GB 的日志吃掉。配一条按周切分、保留四周的规则,成本很低。
把运维手册写下来。哪怕是给自己看的。半年后你根本不记得当初那个参数为什么设成那个值,有份记录能救你。
最后分享一个我一直在用的小习惯:每次部署完,用一台没登录过的设备、换一个网络环境,从"打开首页、登录、进一门课、下载一个文件、提交一个作业、查看成绩"这条完整链路走一遍。这条链路走通了,才算真的部署完成;哪一步卡住,那里就是问题所在。部署这事没有"大概没问题",只有"我亲手验证过"。