Moodle setup with high availability (HA) capabilities for Docker, build on Alpine Linux.
Repository: https://github.com/jimsihk/alpine-moodle
- Based on official Moodle source https://github.com/moodle/moodle
- Built on the lightweight image https://github.com/jimsihk/alpine-php-nginx
- Smaller container image size (+/-150MB for full version, +/-90MB for slim version)
- Supports HA installation with multiple type of cache stores (memcached, Redis) and PostgresSQL poolers like PgBouncer
- Supports also Redis Sentinel as cache stores via plugin https://github.com/catalyst/moodle-cachestore_redissentinel
- Pre-install Moodle plug-ins at build time with argument
ARG_MOODLE_PLUGIN_LIST
- Always up-to-date Moodle version and Alpine packages with Renovate (see below)
- Supports read-only replica of database
- Multi-arch support: 386, amd64, arm/v7, arm64, ppc64le, s390x
- Optimized for 100 concurrent users
- Optimized to only use resources when there's traffic (by using PHP-FPM's ondemand PM)
- JIT enabled by default
- Use of runit instead of supervisord to reduce memory footprint
- Configured cron to run as non-privileged user gliderlabs/docker-alpine#381 (comment)
- Configuration via ENV variables
- Auto update Moodle plugin and upgrade to newer Moodle versions (via
ARG_MOODLE_GIT_URL
andARG_MOODLE_GIT_BRANCH
at build time,MOODLE_GIT_URL
andMOODLE_GIT_BRANCH
at run time) when container start - The servers NGINX, PHP-FPM run under a non-privileged user (nobody) to make it more secure
- The logs of all the services are redirected to the output of the Docker container (visible with
docker logs -f <container name>
) - Follows the KISS principle (Keep It Simple, Stupid) to make it easy to understand and adjust the image to your needs
Moodle version and package dependencies are monitored and automatically updated through pull requests by Renovate: https://github.com/renovatebot/renovate
A nightly build in GitHub Action scans for changes, then performs tagging and publishes a newer release on container registries.
The release tag will be in pattern: XXX.YYY.ZZ
- XXX = Moodle Branch
- YYY = Moodle Release Increments & Incremental Changes Number based on
version.php
of Moodle source - ZZ = Git Repo Releases
e.g. for Moodle 4.1.1+ branch 401 version 2022112801.06, the release tag number will be starting from 401.106.0
The images are available on multiple registries:
- DockerHub: https://hub.docker.com/r/jimsihk/alpine-moodle
- Quay.io: https://quay.io/repository/jimsihk/alpine-moodle
- Standard version with full features
- Even smaller container image size
- Git is not installed
- Removed in-place code upgrade functionality (i.e. ignored
UPDATE_MOODLE_CODE
) - Controlled by build argument
ARG_ENABLE_GIT_CLONE
when build
Start the Docker containers:
docker compose up
Start a Moodle cluster:
./generate_ssl_cert.sh
docker compose --file docker-compose.replica.yml up
Login on the system using the provided credentials (ENV vars)
- docker-compose.yml - with PostgreSQL
- docker-compose.replica.yml - with PostgreSQL, Redis and multiple Moodle containers, using NGINX as load balancer with SSL termination
- execute
generate_ssl_cert.sh
to generate a sample SSL certificate for localhost - refer to https://docs.moodle.org/en/Caching for setting up after login or set the
SESSION_CACHE_*
environment variables - please note this setup is NOT configured for production use, use it for demonstration only
- execute
Define the ENV variables in docker-compose.yml file
Variable Name | Default | Description |
---|---|---|
LANG | en_US.UTF-8 | |
LANGUAGE | en_US:en | |
SITE_URL | http://localhost | Sets the public site URL |
SSLPROXY | false | Disable SSL proxy to avoid site loop. e.g. Cloudflare |
DB_TYPE | pgsql | mysqli - pgsql - mariadb |
DB_HOST | postgres | Database hostname e.g. database container name |
DB_PORT | 5432 | PostgresSQL=5432 - MySQL/MariaDB=3306 |
DB_NAME | moodle | Database name |
DB_USER | moodle | Database login username |
DB_PASS | moodle | Database login password |
DB_FETCHBUFFERSIZE | Set to 0 if using PostgresSQL poolers like PgBouncer in 'transaction' mode | |
DB_DBHANDLEOPTIONS | false | Set to true if using PostgresSQL poolers like PgBouncer which does not support sending options |
DB_HOST_REPLICA | Database hostname of the read-only replica database | |
DB_PORT_REPLICA | Database port of replica, left it empty to be same as DB_PORT | |
DB_USER_REPLICA | Database login username of replica, left it empty to be same as DB_USER | |
DB_PASS_REPLICA | Database login password of replica, left it empty to be same as DB_PASS | |
DB_PREFIX | mdl_ | Database prefix. WARNING: don't use numeric values or Moodle won't start |
MOODLE_EMAIL | [email protected] | |
MOODLE_LANGUAGE | en | |
MOODLE_SITENAME | New-Site | |
MOODLE_SHORTNAME | moodle | |
MOODLE_USERNAME | moodleuser | |
MOODLE_PASSWORD | PLEASE_CHANGEME | |
SMTP_HOST | smtp.gmail.com | |
SMTP_PORT | 587 | |
SMTP_USER | [email protected] | |
SMTP_PASSWORD | your_password | |
SMTP_PROTOCOL | tls | |
MOODLE_MAIL_NOREPLY_ADDRESS | noreply@localhost | |
MOODLE_MAIL_PREFIX | [moodle] | |
memory_limit | 128M | Maximum amount of memory that a PHP script is allowed to allocate (default value inherited from base image) |
client_max_body_size | 50M | Sets the maximum allowed size of the client request body, specified in the “Content-Length” request header field |
post_max_size | 50M | Max size of post data allowed. This setting also affects file upload. To upload large files, this value must be larger than upload_max_filesize |
upload_max_filesize | 50M | Maximum size of an uploaded file. |
max_input_vars | 5000 | Maximum number of input variables allowed per request, set to at least 5000 |
opcache_jit_buffer_size | 64M | Amount of shared memory to reserve for compiled JIT code, set to 0 to disable the JIT |
opcache_jit | 1235 | Configure the JIT mode (default value inherited from base image) |
opcache_memory_consumption | 128 | Size of the shared memory storage used by OPcache in megabytes (default value inherited from base image) |
SESSION_CACHE_TYPE | Optionally sets shared session cache store: memcached, redis, database (leave it blank to keep unchanged) | |
SESSION_CACHE_HOST | Hostname of the external cache store, required for memcached and redis | |
SESSION_CACHE_PORT | Memcached=11211, Redis=6379, required for memcached and redis | |
SESSION_CACHE_PREFIX | mdl | Cache prefix |
SESSION_CACHE_AUTH | Authentication key for cache store, may be required for redis | |
AUTO_UPDATE_MOODLE | true | Set to false to disable performing update of Moodle (e.g. plugins) at docker start |
UPDATE_MOODLE_CODE | true | Set to false to disable auto download latest patch of Moodle core code, only effective if AUTO_UPDATE_MOODLE is true or built with ARG_ENABLE_GIT_CLONE as true |
DISABLE_WEB_INSTALL_PLUGIN | false | Set to true to disable plugin installation via site admin UI, could be useful to avoid image outsync with HA setting |
MAINT_STATUS_KEYWORD | Status: enabled | Keyword for detecting Moodle maintenance status when running admin/cli/maintenance.php, language following the Moodle site default language |
LOCAL_CACHE_DIRECTORY | Set the path to a local fast filesystem for Moodle local caching that no need to be shared with other instances | |
SKIP_MOODLE_CONFIG | false | Set to true to skip the Moodle configuration script |
More settings on PHP and NGINX can refer to the base image https://github.com/jimsihk/alpine-php-nginx/blob/dev/README.md
If set to true
, Moodle will be set to CLI maintenance mode at container start while performing the update. No user will be able to use Moodle, not even admin.
If a cluster of Moodle containers are deployed for HA (e.g. on Kubernetes), it is suggested to set both to false
to avoid unexpected interruption to users when auto scaling, such as adding extra containers to the cluster or container restart for auto healing.
- For installing plugins while building the main Dockerfile (slower), use
ARG_MOODLE_PLUGIN_LIST
:
docker buildx build . -t my_moodle_image:my_tag \
--build-arg ARG_MOODLE_PLUGIN_LIST='mod_attendance mod_checklist mod_customcert block_checklist gradeexport_checklist'
- For building only to install additional moodle plugins (faster), create a Dockerfile like the following and then build.
- Example of
Dockerfile.plugins
:
# Dockerfile.plugins
FROM quay.io/jimsihk/alpine-moodle:latest
# Install additional plugins, a space/comma separated arg, (optional)
# Run install-plugin-list with argument "-f" to force install
# if the plugin is not compatible with current Moodle version
ARG ARG_MOODLE_PLUGIN_LIST=''
ENV MOODLE_PLUGIN_LIST=${ARG_MOODLE_PLUGIN_LIST}
RUN if [ -n "${MOODLE_PLUGIN_LIST}" ]; then /usr/libexec/moodle/install-plugin-list -p "${MOODLE_PLUGIN_LIST}"; fi && \
rm -rf /tmp/moodle-plugins
- Since v4.2.1.02-2 (402.102.2), this could be further simplified into:
# Dockerfile.plugins
FROM quay.io/jimsihk/alpine-moodle:latest
# Install additional plugins, a space/comma separated arg, (optional)
ARG ARG_MOODLE_PLUGIN_LIST=''
ENV MOODLE_PLUGIN_LIST=${ARG_MOODLE_PLUGIN_LIST}
RUN /usr/libexec/moodle/download-moodle-plugin
- Example of build using
Dockerfile.plugins
:
# Build
docker buildx build . -t my_moodle_image:my_tag \
-f Dockerfile.plugins \
--build-arg ARG_MOODLE_PLUGIN_LIST='mod_attendance,mod_checklist,mod_customcert,block_checklist,gradeexport_checklist'
- Since v4.2.1.02-2 (402.102.2),
ARG_ALLOW_INCOMPATIBLE_PLUGIN
is also available to easily control if continue the installation of latest available version despite lack of compatibility from maturity, default asfalse
:
docker buildx build . -t my_moodle_image:my_tag \
--build-arg ARG_MOODLE_PLUGIN_LIST='mod_attendance mod_checklist mod_customcert block_checklist gradeexport_checklist' \
--build-arg ARG_ALLOW_INCOMPATIBLE_PLUGIN='true'
- Or using a custom
Dockerfile.plugins
:
# Dockerfile.plugins
FROM quay.io/jimsihk/alpine-moodle:latest
ARG ARG_MOODLE_PLUGIN_LIST='mod_attendance mod_checklist mod_customcert block_checklist gradeexport_checklist'
ARG ARG_ALLOW_INCOMPATIBLE_PLUGIN='true'
ENV MOODLE_PLUGIN_LIST=${ARG_MOODLE_PLUGIN_LIST}
ENV ALLOW_INCOMPATIBLE_PLUGIN=${ARG_ALLOW_INCOMPATIBLE_PLUGIN}
RUN /usr/libexec/moodle/download-moodle-plugin
Unable to Create/Update Moodle Roles with "Incorrect role short name" (erseco#26)
Workaround: install Moosh and use therole-update-capability
command, but beware that only version 0.39 of the plugin has this command- FIXED since release v4.1.2.07-1 (401.207.1)
- Plugin installation adopted from Krestomatio