diff --git a/apps/moodle/.env b/apps/moodle/.env index 370f128bd..4fe11e097 100644 --- a/apps/moodle/.env +++ b/apps/moodle/.env @@ -1,16 +1,34 @@ W9_POWER_PASSWORD='mCjG5CnUKA!GsOXK' -W9_VERSION='5.1.1' +W9_VERSION='5.1.3' W9_DIST='community' W9_REPO=websoft9dev/moodle #### -- Not allowed to edit below environments when recreate app based on existing data -- #### W9_ID='moodle' W9_HTTP_PORT=80 -W9_HTTP_PORT_SET='9001' -W9_URL='appname.example.com' +W9_HTTP_PORT_SET=9001 +W9_URL=internet_ip:$W9_HTTP_PORT_SET W9_URL_REPLACE=true +W9_ADMIN_PATH=/admin +W9_LOGIN_USER=admin +W9_LOGIN_PASSWORD=$W9_POWER_PASSWORD W9_DB_EXPOSE="mariadb" -W9_MARIADB_VERSION="11.4" -W9_DIST='community' +W9_DB_VERSION="11.4" W9_NETWORK=websoft9 #### --------------------------------------------------------------------------------------- #### + +MOODLE_URL=http://$W9_URL +MOODLE_DB_HOST=$W9_ID-mariadb +MOODLE_DB_NAME=moodle +MOODLE_DB_USER=moodle +MOODLE_DB_TYPE=mariadb +MOODLE_DB_PORT=3306 +MOODLE_ADMIN_USER=$W9_LOGIN_USER +MOODLE_ADMIN_PASSWORD=$W9_POWER_PASSWORD +MOODLE_DB_PASSWORD=$W9_POWER_PASSWORD +MOODLE_ADMIN_EMAIL=admin@example.com +MOODLE_SITE_NAME=Moodle Learning Platform +MYSQL_ROOT_PASSWORD=$W9_POWER_PASSWORD +MYSQL_DATABASE=moodle +MYSQL_USER=moodle +MYSQL_PASSWORD=$W9_POWER_PASSWORD diff --git a/apps/moodle/Dockerfile b/apps/moodle/Dockerfile index 526c54b6c..f5932a0c5 100644 --- a/apps/moodle/Dockerfile +++ b/apps/moodle/Dockerfile @@ -1,121 +1,51 @@ -# Moodle Dockerfile based on official php:apache -# Reference: https://docs.moodle.org/501/en/Installation_quick_guide +# Moodle Dockerfile based on moodlehq/moodle-php-apache +# Official base image: https://hub.docker.com/r/moodlehq/moodle-php-apache +# Install guide: https://docs.moodle.org/en/Installation_quick_guide -FROM php:8.2-apache +FROM moodlehq/moodle-php-apache:8.3-bullseye LABEL org.opencontainers.image.authors="https://www.websoft9.com" \ - org.opencontainers.image.description="Moodle packaged by Websoft9" \ - org.opencontainers.image.source="https://packaging.moodle.org/stable501/moodle-5.1.1.zip" \ - org.opencontainers.image.title="Moodle" \ - org.opencontainers.image.vendor="Websoft9 Inc." \ - org.opencontainers.image.version="5.1.1" - -# Moodle version -ENV MOODLE_VERSION=5.1.1 \ - MOODLE_DATA=/var/moodledata - -# Install system dependencies and PHP extensions required by Moodle -RUN apt-get update && apt-get install -y \ - # Basic tools - wget \ + org.opencontainers.image.description="Moodle packaged by Websoft9" \ + org.opencontainers.image.title="Moodle" \ + org.opencontainers.image.vendor="Websoft9 Inc." \ + org.opencontainers.image.version="5.1.3" + +ENV MOODLE_VERSION=5.1.3 \ + MOODLE_DATA=/var/moodledata \ + APACHE_DOCUMENT_ROOT=/var/www/html/public + +# Install system tools (all Moodle PHP extensions are pre-installed by base image) +RUN apt-get update && apt-get install -y --no-install-recommends \ + curl \ unzip \ - git \ cron \ - # Libraries for PHP extensions - libicu-dev \ - libpng-dev \ - libjpeg62-turbo-dev \ - libfreetype6-dev \ - libxml2-dev \ - libzip-dev \ - libldap2-dev \ - libpq-dev \ - libonig-dev \ - libxslt1-dev \ - libcurl4-openssl-dev \ - # Database clients default-mysql-client \ - postgresql-client \ - # Cleanup && rm -rf /var/lib/apt/lists/* -# Configure and install PHP extensions required by Moodle -# GD extension -RUN docker-php-ext-configure gd --with-freetype --with-jpeg \ - && docker-php-ext-install -j$(nproc) gd - -# Install other extensions -RUN docker-php-ext-install -j$(nproc) \ - intl \ - mysqli \ - pgsql \ - pdo_mysql \ - pdo_pgsql \ - opcache \ - zip \ - soap \ - mbstring \ - exif - -# LDAP extension (configure separately to avoid path issues) -RUN docker-php-ext-configure ldap \ - && docker-php-ext-install ldap - -# Install additional recommended PHP extensions -RUN pecl install redis \ - && docker-php-ext-enable redis - -# Configure PHP settings for Moodle -RUN { \ - echo 'file_uploads = On'; \ - echo 'memory_limit = 512M'; \ - echo 'upload_max_filesize = 512M'; \ - echo 'post_max_size = 512M'; \ - echo 'max_execution_time = 600'; \ - echo 'max_input_vars = 5000'; \ - echo 'max_input_time = 600'; \ - echo 'session.save_handler = files'; \ - echo 'session.auto_start = 0'; \ - echo 'session.gc_maxlifetime = 1440'; \ - echo 'zend.exception_ignore_args = On'; \ - } > /usr/local/etc/php/conf.d/moodle.ini - -# Configure OPcache for performance -RUN { \ - echo 'opcache.enable = 1'; \ - echo 'opcache.memory_consumption = 128'; \ - echo 'opcache.interned_strings_buffer = 8'; \ - echo 'opcache.max_accelerated_files = 4000'; \ - echo 'opcache.revalidate_freq = 60'; \ - echo 'opcache.fast_shutdown = 1'; \ - } > /usr/local/etc/php/conf.d/opcache-recommended.ini - # Enable Apache modules -RUN a2enmod rewrite expires headers ssl - -# Configure Apache DocumentRoot to use /public directory (Moodle 5.0+ requirement) -RUN sed -i 's|DocumentRoot /var/www/html|DocumentRoot /var/www/html/public|g' /etc/apache2/sites-available/000-default.conf \ - && sed -i 's||\n Options Indexes FollowSymLinks\n AllowOverride All\n Require all granted\n\n|g' /etc/apache2/apache2.conf +RUN a2enmod rewrite expires headers -# Create moodledata directory with proper permissions +# Create Moodle data directory with correct permissions RUN mkdir -p ${MOODLE_DATA} \ && chown -R www-data:www-data ${MOODLE_DATA} \ - && chmod -R 0777 ${MOODLE_DATA} + && chmod 777 ${MOODLE_DATA} -# Download and extract Moodle +# Download Moodle source code +# For CI/CD: no proxy needed. For local builds behind a firewall: +# docker build --network=host --build-arg CURL_PROXY=socks5h://127.0.0.1:1080 ... +ARG CURL_PROXY= WORKDIR /var/www/html -RUN wget -O moodle.zip "https://packaging.moodle.org/stable501/moodle-${MOODLE_VERSION}.zip" \ - && unzip -q moodle.zip \ - && mv moodle/* moodle/.??* . 2>/dev/null || true \ - && rmdir moodle \ - && rm moodle.zip \ - && chown -R www-data:www-data /var/www/html \ - && chmod -R 0755 /var/www/html +RUN curl ${CURL_PROXY:+--proxy "$CURL_PROXY"} -fsSL -o /tmp/moodle.zip \ + "https://packaging.moodle.org/stable501/moodle-${MOODLE_VERSION}.zip" \ + && unzip -q /tmp/moodle.zip -d /tmp/moodle_src \ + && cp -a /tmp/moodle_src/moodle/. /var/www/html/ \ + && rm -rf /tmp/moodle.zip /tmp/moodle_src \ + && chown -R www-data:www-data /var/www/html -# Setup cron job for Moodle -RUN echo "* * * * * www-data /usr/local/bin/php /var/www/html/admin/cli/cron.php >/dev/null" >> /etc/crontab +# Moodle scheduled task (cron) +RUN echo "* * * * * www-data /usr/local/bin/php /var/www/html/admin/cli/cron.php >/dev/null 2>&1" \ + >> /etc/crontab -# Create entrypoint script COPY docker-entrypoint.sh /usr/local/bin/ RUN chmod +x /usr/local/bin/docker-entrypoint.sh diff --git a/apps/moodle/Notes.md b/apps/moodle/Notes.md index e363a94f3..e69de29bb 100644 --- a/apps/moodle/Notes.md +++ b/apps/moodle/Notes.md @@ -1,158 +0,0 @@ -## About - -Moodle Docker deployment with MariaDB support. - -## URL Configuration - -### Changing from IP to Domain - -When you need to change from IP access to domain access, you need to update both the config file and database: - -1. **Update config.php** (in container `/var/www/html/config.php`): -```bash -docker exec -it moodle sed -i "s|http://.*';|http://your-domain.com';|g" /var/www/html/config.php -``` - -2. **Update database**: -```bash -docker exec -it moodle-mariadb mariadb -umoodle -p moodle -e "UPDATE mdl_config SET value = 'http://your-domain.com' WHERE name = 'wwwroot';" -``` - -3. **Clear Moodle cache**: -```bash -docker exec -it moodle php /var/www/html/admin/cli/purge_caches.php -``` - -### HTTPS Configuration with Reverse Proxy - -If you encounter **infinite redirect loop** after configuring HTTPS certificate (via Nginx Proxy Manager), you need to configure Moodle to work behind a reverse proxy. - -**Problem**: -- config.php has `$CFG->wwwroot = 'http://domain.com';` -- User accesses via HTTPS -- Moodle detects protocol mismatch and redirects infinitely - -**Solution**: Add reverse proxy configuration to `/var/www/html/config.php`: - -```bash -# Enter the container -docker exec -it moodle bash - -# Edit config.php and add these lines BEFORE require_once(): -vi /var/www/html/config.php -``` - -Add the following configuration **BEFORE** the `require_once(__DIR__ . '/lib/setup.php');` line: - -```php -// HTTPS Reverse Proxy Configuration -$CFG->wwwroot = 'https://safeline.websoft9.cn'; // Change to HTTPS - -// Force HTTPS when behind reverse proxy -if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') { - $_SERVER['HTTPS'] = 'on'; - $_SERVER['SERVER_PORT'] = 443; -} - -// Alternative: Force HTTPS for all requests -// $CFG->reverseproxy = true; -// $_SERVER['HTTPS'] = 'on'; -``` - -**Complete config.php example**: - -```php -dbtype = 'mariadb'; -$CFG->dblibrary = 'native'; -$CFG->dbhost = 'moodle_edf5j-mariadb'; -$CFG->dbname = 'moodle'; -$CFG->dbuser = 'moodle'; -$CFG->dbpass = 'qB!5Glu37szh1bUd'; -$CFG->prefix = 'mdl_'; -$CFG->dboptions = array( - 'dbpersist' => 0, - 'dbport' => '3306', - 'dbsocket' => '', - 'dbcollation' => 'utf8mb4_unicode_ci', -); - -// IMPORTANT: Change to HTTPS -$CFG->wwwroot = 'https://safeline.websoft9.cn'; -$CFG->dataroot = '/var/moodledata'; -$CFG->admin = 'admin'; - -$CFG->directorypermissions = 0777; - -// HTTPS Reverse Proxy Support -if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') { - $_SERVER['HTTPS'] = 'on'; - $_SERVER['SERVER_PORT'] = 443; -} - -require_once(__DIR__ . '/lib/setup.php'); - -// There is no php closing tag in this file, -// it is intentional because it prevents trailing whitespace problems! -``` - -**Quick Fix Command**: - -```bash -# Method 1: Edit manually -docker exec -it moodle vi /var/www/html/config.php - -# Method 2: Use sed to update URL to HTTPS -docker exec -it moodle sed -i "s|http://safeline.websoft9.cn|https://safeline.websoft9.cn|g" /var/www/html/config.php - -# Then add reverse proxy config (manual edit required) -docker exec -it moodle vi /var/www/html/config.php -# Add the HTTP_X_FORWARDED_PROTO check before require_once() -``` - -**Update database** (also change to HTTPS): - -```bash -docker exec -it moodle_edf5j-mariadb mariadb -umoodle -pqB\!5Glu37szh1bUd moodle -e "UPDATE mdl_config SET value = 'https://safeline.websoft9.cn' WHERE name = 'wwwroot';" -``` - -**Clear cache**: - -```bash -docker exec -it moodle php /var/www/html/admin/cli/purge_caches.php -``` - -### Verify Nginx Proxy Manager Configuration - -Ensure your Nginx Proxy Manager has these settings: - -1. **SSL Certificate**: Valid and properly configured -2. **Force SSL**: Enabled -3. **Custom Nginx Configuration** (Advanced tab): - -```nginx -# Ensure these headers are passed to backend -proxy_set_header X-Forwarded-Proto $scheme; -proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; -proxy_set_header X-Real-IP $remote_addr; -proxy_set_header Host $host; -``` - -## Troubleshooting - -### Issue: Infinite Redirect Loop -- **Cause**: Protocol mismatch between config.php (http) and actual access (https) -- **Solution**: Change `$CFG->wwwroot` to HTTPS and add reverse proxy support - -### Issue: "Site not secure" warning -- **Cause**: Mixed content (HTTP resources on HTTPS page) -- **Solution**: Ensure `$CFG->wwwroot` uses HTTPS - -### Issue: Session errors -- **Cause**: Cookie domain mismatch -- **Solution**: Clear browser cookies and cache after changing URL diff --git a/apps/moodle/README.md b/apps/moodle/README.md index a82f2e5ac..aa858b739 100644 --- a/apps/moodle/README.md +++ b/apps/moodle/README.md @@ -3,12 +3,12 @@ This is an **[Docker Compose template](https://github.com/Websoft9/docker-library)** powered by [Websoft9](https://www.websoft9.com) based on Docker for Moodle: - - community: 5.0, latest + - community: 5.1.3, latest ## System Requirements -The following are the minimal [recommended requirements](https://github.com/moodle/docker#recommended-system-requirements): +The following are the minimal [recommended requirements](https://docs.moodle.org/en/Installing_Moodle#System_requirements): * **RAM**: 1 GB or more * **CPU**: 1 cores or higher diff --git a/apps/moodle/STORY.md b/apps/moodle/STORY.md deleted file mode 100644 index eef809355..000000000 --- a/apps/moodle/STORY.md +++ /dev/null @@ -1,514 +0,0 @@ -# Moodle Docker 镜像构建项目 Story - -## 📋 项目概述 - -**项目名称**: Moodle 官方 Docker 镜像(非官方维护) -**目标**: 为 Moodle 创建生产级 Docker 镜像并推送到 Docker Hub -**背景**: Moodle 官方不维护 Docker 镜像,需要基于 `php:apache` 自行构建 -**镜像仓库**: `docker.io/websoft9dev/moodle` - -## 🎯 项目目标 - -### 核心目标 -1. 创建基于官方 `php:apache` 的 Moodle 容器镜像 -2. 支持最新的 Moodle 5.1.1 版本(稳定版) -3. 遵循 Moodle 官方安装指南和最佳实践 -4. 提供生产环境可用的配置 -5. 支持一键部署和自动化安装 - -### 技术要求 -- ✅ PHP 8.2 + Apache(Moodle 5.1 官方要求) -- ✅ 所有必需的 PHP 扩展 -- ✅ MariaDB/PostgreSQL 数据库支持 -- ✅ 性能优化配置(OPcache, Redis) -- ✅ 符合 Moodle 5.0+ 新架构(/public 目录) -- ✅ 自动化配置和安装脚本 -- ✅ 健康检查和日志管理 -- ✅ 数据持久化 - -## 📚 参考文档 - -- **官方安装指南**: https://docs.moodle.org/501/en/Installation_quick_guide -- **系统要求**: https://docs.moodle.org/501/en/Installing_Moodle#Requirements -- **下载地址**: https://packaging.moodle.org/stable501/moodle-5.1.1.zip -- **PHP Docker 镜像**: https://hub.docker.com/_/php - -## 🏗️ 架构设计 - -### 容器架构 -``` -┌─────────────────────────────────────────┐ -│ Moodle Container │ -│ ┌────────────────────────────────┐ │ -│ │ Apache 2.4 + PHP 8.2 │ │ -│ │ - mod_rewrite enabled │ │ -│ │ - DocumentRoot: /public │ │ -│ └────────────────────────────────┘ │ -│ ┌────────────────────────────────┐ │ -│ │ Moodle 5.1.1 Application │ │ -│ │ - /var/www/html │ │ -│ │ - /var/moodledata (data) │ │ -│ └────────────────────────────────┘ │ -│ ┌────────────────────────────────┐ │ -│ │ Cron Job (每分钟执行) │ │ -│ └────────────────────────────────┘ │ -└─────────────────────────────────────────┘ - │ - │ Network: websoft9 - ↓ -┌─────────────────────────────────────────┐ -│ MariaDB Container │ -│ - utf8mb4_unicode_ci │ -│ - InnoDB optimized │ -└─────────────────────────────────────────┘ -``` - -### 目录结构 -``` -moodle-docker/ -├── Dockerfile # 主镜像定义 -├── docker-entrypoint.sh # 启动脚本 -├── docker-compose.yml # Bitnami 版本(向后兼容) -├── docker-compose-custom.yml # 自定义镜像版本 -├── .env # 环境变量 -├── build-and-deploy.sh # 构建部署脚本 -├── DOCKERFILE_README.md # 使用文档 -├── STORY.md # 本文档 -└── src/ # 配置文件(如需要) -``` - -## 🔧 技术实现 - -### 第一阶段:Dockerfile 构建 - -#### 1.1 基础镜像选择 -- **镜像**: `php:8.2-apache` -- **原因**: - - 官方维护,安全更新及时 - - 预装 Apache,减少配置工作 - - Debian-based,软件包丰富 - -#### 1.2 系统依赖安装 -```dockerfile -RUN apt-get update && apt-get install -y \ - wget unzip git cron \ - libicu-dev libpng-dev libjpeg62-turbo-dev \ - libfreetype6-dev libxml2-dev libzip-dev \ - libldap2-dev libpq-dev libonig-dev \ - libxslt1-dev libcurl4-openssl-dev \ - default-mysql-client postgresql-client -``` - -**关键依赖说明**: -- `libicu-dev`: 国际化支持(必需) -- `libpng-dev`, `libjpeg62-turbo-dev`: GD 图像处理 -- `libzip-dev`: ZIP 文件处理 -- `libldap2-dev`: LDAP 认证 -- `default-mysql-client`: 数据库连接测试 - -#### 1.3 PHP 扩展安装 -必需扩展(根据官方要求): -- ✅ **gd** - 图像处理 -- ✅ **intl** - 国际化 -- ✅ **mysqli** / **pgsql** - 数据库 -- ✅ **opcache** - 性能优化 -- ✅ **zip** - 文件压缩 -- ✅ **soap** - Web 服务 -- ✅ **mbstring** - 多字节字符串 -- ✅ **exif** - 图像元数据 -- ✅ **ldap** - LDAP 认证 - -推荐扩展: -- ✅ **redis** - 缓存和会话存储 - -#### 1.4 PHP 配置优化 -```ini -# /usr/local/etc/php/conf.d/moodle.ini -memory_limit = 512M -upload_max_filesize = 512M -post_max_size = 512M -max_execution_time = 600 -max_input_vars = 5000 -zend.exception_ignore_args = On # 安全要求 -``` - -```ini -# /usr/local/etc/php/conf.d/opcache-recommended.ini -opcache.enable = 1 -opcache.memory_consumption = 128 -opcache.max_accelerated_files = 4000 -opcache.revalidate_freq = 60 -``` - -#### 1.5 Apache 配置 -关键配置: -- **DocumentRoot**: `/var/www/html/public` (Moodle 5.0+ 要求) -- **启用模块**: rewrite, expires, headers, ssl -- **AllowOverride**: All (支持 .htaccess) - -#### 1.6 Moodle 下载和部署 -```dockerfile -RUN wget -O moodle.zip "https://packaging.moodle.org/stable501/moodle-5.1.1.zip" \ - && unzip -q moodle.zip \ - && mv moodle/* moodle/.??* . \ - && rmdir moodle && rm moodle.zip -``` - -#### 1.7 Cron 任务配置 -```dockerfile -RUN echo "* * * * * www-data /usr/local/bin/php /var/www/html/admin/cli/cron.php >/dev/null" >> /etc/crontab -``` - -### 第二阶段:Entrypoint 脚本 - -#### 2.1 启动流程 -```bash -1. 启动 cron 服务 -2. 等待数据库就绪(健康检查) -3. 检查 config.php 是否存在 - - 不存在:从环境变量生成 - - 存在:跳过配置 -4. 运行自动安装(如果设置了管理员账号) -5. 修复文件权限 -6. 启动 Apache -``` - -#### 2.2 数据库连接等待 -```bash -for i in {1..30}; do - if mysqladmin ping -h"$MOODLE_DB_HOST" -u"$MOODLE_DB_USER" -p"$MOODLE_DB_PASSWORD" --silent; then - echo "Database is ready!" - break - fi - sleep 2 -done -``` - -#### 2.3 自动配置生成 -```php -dbtype = 'mariadb'; // 注意:Moodle 5.1 推荐使用 mariadb -$CFG->dbhost = 'moodle-mariadb'; -$CFG->dbname = 'moodle'; -$CFG->dbuser = 'moodle'; -$CFG->dbpass = 'password'; -$CFG->wwwroot = 'http://example.com'; -$CFG->dataroot = '/var/moodledata'; -$CFG->directorypermissions = 0777; -``` - -### 第三阶段:Docker Compose 编排 - -#### 3.1 服务定义 -```yaml -services: - moodle: - build: . - image: websoft9dev/moodle:5.1 - depends_on: - mariadb: - condition: service_healthy - environment: - - MOODLE_DB_TYPE=mariadb - - MOODLE_DB_HOST=moodle-mariadb - # ... 其他环境变量 - volumes: - - moodle_html:/var/www/html - - moodle_data:/var/moodledata - ports: - - "9001:80" - - mariadb: - image: mariadb:11.4 - environment: - - MYSQL_DATABASE=moodle - - MYSQL_USER=moodle - command: - - --character-set-server=utf8mb4 - - --collation-server=utf8mb4_unicode_ci - healthcheck: - test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"] - interval: 10s - retries: 5 -``` - -#### 3.2 数据持久化 -- `moodle_html`: Moodle 程序文件 -- `moodle_data`: 用户上传、课程内容 -- `mariadb_data`: 数据库数据 - -### 第四阶段:镜像构建和推送 - -#### 4.1 本地构建测试 -```bash -# 构建镜像 -docker build -t websoft9dev/moodle:5.1 . -docker build -t websoft9dev/moodle:latest . - -# 本地测试 -docker compose -f docker-compose-custom.yml up -d - -# 验证 -curl http://localhost:9001 -docker logs moodle -``` - -#### 4.2 推送到 Docker Hub -```bash -# 登录 Docker Hub -docker login - -# 推送镜像 -docker push websoft9dev/moodle:5.1 -docker push websoft9dev/moodle:5.1.1 -docker push websoft9dev/moodle:latest - -# 验证 -docker pull websoft9dev/moodle:5.1 -``` - -#### 4.3 多架构支持(可选) -```bash -# 创建 buildx builder -docker buildx create --use - -# 构建多架构镜像 -docker buildx build \ - --platform linux/amd64,linux/arm64 \ - -t websoft9dev/moodle:5.1 \ - --push . -``` - -## 🔒 安全考虑 - -### 镜像安全 -- ✅ 使用官方基础镜像 -- ✅ 定期更新依赖包 -- ✅ 最小化镜像层数 -- ✅ 不在镜像中存储敏感信息 -- ✅ 使用 `.dockerignore` 排除不必要文件 - -### 运行时安全 -- ✅ 使用非 root 用户运行(www-data) -- ✅ 只开放必要端口 -- ✅ 使用环境变量管理密码 -- ✅ 启用 PHP 安全设置(zend.exception_ignore_args) -- ✅ 配置 HTTPS(通过反向代理) - -### 数据安全 -- ✅ 数据库密码加密存储 -- ✅ 定期备份 volumes -- ✅ 使用 Docker secrets(生产环境) - -## 📊 性能优化 - -### PHP 优化 -- ✅ OPcache 预编译缓存 -- ✅ 适当的内存限制(512MB) -- ✅ 会话和缓存使用 Redis - -### 数据库优化 -- ✅ InnoDB buffer pool 调优 -- ✅ utf8mb4_unicode_ci 字符集 -- ✅ 连接池配置 - -### Apache 优化 -- ✅ 启用 mod_expires (浏览器缓存) -- ✅ 启用 mod_deflate (压缩) -- ✅ KeepAlive 配置 - -## 🧪 测试计划 - -### 功能测试 -1. **基础功能** - - [ ] 容器启动成功 - - [ ] Apache 响应正常 - - [ ] 数据库连接成功 - - [ ] Moodle 安装向导可访问 - -2. **安装测试** - - [ ] 系统检查全部通过 - - [ ] 数据库类型识别正确(mariadb) - - [ ] 自动安装完成 - - [ ] 管理员登录成功 - -3. **核心功能** - - [ ] 创建课程 - - [ ] 上传文件 - - [ ] 用户注册 - - [ ] Cron 任务执行 - -### 性能测试 -- [ ] 首页加载时间 < 2s -- [ ] 并发 100 用户响应正常 -- [ ] 内存使用 < 1GB(正常负载) - -### 兼容性测试 -- [ ] 支持 MariaDB 10.11+ -- [ ] 支持 PostgreSQL 15+ -- [ ] 支持 MySQL 8.0+ - -## 📦 交付清单 - -### 代码文件 -- [x] Dockerfile -- [x] docker-entrypoint.sh -- [x] docker-compose.yml -- [x] docker-compose-custom.yml -- [x] .env -- [x] .dockerignore - -### 文档 -- [x] README.md - 项目说明 -- [x] DOCKERFILE_README.md - 使用指南 -- [x] STORY.md - 本文档 -- [x] CHANGELOG.md - 版本历史 - -### 脚本 -- [x] build-and-deploy.sh - 构建部署 -- [ ] backup.sh - 备份脚本 -- [ ] upgrade.sh - 升级脚本 - -### Docker Hub -- [ ] 镜像推送:websoft9dev/moodle:5.1 -- [ ] 镜像推送:websoft9dev/moodle:5.1.1 -- [ ] 镜像推送:websoft9dev/moodle:latest -- [ ] README 更新 -- [ ] 标签管理 - -## 🚀 部署流程 - -### 开发环境部署 -```bash -git clone -cd moodle -docker network create websoft9 -docker build -t websoft9dev/moodle:5.1 . -docker compose -f docker-compose-custom.yml up -d -``` - -### 生产环境部署 -```bash -# 1. 准备环境 -docker network create websoft9 - -# 2. 配置环境变量 -cp .env.example .env -nano .env # 修改密码、域名等 - -# 3. 拉取镜像 -docker pull websoft9dev/moodle:5.1 -docker pull mariadb:11.4 - -# 4. 启动服务 -docker compose -f docker-compose-custom.yml up -d - -# 5. 查看日志 -docker compose logs -f - -# 6. 访问应用 -https://yourdomain.com -``` - -## 📈 版本管理 - -### 版本号规则 -- **5.1** - 主版本(跟随 Moodle) -- **5.1.1** - 精确版本 -- **latest** - 最新稳定版 - -### 更新策略 -- **每月检查** Moodle 官方更新 -- **安全补丁** 立即更新 -- **主版本** 经过测试后更新 - -### Git 标签 -```bash -git tag -a v5.1.1 -m "Moodle 5.1.1 Docker image" -git push origin v5.1.1 -``` - -## 🐛 已知问题和解决方案 - -### 问题 1: 数据库连接失败 -**现象**: "Database connection failed" -**原因**: MariaDB 未完全启动 -**解决**: -- 添加 healthcheck -- entrypoint 中等待数据库就绪 - -### 问题 2: /public 目录访问 -**现象**: "Moodle root directory must not be publicly accessible" -**原因**: Moodle 5.0+ 要求 DocumentRoot 指向 /public -**解决**: -- 修改 Apache 配置 -- `DocumentRoot /var/www/html/public` - -### 问题 3: 数据库类型警告 -**现象**: "You need to change it from 'mysqli' to 'mariadb'" -**原因**: Moodle 5.1 推荐使用 mariadb 驱动 -**解决**: -- 修改 `$CFG->dbtype = 'mariadb'` - -## 🎓 学习资源 - -- [Moodle 官方文档](https://docs.moodle.org/) -- [Docker 最佳实践](https://docs.docker.com/develop/dev-best-practices/) -- [PHP Docker 镜像](https://github.com/docker-library/php) -- [Apache 配置](https://httpd.apache.org/docs/2.4/) - -## 📝 待办事项 - -### 短期目标(本周) -- [x] 完成 Dockerfile 编写 -- [x] 完成 docker-entrypoint.sh -- [x] 完成 docker-compose 配置 -- [x] 本地测试通过 -- [ ] 推送镜像到 Docker Hub -- [ ] 编写完整的 README - -### 中期目标(本月) -- [ ] 添加 Redis 缓存支持 -- [ ] 添加 SSL/HTTPS 配置示例 -- [ ] 创建备份和恢复脚本 -- [ ] 多架构支持(amd64, arm64) -- [ ] CI/CD 自动化构建 - -### 长期目标(季度) -- [ ] 支持所有 Moodle 4.x 和 5.x 版本 -- [ ] 性能基准测试报告 -- [ ] 集群部署方案 -- [ ] Kubernetes YAML 配置 -- [ ] 监控和日志方案(Prometheus + Grafana) - -## 🤝 贡献指南 - -### 如何贡献 -1. Fork 项目 -2. 创建特性分支 (`git checkout -b feature/AmazingFeature`) -3. 提交更改 (`git commit -m 'Add some AmazingFeature'`) -4. 推送到分支 (`git push origin feature/AmazingFeature`) -5. 开启 Pull Request - -### 代码规范 -- Dockerfile 使用多阶段构建(如适用) -- Shell 脚本遵循 ShellCheck 建议 -- 注释清晰,说明关键逻辑 -- 提交信息遵循 Conventional Commits - -## 📞 支持和反馈 - -- **问题反馈**: GitHub Issues -- **功能请求**: GitHub Discussions -- **技术支持**: support@websoft9.com -- **文档贡献**: Pull Request - -## 📄 许可证 - -本项目遵循 MIT 许可证。Moodle 本身遵循 GPL v3 许可证。 - ---- - -**最后更新**: 2026-02-05 -**维护者**: Websoft9 Team -**版本**: 1.0.0 diff --git a/apps/moodle/build-and-deploy.sh b/apps/moodle/build-and-deploy.sh deleted file mode 100644 index 1fa8eb284..000000000 --- a/apps/moodle/build-and-deploy.sh +++ /dev/null @@ -1,47 +0,0 @@ -#!/bin/bash -# Quick build and deploy script for custom Moodle - -set -e - -echo "==========================================" -echo "Moodle Custom Docker Build & Deploy" -echo "==========================================" -echo "" - -# Check if websoft9 network exists -if ! docker network inspect websoft9 &>/dev/null; then - echo "Creating websoft9 network..." - docker network create websoft9 -else - echo "✓ websoft9 network exists" -fi - -echo "" -echo "Building custom Moodle image..." -docker build -t websoft9dev/moodle:5.1 . - -echo "" -echo "Starting services..." -docker compose -f docker-compose-custom.yml up -d - -echo "" -echo "Waiting for services to be ready..." -sleep 10 - -echo "" -echo "==========================================" -echo "Deployment complete!" -echo "==========================================" -echo "" -echo "Access Moodle at: http://localhost:9001" -echo "" -echo "Default credentials:" -echo " Username: admin" -echo " Password: Check .env file (W9_POWER_PASSWORD)" -echo "" -echo "Useful commands:" -echo " View logs: docker compose -f docker-compose-custom.yml logs -f" -echo " Stop: docker compose -f docker-compose-custom.yml down" -echo " Restart: docker compose -f docker-compose-custom.yml restart" -echo " Remove all: docker compose -f docker-compose-custom.yml down -v" -echo "" diff --git a/apps/moodle/docker-compose.yml b/apps/moodle/docker-compose.yml index c4beb5831..5756d7172 100644 --- a/apps/moodle/docker-compose.yml +++ b/apps/moodle/docker-compose.yml @@ -1,7 +1,5 @@ -# Custom Moodle with php:apache base image -# Official installation guide: https://docs.moodle.org/501/en/Installation_quick_guide - -version: "3.8" +# image: https://hub.docker.com/r/websoft9dev/moodle (self-built, base: moodlehq/moodle-php-apache) +# docs: https://docs.moodle.org/en/Installation_quick_guide services: moodle: @@ -9,58 +7,37 @@ services: container_name: ${W9_ID} restart: unless-stopped env_file: .env - environment: - # Database configuration - - MOODLE_DB_TYPE=mariadb - - MOODLE_DB_HOST=${W9_ID}-mariadb - - MOODLE_DB_PORT=3306 - - MOODLE_DB_NAME=moodle - - MOODLE_DB_USER=moodle - - MOODLE_DB_PASSWORD=${W9_POWER_PASSWORD} - # Site configuration - - MOODLE_URL=http://${W9_URL} - - MOODLE_SITE_NAME=Moodle Learning Platform - - MOODLE_SITE_SHORT=Moodle - # Data directory - - MOODLE_DATA=/var/moodledata ports: - - "${W9_HTTP_PORT_SET}:80" + - "${W9_HTTP_PORT_SET}:${W9_HTTP_PORT}" volumes: - - moodle_html:/var/www/html - moodle_data:/var/moodledata + - ./src/php.ini:/usr/local/etc/php/conf.d/moodle.ini depends_on: mariadb: condition: service_healthy mariadb: - image: mariadb:${W9_MARIADB_VERSION} + image: mariadb:${W9_DB_VERSION} container_name: ${W9_ID}-mariadb restart: unless-stopped - environment: - - MYSQL_ROOT_PASSWORD=${W9_POWER_PASSWORD} - - MYSQL_DATABASE=moodle - - MYSQL_USER=moodle - - MYSQL_PASSWORD=${W9_POWER_PASSWORD} + env_file: .env command: > - --character-set-server=utf8mb4 - --collation-server=utf8mb4_unicode_ci - --max_allowed_packet=512M - --innodb_buffer_pool_size=512M - --innodb_log_file_size=256M + --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --max_allowed_packet=512M volumes: - mariadb_data:/var/lib/mysql healthcheck: - test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"] + test: [ "CMD", "healthcheck.sh", "--connect", "--innodb_initialized" ] interval: 10s timeout: 5s - retries: 5 - + retries: 10 + start_period: 30s + volumes: - moodle_html: moodle_data: mariadb_data: + networks: default: name: ${W9_NETWORK} - external: true \ No newline at end of file + external: true diff --git a/apps/moodle/docker-entrypoint.sh b/apps/moodle/docker-entrypoint.sh index ac7da1976..298c3be3c 100644 --- a/apps/moodle/docker-entrypoint.sh +++ b/apps/moodle/docker-entrypoint.sh @@ -1,87 +1,82 @@ #!/bin/bash -set -e +set -euo pipefail -# Start cron service -service cron start +: "${MOODLE_DB_HOST:=}" +: "${MOODLE_DB_PORT:=3306}" +: "${MOODLE_DB_NAME:=moodle}" +: "${MOODLE_DB_USER:=moodle}" +: "${MOODLE_DB_PASSWORD:=}" +: "${MOODLE_DB_TYPE:=mariadb}" +: "${MOODLE_DATA:=/var/moodledata}" +: "${MOODLE_URL:=http://localhost}" +: "${MOODLE_ADMIN_USER:=admin}" +: "${MOODLE_ADMIN_PASSWORD:=${MOODLE_DB_PASSWORD}}" +: "${MOODLE_ADMIN_EMAIL:=admin@example.com}" +: "${MOODLE_SITE_NAME:=Moodle Learning Platform}" -# Wait for database to be ready -if [ -n "$MOODLE_DB_HOST" ]; then - echo "Waiting for database to be ready..." - for i in {1..30}; do - if mysqladmin ping -h"$MOODLE_DB_HOST" -u"${MOODLE_DB_USER:-moodle}" -p"${MOODLE_DB_PASSWORD}" --silent 2>/dev/null; then - echo "Database is ready!" - break +# Start cron daemon (runs in background, handles /etc/crontab) +cron + +# Restore config.php from moodledata if it was persisted after a previous install +if [ -f "${MOODLE_DATA}/.moodle_config.php" ] && [ ! -f /var/www/html/config.php ]; then + echo "Restoring config.php from moodledata..." + cp "${MOODLE_DATA}/.moodle_config.php" /var/www/html/config.php +fi + +# Wait for the database to be ready (max 120 seconds) +if [ -n "${MOODLE_DB_HOST}" ]; then + echo "Waiting for database at ${MOODLE_DB_HOST}:${MOODLE_DB_PORT}..." + timeout=120 + elapsed=0 + until mysqladmin ping \ + -h "${MOODLE_DB_HOST}" \ + -P "${MOODLE_DB_PORT}" \ + -u "${MOODLE_DB_USER}" \ + -p"${MOODLE_DB_PASSWORD}" \ + --silent 2>/dev/null; do + if [ "${elapsed}" -ge "${timeout}" ]; then + echo "ERROR: Database did not become ready within ${timeout}s" >&2 + exit 1 fi - echo "Waiting for database... ($i/30)" sleep 2 + elapsed=$((elapsed + 2)) done + echo "Database is ready." fi -# If config.php doesn't exist, create it from environment variables -if [ ! -f /var/www/html/config.php ] && [ -n "$MOODLE_DB_HOST" ]; then - cat > /var/www/html/config.php <dbtype = '${MOODLE_DB_TYPE:-mariadb}'; -\$CFG->dblibrary = 'native'; -\$CFG->dbhost = '${MOODLE_DB_HOST}'; -\$CFG->dbname = '${MOODLE_DB_NAME:-moodle}'; -\$CFG->dbuser = '${MOODLE_DB_USER:-moodle}'; -\$CFG->dbpass = '${MOODLE_DB_PASSWORD}'; -\$CFG->prefix = 'mdl_'; -\$CFG->dboptions = array( - 'dbpersist' => 0, - 'dbport' => '${MOODLE_DB_PORT:-3306}', - 'dbsocket' => '', - 'dbcollation' => 'utf8mb4_unicode_ci', -); - -\$CFG->wwwroot = '${MOODLE_URL:-http://localhost}'; -\$CFG->dataroot = '${MOODLE_DATA:-/var/moodledata}'; -\$CFG->admin = 'admin'; - -\$CFG->directorypermissions = 0777; - -require_once(__DIR__ . '/lib/setup.php'); - -// There is no php closing tag in this file, -// it is intentional because it prevents trailing whitespace problems! -EOF - - chown www-data:www-data /var/www/html/config.php - chmod 0644 /var/www/html/config.php - - # Run installation if MOODLE_ADMIN_USER is set - if [ -n "$MOODLE_ADMIN_USER" ]; then - echo "Installing Moodle..." - php /var/www/html/admin/cli/install.php \ - --lang=en \ - --wwwroot="${MOODLE_URL:-http://localhost}" \ - --dataroot="${MOODLE_DATA:-/var/moodledata}" \ - --dbtype="${MOODLE_DB_TYPE:-mysqli}" \ - --dbhost="${MOODLE_DB_HOST}" \ - --dbname="${MOODLE_DB_NAME:-moodle}" \ - --dbuser="${MOODLE_DB_USER:-moodle}" \ - --dbpass="${MOODLE_DB_PASSWORD}" \ - --dbport="${MOODLE_DB_PORT:-3306}" \ - --prefix=mdl_ \ - --fullname="${MOODLE_SITE_NAME:-Moodle Site}" \ - --shortname="${MOODLE_SITE_SHORT:-Moodle}" \ - --adminuser="${MOODLE_ADMIN_USER:-admin}" \ - --adminpass="${MOODLE_ADMIN_PASSWORD}" \ - --adminemail="${MOODLE_ADMIN_EMAIL:-admin@example.com}" \ - --non-interactive \ - --agree-license || echo "Installation may already be completed" - fi +# Install or upgrade Moodle +if [ ! -f /var/www/html/config.php ]; then + echo "Starting Moodle installation..." + php /var/www/html/admin/cli/install.php \ + --lang=en \ + --wwwroot="${MOODLE_URL}" \ + --dataroot="${MOODLE_DATA}" \ + --dbtype="${MOODLE_DB_TYPE}" \ + --dbhost="${MOODLE_DB_HOST}" \ + --dbname="${MOODLE_DB_NAME}" \ + --dbuser="${MOODLE_DB_USER}" \ + --dbpass="${MOODLE_DB_PASSWORD}" \ + --dbport="${MOODLE_DB_PORT}" \ + --prefix=mdl_ \ + --fullname="${MOODLE_SITE_NAME}" \ + --shortname="Moodle" \ + --adminuser="${MOODLE_ADMIN_USER}" \ + --adminpass="${MOODLE_ADMIN_PASSWORD}" \ + --adminemail="${MOODLE_ADMIN_EMAIL}" \ + --non-interactive \ + --agree-license + echo "Moodle installation complete." + # Persist config.php to moodledata so it survives container recreations + cp /var/www/html/config.php "${MOODLE_DATA}/.moodle_config.php" +elif php /var/www/html/admin/cli/upgrade.php --is-pending --non-interactive 2>/dev/null | grep -q "pending\|Upgrade"; then + echo "Database upgrade pending, running upgrade..." + php /var/www/html/admin/cli/upgrade.php --non-interactive + echo "Moodle upgrade complete." + cp /var/www/html/config.php "${MOODLE_DATA}/.moodle_config.php" fi -# Fix permissions +# Ensure correct permissions chown -R www-data:www-data /var/www/html -chown -R www-data:www-data ${MOODLE_DATA:-/var/moodledata} +chown -R www-data:www-data "${MOODLE_DATA}" -# Execute the CMD exec "$@" diff --git a/apps/moodle/src/README.md b/apps/moodle/src/README.md new file mode 100644 index 000000000..c67d24218 --- /dev/null +++ b/apps/moodle/src/README.md @@ -0,0 +1,24 @@ +# src/ — Custom Configuration Files + +This directory contains configuration files that are bind-mounted into the Moodle container at startup. + +## Files + +### php.ini + +Mounted to: `/usr/local/etc/php/conf.d/moodle.ini` + +Overrides PHP defaults with Moodle-recommended values: + +| Setting | Value | Purpose | +|---|---|---| +| `memory_limit` | 512M | Moodle minimum is 256M; 512M recommended | +| `upload_max_filesize` | 512M | Allows large file uploads in courses | +| `post_max_size` | 512M | Must be ≥ `upload_max_filesize` | +| `max_execution_time` | 600 | Prevents timeouts during upgrades/cron | +| `max_input_vars` | 5000 | Required for forms with many items | +| `max_input_time` | 600 | Time limit for parsing input data | + +**To apply changes:** Edit `php.ini` and run `docker compose restart moodle`. + +**Reference:** https://docs.moodle.org/en/PHP_settings diff --git a/apps/moodle/src/after_up.sh b/apps/moodle/src/after_up.sh deleted file mode 100644 index 8b1378917..000000000 --- a/apps/moodle/src/after_up.sh +++ /dev/null @@ -1 +0,0 @@ - diff --git a/apps/moodle/src/assets/exttests/apache2.conf b/apps/moodle/src/assets/exttests/apache2.conf deleted file mode 100644 index ab31697b1..000000000 --- a/apps/moodle/src/assets/exttests/apache2.conf +++ /dev/null @@ -1,31 +0,0 @@ - - # The ServerName directive sets the request scheme, hostname and port that - # the server uses to identify itself. This is used when creating - # redirection URLs. In the context of virtual hosts, the ServerName - # specifies what hostname must appear in the request's Host: header to - # match this virtual host. For the default virtual host (this file) this - # value is not decisive as it is used as a last resort host regardless. - # However, you must set it for any further virtual host explicitly. - #ServerName www.example.com - - ServerAdmin webmaster@localhost - DocumentRoot /var/www/html - - # Available loglevels: trace8, ..., trace1, debug, info, notice, warn, - # error, crit, alert, emerg. - # It is also possible to configure the loglevel for particular - # modules, e.g. - #LogLevel info ssl:warn - - ErrorLog ${APACHE_LOG_DIR}/error.log - CustomLog ${APACHE_LOG_DIR}/access.log combined - - # For most configuration files from conf-available/, which are - # enabled or disabled at a global level, it is possible to - # include a line for only one particular virtual host. For example the - # following line enables the CGI configuration for this host only - # after it has been globally disabled with "a2disconf". - #Include conf-available/serve-cgi-bin.conf - - -# vim: syntax=apache ts=4 sw=4 sts=4 sr noet diff --git a/apps/moodle/src/assets/exttests/apache2_ports.conf b/apps/moodle/src/assets/exttests/apache2_ports.conf deleted file mode 100644 index 13f9d48a3..000000000 --- a/apps/moodle/src/assets/exttests/apache2_ports.conf +++ /dev/null @@ -1,15 +0,0 @@ -# If you just change the port or add more ports here, you will likely also -# have to change the VirtualHost statement in -# /etc/apache2/sites-enabled/000-default.conf - -Listen 9000 - - - Listen 9443 - - - - Listen 9443 - - -# vim: syntax=apache ts=4 sw=4 sts=4 sr noet diff --git a/apps/moodle/src/assets/web/apache2_faildumps.conf b/apps/moodle/src/assets/web/apache2_faildumps.conf deleted file mode 100644 index 8b607565c..000000000 --- a/apps/moodle/src/assets/web/apache2_faildumps.conf +++ /dev/null @@ -1,6 +0,0 @@ - - Options +Indexes - - -Alias /_/faildumps /var/www/behatfaildumps - diff --git a/apps/moodle/src/assets/web/apache2_mailhog.conf b/apps/moodle/src/assets/web/apache2_mailhog.conf deleted file mode 100644 index 9230390e1..000000000 --- a/apps/moodle/src/assets/web/apache2_mailhog.conf +++ /dev/null @@ -1,19 +0,0 @@ - - LoadModule proxy_module /usr/lib/apache2/modules/mod_proxy.so - - - - LoadModule proxy_http_module /usr/lib/apache2/modules/mod_proxy_http.so - - - - LoadModule proxy_wstunnel_module /usr/lib/apache2/modules/mod_proxy_wstunnel.so - - -Redirect "/_/mail" "/_/mail/" - -ProxyPass "/_/mail/api/v2/websocket" "ws://mailhog:8025/api/v2/websocket" -ProxyPassReverse "/_/mail/api/v2/websocket" "ws://mailhog:8025/api/v2/websocket" - -ProxyPass "/_/mail/" "http://mailhog:8025/" -ProxyPassReverse "/_/mail/" "http://mailhog:8025/" diff --git a/apps/moodle/src/filelist b/apps/moodle/src/filelist deleted file mode 100644 index 341240aed..000000000 --- a/apps/moodle/src/filelist +++ /dev/null @@ -1,3 +0,0 @@ -docker-compose.yml -script/test.sh -docker \ No newline at end of file diff --git a/apps/moodle/src/get_version.sh b/apps/moodle/src/get_version.sh deleted file mode 100644 index b224ea657..000000000 --- a/apps/moodle/src/get_version.sh +++ /dev/null @@ -1 +0,0 @@ -sudo echo "moodle version": $(docker exec -i moodle cat /bitnami/moodle/licenses/gpl-source-links.txt | cut -d "," -f 1 | cut -d "-" -f 2) | tee -a /data/logs/install_version.txt diff --git a/apps/moodle/src/php.ini b/apps/moodle/src/php.ini new file mode 100644 index 000000000..b9566777e --- /dev/null +++ b/apps/moodle/src/php.ini @@ -0,0 +1,9 @@ +; Moodle recommended PHP settings +; Edit this file and restart the container to apply changes + +memory_limit = 512M +upload_max_filesize = 512M +post_max_size = 512M +max_execution_time = 600 +max_input_vars = 5000 +max_input_time = 600 diff --git a/apps/moodle/variables.json b/apps/moodle/variables.json index 2cef02f89..edd158a53 100644 --- a/apps/moodle/variables.json +++ b/apps/moodle/variables.json @@ -2,18 +2,21 @@ "name": "moodle", "trademark": "Moodle", "release": true, - "fork_url": "https://github.com/moodlehq/moodle-docker", - "version_from": "https://hub.docker.com/r/bitnami/moodle/tags", + "fork_url": "https://github.com/moodlehq/moodle-php-apache", + "version_from": "https://github.com/moodle/moodle/releases", "edition": [ { "dist": "community", - "version": ["5.1.1","latest"] + "version": [ + "5.1.3", + "latest" + ] } ], "requirements": { "cpu": "1", "memory": "1", "disk": "4", - "url": "https://github.com/moodle/docker#recommended-system-requirements" + "url": "https://docs.moodle.org/en/Installing_Moodle#System_requirements" } -} +} \ No newline at end of file