Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 22 additions & 5 deletions apps/moodle/.env
Original file line number Diff line number Diff line change
@@ -1,16 +1,33 @@
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_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=root
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
134 changes: 32 additions & 102 deletions apps/moodle/Dockerfile
Original file line number Diff line number Diff line change
@@ -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|<Directory /var/www/>|<Directory /var/www/html/>\n Options Indexes FollowSymLinks\n AllowOverride All\n Require all granted\n</Directory>\n<Directory /var/www/html/public/>|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

Expand Down
158 changes: 0 additions & 158 deletions apps/moodle/Notes.md
Original file line number Diff line number Diff line change
@@ -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
<?php // Moodle configuration file

unset($CFG);
global $CFG;
$CFG = new stdClass();

$CFG->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
4 changes: 2 additions & 2 deletions apps/moodle/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading
Loading