Skip to content

Deploying an IOMAD App

Introduction

IOMAD is an open-source multi-tenant LMS built on Moodle. Deploying IOMAD with a Dockerfile on Klutch.sh gives you reproducible builds, managed secrets, and durable storage for course content and user uploads—all managed from klutch.sh/app. This guide covers installation, repository prep, a production-ready Dockerfile, deployment steps, Nixpacks overrides, and best practices for enterprise learning environments.


Prerequisites

  • A Klutch.sh account (create one)
  • A GitHub repository containing your IOMAD/Moodle code (GitHub is the only supported git source)
  • Docker and PHP familiarity (IOMAD typically uses PHP-FPM/Apache with MySQL or MariaDB)
  • Database credentials (MySQL/MariaDB) and optional Redis cache endpoint
  • Optional object storage for large file backups

For basics on connecting GitHub, review the Quick Start.


Architecture and ports

  • Serve IOMAD over HTTP; set the internal container port to 8080.
  • Run MySQL/MariaDB (and Redis if used) as separate Klutch.sh TCP apps. Expose them on port 8000 and connect internally on their native ports (3306 for MySQL/MariaDB, 6379 for Redis).
  • Persistent storage is required for moodledata and recommended for logs.

Repository layout

iomad/
├── config.php.example # Template config
├── moodledata/ # Must be on persistent storage
├── local/ # Custom plugins
├── theme/ # Custom themes
├── Dockerfile # Must be at repo root for auto-detection
├── composer.json # If using Composer-managed plugins
└── README.md

Keep secrets out of Git; manage them via Klutch.sh environment variables.


Installation (local) and starter commands

Install dependencies and run IOMAD locally before pushing to GitHub:

Terminal window
php admin/cli/checks.php
php admin/cli/install.php --chmod=2770 \
--lang=en \
--wwwroot=http://localhost:8080 \
--dataroot=/var/www/html/moodledata \
--dbtype=mysqli --dbhost=localhost --dbname=iomad --dbuser=iomad --dbpass=secret \
--fullname="IOMAD" --shortname="IOMAD" --adminuser=admin --adminpass=AdminPass123!
php -S 0.0.0.0:8080 -t .

Optional helper start.sh for portability and Nixpacks fallback:

#!/usr/bin/env bash
set -euo pipefail
php admin/cli/upgrade.php --non-interactive
exec php -S 0.0.0.0:8080 -t .

Make it executable with chmod +x start.sh.


Dockerfile for IOMAD (production-ready)

Place this Dockerfile at the repository root; Klutch.sh auto-detects it (no Docker selection in the UI):

FROM php:8.2-apache
RUN apt-get update && apt-get install -y \
libpng-dev libjpeg-dev libfreetype6-dev libzip-dev libicu-dev libxml2-dev libonig-dev \
ghostscript graphviz aspell git unzip && \
docker-php-ext-configure gd --with-freetype --with-jpeg && \
docker-php-ext-install gd intl zip mysqli opcache soap xml && \
a2enmod rewrite && \
rm -rf /var/lib/apt/lists/*
WORKDIR /var/www/html
# Copy application
COPY . /var/www/html
# Moodle/IOMAD needs a writable dataroot; keep it on a volume
RUN mkdir -p /var/www/html/moodledata && chown -R www-data:www-data /var/www/html
ENV APACHE_DOCUMENT_ROOT=/var/www/html \
MOODLE_DOCKER_WWWROOT=/var/www/html \
PORT=8080
EXPOSE 8080
CMD ["apache2-foreground"]

Notes:

  • Pin PHP and extension versions to match your IOMAD release.
  • If you front with Nginx + PHP-FPM, swap the base image and keep EXPOSE 8080 consistent.

Environment variables (Klutch.sh)

Set these in the Klutch.sh app settings (Secrets tab) before deploying:

  • PORT=8080
  • MOODLE_DOCKER_WWWROOT=/var/www/html
  • MOODLE_DOCKER_DATAROOT=/var/www/html/moodledata
  • DB_TYPE=mysqli
  • DB_HOST
  • DB_PORT=3306
  • DB_NAME
  • DB_USER
  • DB_PASS
  • SSLPROXY=true (if terminating TLS before the app)
  • REDIS_HOST and REDIS_PORT (if using Redis)
  • PHP_MEMORY_LIMIT=512M (optional)

If you deploy without a Dockerfile and want Nixpacks overrides:

  • NIXPACKS_BUILD_CMD=composer install --no-dev --optimize-autoloader
  • NIXPACKS_START_CMD=php -S 0.0.0.0:8080 -t .
  • NIXPACKS_INSTALL_PKGS="php82 php82Extensions.pdo_mysql php82Extensions.intl php82Extensions.gd php82Extensions.zip"

These keep IOMAD compatible with the Nixpacks build pipeline when a Dockerfile is absent.


Attach persistent volumes

In Klutch.sh storage settings, add mount paths and sizes (no volume names required):

  • /var/www/html/moodledata — mandatory for file storage, cache, and sessions.
  • /var/www/html/theme — optional if you manage custom themes at runtime.
  • /var/www/html/local — optional for runtime-installed plugins.

Ensure these paths are writable by the web user inside the container.


Deploy IOMAD on Klutch.sh (Dockerfile workflow)

  1. Push your repository (with the Dockerfile at the root) to GitHub.
  2. Open klutch.sh/app, create a project, and add an app.
  3. Connect the GitHub repository; Klutch.sh automatically detects the Dockerfile.
  4. Choose HTTP traffic for IOMAD.
  5. Set the internal port to 8080.
  6. Add the environment variables above (database, Redis, Moodle/IOMAD settings, and any NIXPACKS_* overrides if you temporarily deploy without the Dockerfile).
  7. Attach persistent volumes for moodledata (and theme/local if needed), choosing sizes that fit your content.
  8. Deploy. Your LMS will be reachable at https://example-app.klutch.sh; attach a custom domain if desired.

For MySQL/MariaDB or Redis on Klutch.sh, create separate TCP apps, expose them on port 8000, and point DB_HOST or REDIS_HOST to those endpoints (internal ports 3306/6379).


Health checks and production tips

  • Add a lightweight /health endpoint or use Moodle’s built-in status checks for monitoring.
  • Back up the database and moodledata regularly; do not rely on container filesystems for durability.
  • Pin PHP and dependency versions; avoid unexpected upgrades between deploys.
  • Enable HTTPS at the edge; set SSLPROXY=true when traffic is terminated before reaching the app.
  • Monitor disk usage on volumes and resize before they fill.

IOMAD on Klutch.sh combines reproducible Docker builds with managed secrets, persistent volumes for moodledata, and flexible HTTP/TCP routing. With the Dockerfile at the repo root and ports set to 8080 for the app (8000 externally for TCP databases or caches), you can deliver multi-tenant learning experiences reliably without extra YAML or workflow overhead.