Moodle 是成熟的开源学习管理系统(LMS),适合企业内训、学校课程、考试培训和会员内容平台。自托管 Moodle 可以掌握课程文件、用户数据和插件版本,也能避免按用户数量持续增加 SaaS 费用。本文以 Ubuntu 24.04 LTS、Docker Compose、PostgreSQL、Redis 和 Nginx 反向代理为例,说明如何在 VPS 上部署可维护的 Moodle 环境。
Moodle 的 Web 请求、定时任务、文件上传和数据库查询会同时消耗资源。视频不建议直接放在 Moodle 服务器上,课程视频应使用对象存储或专门的视频平台。
| 场景 | CPU | 内存 | 磁盘 | 建议 |
|---|---|---|---|---|
| 个人测试 | 2 vCPU | 4 GB | 50 GB SSD | 少量课程,关闭调试日志 |
| 小型培训站 | 4 vCPU | 8 GB | 100 GB NVMe | 独立备份,启用 Redis 缓存 |
| 多班级生产 | 8 vCPU | 16 GB+ | 200 GB NVMe+ | 数据库、文件和队列分层 |
先准备 learn.example.com,将 DNS 的 A/AAAA 记录指向 VPS,只开放 SSH、HTTP 和 HTTPS。PostgreSQL、Redis 和 PHP-FPM 不要直接暴露公网。磁盘规划要包含 moodledata、数据库增长、临时压缩包和至少一份本地备份。可以参考 VPS 配置怎么选。
sudo apt update
sudo apt install -y ca-certificates curl git openssl
curl -fsSL https://get.docker.com | sudo sh
sudo usermod -aG docker "$USER"
newgrp docker
sudo mkdir -p /opt/moodle
sudo chown -R "$USER":"$USER" /opt/moodle
cd /opt/moodle
生产环境应固定 Moodle、数据库和 Redis 的镜像版本,不要使用 latest。可以基于 Bitnami Moodle 镜像或官方 PHP/Apache 镜像维护自己的 Compose 文件。示例服务包括 moodle、postgres、redis 和反向代理,重要数据通过 named volume 保存。
mkdir -p compose moodledata backups
touch compose/docker-compose.yml .env
chmod 600 .env
每次升级前记录 Git commit、镜像 digest 和 docker compose config,这样出现兼容性问题时能明确回退目标。
Moodle 的数据库建议使用 PostgreSQL 14 或更高版本,并使用 UTF-8 编码。Redis 可以用于应用缓存和会话,但不要把 Redis 作为唯一数据存储。
MOODLE_IMAGE=bitnami/moodle:4.5
POSTGRES_IMAGE=postgres:16
POSTGRES_DB=moodle
POSTGRES_USER=moodle
POSTGRES_PASSWORD=change-a-long-database-password
REDIS_PASSWORD=change-a-long-redis-password
MOODLE_HOST=learn.example.com
MOODLE_SITE_NAME=企业学习平台
MOODLE_ADMIN_USER=admin
MOODLE_ADMIN_PASSWORD=change-a-long-admin-password
[email protected]
密码和应用密钥应使用随机值生成:
openssl rand -base64 48
openssl rand -hex 32
Compose 配置至少要保证数据库和 moodledata 不会随容器删除:
services:
postgres:
image: postgres:16
restart: unless-stopped
environment:
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- postgres_data:/var/lib/postgresql/data
redis:
image: redis:7-alpine
command: ["redis-server", "--requirepass", "${REDIS_PASSWORD}"]
restart: unless-stopped
volumes:
- redis_data:/data
moodle:
image: ${MOODLE_IMAGE}
restart: unless-stopped
depends_on:
- postgres
- redis
ports:
- "127.0.0.1:8080:8080"
volumes:
- moodle_data:/bitnami/moodle
- moodle_files:/bitnami/moodledata
volumes:
postgres_data:
redis_data:
moodle_data:
moodle_files:
不同镜像的环境变量和目录可能不同,部署前必须以所选镜像文档为准,先运行 docker compose config 检查渲染结果,再启动服务:
docker compose -f compose/docker-compose.yml config
docker compose -f compose/docker-compose.yml pull
docker compose -f compose/docker-compose.yml up -d
docker compose -f compose/docker-compose.yml ps
首次打开 http://127.0.0.1:8080 或通过临时域名访问时,按向导选择 PostgreSQL,填写数据库主机名 postgres、数据库名、用户和密码。站点目录和 moodledata 必须位于容器卷中,moodledata 不能放在 Web 可直接访问的目录下。
安装完成后立即检查版本和计划任务:
docker compose -f compose/docker-compose.yml exec moodle php admin/cli/cfg.php --name=wwwroot
docker compose -f compose/docker-compose.yml exec moodle php admin/cli/cron.php
后台先创建课程分类、教师角色、学生角色和隐私策略,再导入课程。不要用管理员账号日常授课;教师、助教和审计用户应按最小权限分配能力。
Moodle 的文件上传通常比普通博客大,需要同时调整 Nginx、PHP upload_max_filesize、post_max_size 和 Moodle 的站点限制。这里用宿主机 Nginx 终止 TLS:
sudo apt install -y nginx certbot python3-certbot-nginx
sudo nano /etc/nginx/sites-available/moodle
server {
listen 80;
server_name learn.example.com;
client_max_body_size 256m;
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;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
sudo ln -s /etc/nginx/sites-available/moodle /etc/nginx/sites-enabled/moodle
sudo nginx -t
sudo systemctl reload nginx
sudo certbot --nginx -d learn.example.com
证书签发后测试登录、课程文件下载和大文件上传。也可以使用 Caddy 简化证书续期,参考 VPS 用 Caddy 反向代理完全指南。
Moodle 的计划任务负责发送通知、处理统计、清理临时文件和执行异步任务。生产环境应每分钟运行一次 cron,而不是依赖管理员访问页面触发:
* * * * * cd /opt/moodle && docker compose -f compose/docker-compose.yml exec -T moodle php admin/cli/cron.php >/dev/null 2>&1
启用 Redis 后,在 Moodle 后台配置应用缓存和会话缓存,确认 Redis 主机、端口和密码正确。不要把数据库缓存、应用缓存和会话缓存全部指向同一个无密码 Redis 实例。
性能排查顺序通常是:先看 PHP worker 和数据库慢查询,再看磁盘 I/O,最后调整缓存和并发。课程首页图片、视频和大附件应使用 CDN 或对象存储,避免单台 VPS 的出口带宽成为瓶颈。
密码重置、课程通知、论坛订阅和作业提醒都依赖 SMTP。配置 SMTP 后先给管理员发送测试邮件,并检查 SPF、DKIM、DMARC、PTR 和出站端口策略。
- 管理员启用 MFA,后台使用独立账号。
- 教师只能管理分配给自己的课程,审计账号只读。
- 关闭不使用的自注册、访客访问和插件。
- API 集成使用独立服务账号和 Token,定期轮换并限制权限。
- 开启登录失败限制、备份保留策略和安全更新提醒。
插件要从可信来源安装,并在测试环境验证 Moodle 主版本兼容性。不要为了一个小功能长期保留无人维护的插件。
完整备份必须包含 PostgreSQL、Moodle 代码配置、moodledata、插件清单和 Compose 文件。仅备份数据库无法恢复课程附件、作业提交和用户头像。
mkdir -p /opt/moodle/backups
docker compose -f compose/docker-compose.yml exec -T postgres pg_dump -U "$POSTGRES_USER" "$POSTGRES_DB" | gzip > /opt/moodle/backups/moodle-$(date +%F).sql.gz
docker compose -f compose/docker-compose.yml cp moodle:/bitnami/moodledata /opt/moodle/backups/moodledata-$(date +%F)
cp .env compose/docker-compose.yml /opt/moodle/backups/
docker compose -f compose/docker-compose.yml config > /opt/moodle/backups/compose-$(date +%F).yaml
将备份同步到另一台 VPS 或对象存储,并加密包含密码的文件。至少每月在隔离域名做一次恢复演练,验证登录、课程、附件、考试、邮件和 cron。可以结合 Restic、Rclone 与 Docker 数据库的恢复演练。
Moodle 升级前先阅读版本要求,确认 PHP、PostgreSQL、插件和主题兼容。推荐流程:
- 开启维护模式,停止用户写入。
- 备份数据库、
moodledata、配置和当前镜像 digest。 - 在测试环境升级并运行 CLI 检查、cron 和课程回归测试。
- 生产环境更新代码或镜像,运行数据库升级。
- 验证登录、课程、文件、邮件、缓存和后台任务后关闭维护模式。
docker compose -f compose/docker-compose.yml exec moodle php admin/cli/maintenance.php --enable
docker compose -f compose/docker-compose.yml pull
docker compose -f compose/docker-compose.yml up -d
docker compose -f compose/docker-compose.yml exec moodle php admin/cli/upgrade.php --non-interactive
docker compose -f compose/docker-compose.yml exec moodle php admin/cli/maintenance.php --disable
如果升级后的数据库结构已经变化,不要直接将旧镜像接回生产。应从备份恢复到隔离环境,确认旧版本可用后再决定回滚或继续迁移。
检查 Nginx、Moodle、PostgreSQL 和 Redis 日志,确认 8080 端口监听、容器网络可达,PHP 内存限制没有过低。
同时检查 Nginx client_max_body_size、PHP upload_max_filesize、post_max_size、Moodle 站点上限和反向代理超时。
检查 SMTP 认证、DNS、出站端口、系统 cron 和容器内 admin/cli/cron.php 输出。队列堆积时查看 Redis 和 worker 资源,不要直接删除任务数据。
检查 moodledata、课程备份、日志、临时文件、PostgreSQL WAL、Docker 镜像和旧备份。清理前先确认异地备份可恢复。
- Moodle、PostgreSQL、Redis 和 Web 容器状态正常。
- HTTPS、强制 HTTPS、上传限制和反向代理头配置正确。
- cron 每分钟执行,Redis 缓存和会话配置通过测试。
- SMTP、密码重置、课程通知和大文件上传测试成功。
- 管理员启用 MFA,教师和审计用户遵循最小权限。
- 数据库、
moodledata、配置和插件版本已异地备份。 - 已完成一次隔离环境恢复演练,并记录恢复时间。
Moodle 自托管真正需要维护的是数据、插件、计划任务和恢复流程。先把课程文件、数据库和邮件链路跑通,再逐步接入对象存储、CDN、监控和自动化升级,VPS 才能稳定支撑长期教学业务。
延伸阅读:
