恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
Muu云课堂v2.1.9部署全攻略:LNMP环境搭建与二次开发要点
首页
资讯中心
/
Muu云课堂v2.1.9部署全攻略:LNMP环境搭建与二次开发要点
Muu云课堂v2.1.9部署全攻略:LNMP环境搭建与二次开发要点
发布时间:2026/9/16 21:23:27
简介一套用于搭建在线教育平台的完整源码包基于PHP开发并配有微信小程序端适合具备一定PHP基础、想了解前后端分离的全栈开发者。资源分为“wxapp”和“muu_classroom”两大目录前者是小程序界面和业务逻辑包含WXML、WXSS与JS文件后者是后端核心提供API接口、数据库交互、用户权限验证和课程管理等功能。整份压缩包共4413个文件压缩后约46.44MB以js、php、wxml、wxss、json、html等为主同时还有sql安装脚本、配置文件和说明文档便于部署学习。当前已有543人学习浏览对希望研究在线教育系统结构、二次开发或提升PHP小程序协同开发能力的人来说是结构清晰、内容完整的实战源码。通过阅读源码可掌握常见的登录鉴权、课程列表分页、视频交互、接口请求封装等实现思路为自主搭建教学类项目提供直接参考。1. Muu云课堂 v2.1.9 是什么、能做什么、适合谁直接说结论Muu云课堂是一套以 PHP MySQL 为底座的在线教学系统v2.1.9 是它的一个迭代打包版本交付形态是 zip 压缩包。这类系统解决的问题很典型——中小型培训机构、个人讲师、企业内部培训团队需要一套能独立部署的网课平台而不是去注册 SaaS 服务。你不用按人头按月付费也不用担心课程数据被平台方锁死源码在自己手里模板、支付、播放权限都可以改。v2.1.9 这个版本通常已经把后台管理、会员体系、课程发布、订单支付这几条主链路跑通了作为二次开发基座是够用的。但我得先把丑话说在前面这套系统不是拿来就能跑的那种一键安装包。它对运行环境有明确要求PHP 版本、MySQL 版本、扩展是否开启、目录权限是否给够任何一环不对表现就是安装页能打开下一步就白屏后台能登录上传课程时却报 500或者学员端首页正常播放页打不开。这不是 bug是环境匹配问题。所以这篇文章不打算逐行解读源码——毕竟任何人对一个未知 zip 包的第一手资料都应该是自己的服务器日志而不是别人博客里的抄来的总结。我按一线部署与二次开发的真实路径来讲先搭建能承接这套系统的 PHP 环境再把 zip 包完整落盘、完成初始化和配置最后聚焦到上传目录、伪静态、定时任务这 3 个最容易返工的点上。适合手里已经拿到 v2.1.9 包、准备本机或服务器部署的开发者也适合需要在此基础上做插件或功能定制的工程师。2. 给 Muu云课堂 v2.1.9 先搭 PHP 运行环境LNMP 组合与四个必查扩展2.1 为什么最稳妥的工作台是 LNMP 而不是 Windows 一键环境常见做法是 Linux Nginx MySQL PHP 这套组合。原因很简单这套系统在大批量静态资源课程封面、视频切片和高并发访问学员同时刷课场景下Nginx 的静态文件处理能力远好于 Apache而对 PHP 的转发也干净利落。如果你手里是 Windows 机器用 phpstudy 或小皮面板做开发调试没问题但一旦要上生产我建议直接照 LNMP 来避免开发环境与线上环境行为不一致。另一个更偷懒但成功率极高的方案是宝塔面板。它本质上也是 LNMP但把环境装配、站点配置、伪静态设置全部图形化了。虽然很多人抨击宝塔占用资源可对于 v2.1.9 这种老牌 PHP 项目宝塔能省掉大量手工编辑配置文件的时间。你如果熟悉命令行完全手动装想快就装面板。两条路最终通往同一个结果但 PHP 版本必须锁在 7.1 ~ 7.4 之间。v2.1.9 的代码风格偏向传统 PHP没有严格类型声明和箭头函数PHP 8.x 下容易触发 deprecation 警告甚至直接白屏新手没必要去踩这个坑。2.2 手动装配以 CentOS 系为例跑通最小依赖这里给一套我在纯净服务器上验证过多次的步骤。PHP 用 7.4 的 remi 源Nginx 用官方源MySQL 用 5.7不追新版本理由上文已经说过稳定优先。# 安装 EPEL 和 remi 仓库remi 是 PHP 多版本的主要来源 yum install -y epel-release yum install -y https://rpms.remirepo.net/enterprise/remi-release-7.rpm # 启用 PHP 7.4 模块并安装 yum-config-manager --enable remi-php74 yum install -y php php-fpm php-mysqlnd php-gd php-xml php-mbstring php-json php-curl php-zip # 安装 Nginx 与 MySQL 5.7 yum install -y nginx yum install -y https://dev.mysql.com/get/mysql57-community-release-el7-11.noarch.rpm yum install -y mysql-community-server # 启动服务并设置开机自启 systemctl start php-fpm nginx mysqld systemctl enable php-fpm nginx mysqld这套命令里值得关注的是php-mysqlnd而不是php-mysql。mysqlnd 是 PHP 官方的 MySQL 驱动性能比 libmysqlclient 好而且对mysql扩展的兼容性最平滑。v2.1.9 如果还沿用了老的mysql_connect写法只有 mysqlnd 能兜底。php-gd是处理课程封面缩略图、二维码生成的必须扩展php-mbstring管中文字符串截取和编码转换缺了它后台文章和课程详情页会乱码php-zip看起来不起眼但后台上传模板包、主题包时都要靠它解压。2.3 环境验证用一个探针文件确认 PHP 扩展全部就位不急着解压 v2.1.9 的 zip 包先写一个临时 PHP 文件来确认当前环境是否满足系统的最低要求。?php // 当前 PHP 版本必须显示 7.x 而不是 8.x echo PHP 版本: . PHP_VERSION . \n; // 必查扩展清单v2.1.9 部署前任何一项缺失都会引起特定功能白屏 $required_exts [pdo, pdo_mysql, gd, mbstring, curl, zip]; foreach ($required_exts as $ext) { if (extension_loaded($ext)) { echo [OK] {$ext} 已加载\n; } else { echo [MISS] {$ext} 未安装请执行 yum install php-{$ext}\n; } }把上面的内容存为check.php放到 Nginx 站点的根目录在浏览器里访问一次。输出的结果直接决定下一步怎么走。我见过最多的问题不是扩展缺失而是pdo_mysql已加载但pdo本身没开或者 gd 库装上了但要用的imagecreatetruecolor函数被编译时禁用这些都是探针文件能快速暴露的。生产环境里的「能用」和「装好了」是两回事探针文件帮你把这两件事对齐。3. 把 v2.1.9 完整落盘从解压路径到数据库初始化的全部操作3.1 选择合适的站点根目录并上传 zip 包部署路径是有讲究的。先把 zip 包传到服务器上再解压到目标站点目录而不是在本地解压后逐个文件上传。后者的最大问题是会丢文件——某些隐藏的.htaccess、.env或配置文件在本地可能被系统隐藏传到服务器就没了。直接传 zip 包到服务器再解压能保证文件完整性。# 假设站点根目录是 /www/wwwroot/muu mkdir -p /www/wwwroot/muu cd /www/wwwroot/muu # 将 Muu云课堂V2 v2.1.9.zip 上传到当前目录之后执行解压 unzip Muu云课堂V2\ v2.1.9.zip # 解开后确认目录结构正常情况下会看到 application、public、upload 等目录 ls -la解压完成后有一个每个部署者都必须做的动作确认安装包内是否套了一层同名目录。很多 zip 包在 Windows 上压缩时会把所有文件装进一个Muu云课堂V2 v2.1.9文件夹里直接解压会得到嵌套结构Nginx 的 root 路径就要指向嵌套后的那一层。判断方式很简单看解压后当前目录下是直接出现index.php还是先出现一个文件夹。如果是后者把所有文件移动出来让站点根目录就是系统入口。3.2 创建数据库并按导入脚本初始化表结构v2.1.9 通常会在包内附带一个sql目录或单个.sql文本文件。先创建数据库再导入表结构顺序不能反否则 MySQL 会报No database selected。# 进入 MySQL 命令行创建数据库字符集用 utf8mb4 mysql -uroot -p # 在 MySQL 内部执行 CREATE DATABASE IF NOT EXISTS muu_cloud DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; quit; # 回到 shell导入安装包自带的 SQL 文件 mysql -uroot -p muu_cloud /www/wwwroot/muu/sql/muu_cloud.sql字符集这一点必须较真。utf8mb4 和 utf8 的差别在于 emoji 和生僻字网课系统里学员昵称、课程评语分分钟出现表情符号用老式 utf8 存 emoji 会报Incorrect string value错误。即便 SQL 文件里的建表语句写的是DEFAULT CHARSETutf8导入后也要手动改成 utf8mb4连带字段排序规则一起改。导入完成后验证表数量是否与 SQL 文件中的建表语句数量一致最直接的方法是-- 列出当前数据库的所有表 SHOW TABLES; -- 确认表数量通常在 50 张以上 SELECT COUNT(*) FROM information_schema.tables WHERE table_schema muu_cloud;表数量不一致就说明 SQL 导入中断了常见原因是 max_allowed_packet 太小导入大 SQL 时报Got a packet bigger than max_allowed_packet。这时在 MySQL 配置文件[mysqld]分段下加一行max_allowed_packet 128M重启 MySQL 后重新导入。3.3 修改系统配置让业务层连上数据库导入完成后打开系统根目录下的数据库配置文件位置在application/database.php或config/database.php这是 v2.1.9 这代系统的常规放置位置。只需要改四个键数据库地址、端口、库名、账号密码。?php // application/database.php 关键配置段 return [ // 数据库地址本机部署就写 127.0.0.1 hostname 127.0.0.1, // MySQL 端口宝塔默认是 3306 hostport 3306, // 数据库名对应 3.2 里创建的库 database muu_cloud, // 数据库账号生产环境千万别用 root username muu_user, // 数据库密码长度不低于 16 位 password your_strong_password_here, ];我在这个配置上踩过最大的坑不在 PHP 文件内部而在 MySQL 的授权。-- 为应用创建独立账号并授权用 root 跑项目是部署大忌 CREATE USER muu_userlocalhost IDENTIFIED BY your_strong_password_here; GRANT ALL PRIVILEGES ON muu_cloud.* TO muu_userlocalhost; FLUSH PRIVILEGES;如果配置都正确但还是提示数据库连接失败先检查 MySQL 是否只监听了 127.0.0.1以及 skip-networking 是否被打开。我的做法是在服务器上用命令行工具直接测一次mysql -umuu_user -p能登录就排除权限问题把排查范围压缩到 PHP 侧的配置和扩展。3.4 目录权限上传、缓存、日志三类目录必须可写v2.1.9 这类系统的运行期写操作集中在三个地方课程视频/封面所在的 upload 目录、应用缓存目录、日志目录。如果这些目录的属主不是 PHP-FPM 的运行用户上传时提示失败、页面打开白屏都是必然的。# PHP-FPM 默认以 www 用户运行把站点属主和属组都改为 www chown -R www:www /www/wwwroot/muu # 关键目录强制给写权限 chmod -R 755 /www/wwwroot/muu/upload chmod -R 755 /www/wwwroot/muu/runtime chmod -R 755 /www/wwwroot/muu/application # 注意runtime 或 application/cache 若保存模板编译结果需 777 兜底 chmod -R 777 /www/wwwroot/muu/runtime/cache权限溢出也是要防的——不需要让整个站点目录都 777。常规做法是目录属主设为 PHP-FPM 的运行用户目录权限 755普通文件 644只有确实需要写入的子目录单独放开。这样即便 web 层被写入恶意文件也无法覆盖 PHP 脚本本身。4. 登录 Muu云课堂后台后必须处理的 4 个关键事项4.1 后台入口和默认账号的安全操作顺序部署完成后打开浏览器访问站点根目录未登录状态下通常会自动跳转到学员端首页后台入口一般在域名/admin.php或域名/index.php?s/admin。拿到初始密码第一件事不是去逛菜单而是立刻进入管理员列表改密码并绑定自己的邮箱和手机号。我第一次帮朋友部署这套系统时发现它的后台登录失败超过 5 次才开始显示验证码而且没有锁定策略。这意味着暴力破解窗口很大攻击者可以在 5 次以内疯狂换密码组合。所以密码策略必须人工补强长度至少 14 位包含大写、小写、数字和符号四类字符。如果 v2.1.9 支持后台修改管理员名把默认的admin改成不易猜到的字符串把「可登录后台的 IP 白名单」功能开起来配合 Nginx 层的allow/deny指令双保险。4.2 后台「系统设置」中三组不能跳过的配置项进入后台后课程、会员、订单这些模块先不用管优先处理三组基础设置。这些设置决定了你的站点访问链路是否能完整闭环。课程存储路径是第一组。v2.1.9 默认把课程视频放在站点根目录的 upload 目录下这个路径是相对于 Web 根目录的。如果你把视频上传到了独立存储目录或 CDN就必须在这里同步修改。第二组是 URL 重写模式。v2.1.9 支持 PATHINFO 和兼容模式两种前者是干净的伪静态 URL后者是带index.php的兼容形式。如果部署在 Nginx 下我建议把 URL 模式改为 PATHINFO并配置好伪静态规则避免 URL 里出现index.php才能访问课程列表。第三组是发送邮件配置。网课系统的密码找回、订单通知、注册激活都依赖这个。v2.1.9 一般内置了 SMTP 接口推荐使用企业邮箱的 SMTP 服务。配置时特别留意端口选项465 端口对应 SSL 加密587 端口对应 STARTTLS选错了就会一直报「无法连接到邮件服务器」。4.3 Nginx 伪静态规则要让课程页和播放页都能访问v2.1.9 的课程详情页、章节播放页、会员中心都依赖 PATHINFO 路由。Nginx 下如果没有正确配置伪静态访问域名/course/12会直接 404。这是新部署者最常问的问题。下面这段配置是我常用的基础规则适配 ThinkPHP 5.x 系列的路由风格server { listen 80; server_name your-domain.com; root /www/wwwroot/muu/public; index index.php index.html; location / { if (-f $request_filename) { break; } if (!-e $request_filename) { rewrite ^(.*)$ /index.php?s$1 last; break; } } location ~ \.php$ { fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } location ~* \.(jpg|jpeg|png|gif|ico|css|js|mp4|webm)$ { expires 30d; access_log off; } # 上传目录不允许执行 PHP location ~* /upload/.*\.php$ { deny all; } }规则核心就两行rewrite ^(.*)$ /index.php?s$1 last;将所有不存在的文件路径交给 index.php 处理并由框架自身解析路由location ~* /upload/.*\.php$则严禁上传目录执行 PHP防止攻击者上传带马图片然后直接拿 webshell。location ~ \.php$里的fastcgi_param SCRIPT_FILENAME尤其重要如果少了这段所有 PHP 请求都会报 File not found 或 Primary script unknown。4.4 配置定时任务处理订单超时与课程转码v2.1.9 的部分功能依赖定时任务最常见的是未支付订单的自动关闭和视频转码任务。如果网站运行一天后发现订单一直停留在待支付状态就要检查定时任务是否配好了。# 编辑 crontab crontab -e # 每分钟执行一次订单超时检查具体路径以实际项目为准 * * * * * php /www/wwwroot/muu/public/index.php /order/autoclose /www/wwwroot/muu/runtime/autoclose.log 21 # 每天凌晨 2 点执行一次数据库备份前的清理任务 0 2 * * * php /www/wwwroot/muu/public/index.php /task/clean /www/wwwroot/muu/runtime/clean.log 21判断这套命令是否生效不要依赖 crontab 的静默执行用日志输出就好。把定时任务的执行结果都重定向到 runtime 目录第二天去翻日志看有没有报错信息。如果没有生成日志文件先检查 crontab 里 php 的命令路径which php看到的是什么就填什么很多服务器配置多个 PHP 版本时默认路径指向错误版本。5. 上线前的改动备份方案、日志留痕和一处容易被忽略的表结构优化5.1 数据库与课程文件分离备份生产环境最怕的不是服务器宕机而是误删数据后没有备份。v2.1.9 的数据分两部分MySQL 里的业务数据以及 upload 目录下的课程视频。备份脚本需要同时覆盖两处。#!/bin/bash # /root/backup_muu.sh BACKUP_DIR/data/muu_backup/$(date %Y%m%d) mkdir -p $BACKUP_DIR # 备份数据库用 mysqldump 比直接复制 data 目录更可靠 mysqldump -umuu_user -pyour_password muu_cloud $BACKUP_DIR/muu_cloud.sql # 备份课程文件排除缓存目录减少体积 rsync -av --excluderuntime/cache /www/wwwroot/muu/upload $BACKUP_DIR/upload # 保留最近 14 天备份超出自动清理 find /data/muu_backup/ -mtime 14 -type d -exec rm -rf {} \;脚本里避开了一个常见错误——mysqldump放在 crontab 的 PATH 里经常找不到因为 cron 环境干净。所以在备份脚本开头写上 MySQL 的完整路径例如/usr/bin/mysqldump或者用source /etc/profile先加载环境变量。恢复时先解压备份目录里的 SQL 文件导入数据库再将 upload 目录完整放回原位置。数据库版本要一致我在 5.7 上备份的库恢复到 8.0 时遇到过默认排序规则不兼容的问题因此生产环境不要频繁切换 MySQL 大版本。5.2 通过 Nginx access.log 观察学员端行为异常日志是重放事故现场的基础。对 v2.1.9 这类系统最需要监控的是课程视频播放接口的请求分布——如果某个 IP 在一分钟之内请求了上百次视频切片大概率是下载器在抓取课程资源。Nginx 默认的日志格式够用但我会加上请求响应时间和 UA方便区分正常播放器和脚本。log_format main $remote_addr - [$time_local] $request $status $body_bytes_sent $http_referer $http_user_agent $request_time;拿到日志后常用的观察命令# 查看视频播放接口访问量最大的 20 个 IP awk {print $1} /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20 # 查看 500 错误的请求路径 grep 500 /var/log/nginx/access.log | awk {print $7} | sort | uniq -c | sort -rn | head -20$request_time的值如果长期超过 3 秒说明 PHP-FPM 处理能力到瓶颈了这时候不用急着加机器先用top看 PHP-FPM 进程数是否已经打满再判断是 CPU 密集转码类任务还是 IO 密集磁盘读取过慢。很多教程上来就建议调pm.max_children但我通常先看平均响应时间再决定盲调参数只会掩盖真正的问题。5.3 给课程表补一个最常用却总被忽视的索引v2.1.9 默认的数据库结构在业务初期没有问题但课程数量超过 2000 条后后台课程列表打开会越来越慢。观察后发现卡点集中在按cat_id分类和status上下架状态联合筛选时没有可用索引MySQL 走了全表扫描。很多网课类系统都存在这个通病因为建表 SQL 只定义主键而真实业务里的高频查询条件不是主键是各种筛选状态。-- 查看当前表结构的索引情况 SHOW INDEX FROM mu_course; -- 为分类状态组合增加联合索引覆盖后台列表页和学员端课程列表页 ALTER TABLE mu_course ADD INDEX idx_cat_status (cat_id, status); -- 如果搜索框支持按标题模糊查询给 title 加普通索引注意不是全文索引 ALTER TABLE mu_course ADD INDEX idx_title (title(50));title(50)是前缀索引只取前 50 个字符建立索引既控制索引占用空间又覆盖绝大多数标题长度。执行完后用EXPLAIN SELECT * FROM mu_course WHERE cat_id 3 AND status 1验证如果 type 从ALL变成refrows 从几千降到几十说明索引生效了。这样的小改动不需要改任何 PHP 代码却能让后台页面回到秒开状态。部署的完整链路到这里就闭环了。从环境匹配、解压落盘、数据库导入到后台基础项调整、伪静态规则、定时任务再到上线前的备份和索引优化每一步都是 v2.1.9 从压缩包变成稳定服务的位置点。剩余的功能细节——比如模板标签的写法、支付回调的具体参数——建议直接以一线代码为准用浏览器开发者工具和 MySQL 慢查询日志双端验证比翻任何文档都可靠。本文还有配套的精品资源点击获取