{"id":20912951,"url":"https://github.com/erseco/alpine-moodle","last_synced_at":"2025-10-07T01:56:45.432Z","repository":{"id":39592571,"uuid":"259988476","full_name":"erseco/alpine-moodle","owner":"erseco","description":"Moodle docker image based on Alpine Linux","archived":false,"fork":false,"pushed_at":"2025-10-01T21:58:43.000Z","size":208,"stargazers_count":58,"open_issues_count":4,"forks_count":40,"subscribers_count":6,"default_branch":"main","last_synced_at":"2025-10-01T23:33:34.671Z","etag":null,"topics":["alpine","docker","hacktoberfest","lightweight","lms","moodle","nginx","php8"],"latest_commit_sha":null,"homepage":"https://hub.docker.com/r/erseco/alpine-moodle","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/erseco.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2020-04-29T17:02:22.000Z","updated_at":"2025-10-01T21:58:39.000Z","dependencies_parsed_at":"2025-02-28T06:13:14.101Z","dependency_job_id":"7616e4c2-cf89-4e69-89cd-aef0f28c75f5","html_url":"https://github.com/erseco/alpine-moodle","commit_stats":{"total_commits":144,"total_committers":7,"mean_commits":"20.571428571428573","dds":"0.18055555555555558","last_synced_commit":"8568a333febbb0702b541cf9452e3faf5d6708f8"},"previous_names":[],"tags_count":82,"template":false,"template_full_name":null,"purl":"pkg:github/erseco/alpine-moodle","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/erseco%2Falpine-moodle","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/erseco%2Falpine-moodle/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/erseco%2Falpine-moodle/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/erseco%2Falpine-moodle/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/erseco","download_url":"https://codeload.github.com/erseco/alpine-moodle/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/erseco%2Falpine-moodle/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278708025,"owners_count":26031932,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-06T02:00:05.630Z","response_time":65,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["alpine","docker","hacktoberfest","lightweight","lms","moodle","nginx","php8"],"created_at":"2024-11-18T14:34:18.837Z","updated_at":"2025-10-07T01:56:45.426Z","avatar_url":"https://github.com/erseco.png","language":"Shell","funding_links":[],"categories":["🛠️ Tools \u0026 Utilities","Shell"],"sub_categories":["Self-Hosted \u0026 VPS"],"readme":"# Moodle on Alpine Linux\n\n[![Docker Pulls](https://img.shields.io/docker/pulls/erseco/alpine-moodle.svg)](https://hub.docker.com/r/erseco/alpine-moodle/)\n![Docker Image Size](https://img.shields.io/docker/image-size/erseco/alpine-moodle)\n![nginx 1.26](https://img.shields.io/badge/nginx-1.26-brightgreen.svg)\n![php 8.3](https://img.shields.io/badge/php-8.3-brightgreen.svg)\n![moodle](https://img.shields.io/badge/moodle-configurable-yellow)\n![moosh 1.27](https://img.shields.io/badge/moosh-1.27-orange)\n![License MIT](https://img.shields.io/badge/license-MIT-blue.svg)\n![Build Status](https://github.com/erseco/alpine-moodle/actions/workflows/build.yml/badge.svg)\n\nA lightweight Moodle Docker image built on [Alpine Linux](https://alpinelinux.org/). (~100MB)\n\nRepository: https://github.com/erseco/alpine-moodle\n\n**Key Features**\n\n- Built on the lightweight image https://github.com/erseco/alpine-php-webserver\n- Compact Docker image size (~100MB)\n- Uses PHP 8.3 FPM for better performance, lower cpu usage \u0026 memory footprint\n- Includes Composer.\n- Supports Moodle \u003c5.1 and \u003e=5.1 (detects /public directory automatically).\n- Includes Redis session handler support.\n- Includes [Moosh CLI](https://github.com/tmuras/moosh) for Moodle management.\n- Configurable via environment variables (see Dockerfile).\n- Support for HA installations: php-redis, php-ldap (also with self-signed certs)\n- Multi-arch support: 386, amd64, arm/v6, arm/v7, arm64, ppc64le, s390x\n- Optimized for 100 concurrent users\n- Optimized to only use resources when there's traffic (by using PHP-FPM's ondemand PM)\n- Uses `runit` instead of `supervisord` to reduce memory footprint\n- Cron jobs run every 180 seconds by runit\n- Sample `docker compose.yml` with PostgreSQL and Redis\n- Configuration via `ENV` variables\n- Services (`Nginx`, `PHP-FPM` run under a non-privileged user (`nobody`) for improved security\n- Logs are sent to container's STDOUT (`docker logs -f \u003ccontainer\u003e`)\n- Extensible via pre/post configuration hooks  \n- Follows the KISS principle (Keep It Simple, Stupid) to make it easy to understand and adjust the image to your needs\n\n## Important notes\n\n- **Change default credentials**: Always override `MOODLE_USERNAME` and `MOODLE_PASSWORD` with secure values.\n- **Moodle ≥ 5.1**: The script automatically reconfigures Nginx to serve files from `/public`.\n- **Moodle \u003c 5.1**: A compatibility patch is applied to `publicpaths.php` to support port mapping inside the container.\n\n### Upgrading from Moodle \u003c 5.1 to ≥ 5.1\n\nMoodle 5.1 introduces a new `/public` directory for all web-accessible files.\nIf you are upgrading from 5.0 or earlier:\n\n1. **Back up critical data**:\n   - `config.php`\n   - `moodledata/` directory\n   - Database dump\n2. **Clean old files**: Remove any remaining files under `/var/www/html/` to prevent stale or conflicting code.\n3. **Restore configuration**: Copy back `config.php` and custom plugins/themes to the new codebase.\n4. **Run dependencies**: The container will automatically execute `composer install` when `/public` is detected.\n\n\n## Usage\n\n**From Docker Hub:**\n```bash\ndocker compose up\n```\n\u003e Log in using the credentials defined by environment variables.\n\n**From GHCR:**\n```yaml\nservices:\n  moodle:\n    image: ghcr.io/erseco/alpine-moodle\n    # rest of your config\n```\n\n## Running Commands as Root\n\nIn certain situations, you might need to run commands as `root` within your Moodle container, for example, to install additional packages. You can do this using the `docker compose exec` command with the `--user root` option. Here's how:\n\n```bash\ndocker compose exec --user root moodle sh\n```\n\n## Configuration\nDefine the ENV variables in docker compose.yml file\n\n| Variable Name               | Default              | Description                                                                                    |\n|-----------------------------|----------------------|------------------------------------------------------------------------------------------------|\n| LANG                        | en_US.UTF-8          |                                                                                                |\n| LANGUAGE                    | en_US:en             |                                                                                                |\n| SITE_URL                    | http://localhost     | Sets the public site url                                                                       |\n| REVERSEPROXY                | false                | See [Reverse Proxy Configuration](#reverse-proxy-configuration). |\n| SSLPROXY                    | false                | See [Reverse Proxy Configuration](#reverse-proxy-configuration).                               |\n| REDIS_HOST                  |                      | Set the host of the redis instance. Ej. redis                                         |\n| DB_TYPE                     | pgsql                | mysqli - pgsql - mariadb                                                                       |\n| DB_HOST                     | postgres             | DB_HOST Ej. db container name                                                                  |\n| DB_PORT                     | 5432                 | Postgres=5432 - MySQL=3306                                                                     |\n| DB_NAME                     | moodle               |                                                                                                |\n| DB_USER                     | moodle               |                                                                                                |\n| DB_FETCHBUFFERSIZE          |                      | Set to 0 if using PostgresSQL poolers like PgBouncer in 'transaction' mode                     |\n| DB_DBHANDLEOPTIONS          | false                | Set to true if using PostgresSQL poolers like PgBouncer which does not support sending options |\n| DB_HOST_REPLICA             |                      | Database hostname of the read-only replica database                                            |\n| DB_PORT_REPLICA             |                      | Database port of replica, left it empty to be same as DB_PORT                                  |\n| DB_USER_REPLICA             |                      | Database login username of replica, left it empty to be same as DB_USER                        |\n| DB_PASS_REPLICA             |                      | Database login password of replica, left it empty to be same as DB_PASS                        |\n| DB_PREFIX                   | mdl_                 | Database prefix. WARNING: don't use numeric values or moodle won't start                       |\n| MY_CERTIFICATES             | none                 | Trusted LDAP certificate or chain getting through base64 encode                                |\n| MOODLE_EMAIL                | user@example.com     |                                                                                                |\n| MOODLE_LANGUAGE             | en                   |                                                                                                |\n| MOODLE_SITENAME             | New-Site             |                                                                                                |\n| MOODLE_USERNAME             | moodleuser           |                                                                                                |\n| MOODLE_PASSWORD             | PLEASE_CHANGEME      |                                                                                                |\n| SMTP_HOST                   | smtp.gmail.com       |                                                                                                |\n| SMTP_PORT                   | 587                  |                                                                                                |\n| SMTP_USER                   | your_email@gmail.com |                                                                                                |\n| SMTP_PASSWORD               | your_password        |                                                                                                |\n| SMTP_PROTOCOL               | tls                  |                                                                                                |\n| MOODLE_MAIL_NOREPLY_ADDRESS | noreply@localhost    |                                                                                                |\n| MOODLE_MAIL_PREFIX          | [moodle]             |                                                                                                |\n| AUTO_UPDATE_MOODLE          | true                 | Set to false to disable performing update of Moodle (e.g. plugins) at docker start             |\n| DEBUG                       | false                |                                                                                                |\n| client_max_body_size        | 50M                  |                                                                                                |\n| post_max_size               | 50M                  |                                                                                                |\n| upload_max_filesize         | 50M                  |                                                                                                |\n| max_input_vars              | 5000                 |                                                                                                |\n| PRE_CONFIGURE_COMMANDS      |                      | Commands to run before starting the configuration                                              |\n| POST_CONFIGURE_COMMANDS     |                      | Commands to run after finished the configuration                                               |\n| RUN_CRON_TASKS              | true                 | Set to false to disable the moodle cron job from running automatically                         |\n\n## Reverse Proxy Configuration\n\nWhen using a reverse proxy (e.g., Caddy, Traefik, nginx-proxy-manager) that handles SSL termination, you might encounter issues like missing CSS or a \"too many redirects\" error. This is a common problem and can be solved with the correct configuration.\n\n### The Problem\n\n1.  **Missing CSS:** If you set `SITE_URL` to your internal Docker IP (e.g., `http://172.19.0.1:89`), Moodle will generate URLs with this internal address. When your browser, accessing the site via `https://moodle.example.com`, tries to load these assets, it will block them due to mixed content (trying to load `http` content on an `https` page).\n\n2.  **`ERR_TOO_MANY_REDIRECTS`:** If you set `SITE_URL` to your public HTTPS address (e.g., `https://moodle.example.com`) but don't configure the proxy settings correctly, Moodle might get confused about the protocol and enter a redirect loop.\n\n### The Solution\n\nThe key is to tell Moodle that it's behind an SSL-terminating proxy. You can do this with the following environment variable settings:\n\n-   `SITE_URL`: Set this to your **public, external URL** with the `https` scheme (e.g., `https://moodle.example.com`).\n-   `REVERSEPROXY`: Set this to `false` for most reverse proxy setups. Set to `true` only if your Moodle site is intentionally accessible from multiple different base URLs (for example, if users access the site using different domain names or protocols). In a typical reverse proxy scenario where all users access Moodle through a single public URL, this should remain `false`. See [Moodle's documentation on reverse proxies](https://docs.moodle.org/en/Server_cluster) for more details.\n-   `SSLPROXY`: Set this to `true`. This tells Moodle to trust the `X-Forwarded-Proto` header from your proxy and understand that the connection is secure, even though the internal connection to the Docker container is over HTTP.\n\n### Example Configuration\n\nHere's an example of a `docker-compose.yml` file and a `Caddyfile` for a reverse proxy setup.\n\n**`docker-compose.yml`**\n\n```yaml\nservices:\n  moodle:\n    image: erseco/alpine-moodle\n    restart: unless-stopped\n    environment:\n      SITE_URL: https://moodle.example.com\n      REVERSEPROXY: \"false\"\n      SSLPROXY: \"true\"\n      # ... other environment variables\n    # No ports need to be exposed externally, as Caddy will connect\n    # to the container directly via the Docker network.\n    volumes:\n      - moodledata:/var/www/moodledata\n      - moodlehtml:/var/www/html\n    depends_on:\n      - postgres\n\n  # ... other services (postgres, etc.)\n\nvolumes:\n  moodledata:\n  moodlehtml:\n```\n\n**`Caddyfile`**\n\n```caddy\nmoodle.example.com {\n    reverse_proxy moodle:8080 {\n        header_up Host {host}\n        header_up X-Forwarded-Proto {scheme}\n        header_up X-Forwarded-For {remote}\n    }\n}\n```\n\nBy using this configuration, you can avoid the common pitfalls of running Moodle behind a reverse proxy. For more details, see issue [#101](https://github.com/erseco/alpine-moodle/issues/101).\n\n## Minimal docker-compose.yml example\n\n```yaml\n---\nservices:\n  postgres:\n    image: postgres:alpine\n    restart: unless-stopped\n    environment:\n      - POSTGRES_PASSWORD=moodle\n      - POSTGRES_USER=moodle\n      - POSTGRES_DB=moodle\n    volumes:\n      - postgres:/var/lib/postgresql/data\n  moodle:\n    image: erseco/alpine-moodle\n    restart: unless-stopped\n    environment:\n      MOODLE_USERNAME: moodleuser\n      MOODLE_PASSWORD: PLEASE_CHANGEME\n    ports:\n      - 80:8080\n    volumes:\n      - moodledata:/var/www/moodledata\n      - moodlehtml:/var/www/html\n    depends_on:\n      - postgres\nvolumes:\n  postgres: null\n  moodledata: null\n  moodlehtml: null\n```\n\n## Advanced Features\n\n### 1. Using Moosh CLI\n\nThis image includes [Moosh](https://github.com/tmuras/moosh) — a powerful CLI tool to manage Moodle installations. You can invoke any Moosh command using:\n\n```bash\ndocker compose exec moodle moosh \u003ccommand\u003e\n```\n\nExamples:\n\n#### Upgrade plugin list (required to install)\n```bash\ndocker compose exec moodle moosh plugin-list\n```\n\n#### Install a Plugin by Name\n```bash\ndocker compose exec moodle moosh plugin-install mod_attendance\n```\n\n\u003e You can force the installation of unsupported plugins with the `--force` option. \n\n\u003e NOTE:[There is a bug in moosh and the first installation is not working](https://github.com/tmuras/moosh/issues/520), so we recommend calling again the install function with the `--delete` flag option or use the `module-reinstall` option: eg: `docker compose exec moodle moosh plugin-install --delete theme_almondb` or call `docker compose exec moodle moosh module-reinstall theme_almondb`\n#### Backup a Course\n\nBackup course with provided id. By default, logs and grade histories are excluded.\n\nExample: Backup course id=3 into default .mbz file in `/opt/moosh/` directory from container:\n\n```bash\ndocker compose exec moodle moosh course-backup 3\n```\n\n#### Create a User\n\nCreate a new Moodle user. Provide one or more arguments to create one or more users.\n\nExample: create user \"testuser\" with the all the optional values\n\n\n```bash\ndocker compose exec moodle moosh user-create --password pass --email me@example.com --digest 2 --city Valverde --country ES --institution \"IES Garoé\" --department \"Technology\" --firstname \"first name\" --lastname name testuser\n```\n\n#### Delete a User\n\nDelete user(s) from Moodle. Provide one or more usernames as arguments.\nExample: delete user testuser\n\n```bash\ndocker compose exec moodle moosh user-delete testuser\n```\n\nThese examples can be included directly in `POST_CONFIGURE_COMMANDS` to automate plugin installation, backups, or any Moosh-supported functionality.\n\nUsing Moosh promotes the DRY (Don't Repeat Yourself) principle and leverages a powerful toolset for Moodle administration.\n\nFor the full list of commands, visit: https://moosh-online.com/commands/\n\n\n### 2. Pre/Post Configuration Hooks\n\nYou can define commands to be executed before and after the configuration of Moodle using the `PRE_CONFIGURE_COMMANDS` and `POST_CONFIGURE_COMMANDS` environment variables. These can be useful for tasks such as installing additional packages or running scripts.\n\n```yaml\nenvironment:\n  PRE_CONFIGURE_COMMANDS: \"cat config-dist.php\"\n  POST_CONFIGURE_COMMANDS: |\n    moosh plugin-list\n    moosh plugin-install --delete theme_almondb\n    moosh plugin-install --delete theme_almondb\n```\n\n### 3. Specifying a Moodle Version\n\nCalling `docker compose build` uses the latest version of Moodle from the main branch. If you need to use a specific Moodle version, you can specify it using the `MOODLE_VERSION` build argument.\n\nTo use a specific version, edit the build section for the moodle service in your docker compose.yml file:\n\n```yaml\nmoodle:\n  image: erseco/alpine-moodle\n  build:\n    context: .\n    args:\n      MOODLE_VERSION: v4.5.3  # Replace with your desired version\n```\nYou can find the list of available version tags at: https://github.com/moodle/moodle/tags\n\n\n### 4. Enabling Test Scenario Generator\n\nMoodle includes a tool to create [test scenarios](https://moodledev.io/general/development/tools/generator#create-a-testing-scenario-using-behat-generators) under `Admin \u003e Development \u003e Create testing scenarios`. To enable it, run the following command, or add it in `POST_CONFIGURE_COMMANDS`:\n\n```bash\nphp admin/tool/generator/cli/runtestscenario.php\n```\n\nThis tool allows generating all necessary elements for manual testing using `.feature` file syntax.\n\n## Maintenance Tips\n\n**Install Additional Alpine Packages (as root):**\n```bash\ndocker compose exec --user root moodle sh -c \"apk update \u0026\u0026 apk add nano\"\n```\n\n**Manual Database Upgrade:**\n```bash\ndocker compose exec moodle php admin/cli/upgrade.php\n```\n\n**Access Logs:**\n```bash\ndocker compose logs -f moodle\n```\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ferseco%2Falpine-moodle","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ferseco%2Falpine-moodle","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ferseco%2Falpine-moodle/lists"}