Moodle es la plataforma de aprendizaje (LMS) de código abierto más utilizada en centros educativos y empresas: cursos, tareas, cuestionarios, calificaciones y foros en una aplicación PHP. En este tutorial instalarás Moodle 5.2 en Ubuntu 24.04 con Nginx, PHP-FPM 8.3 y MariaDB, lo descargarás con Git para poder actualizarlo fácilmente, lo publicarás con HTTPS y dejarás configurados el cron y las copias de seguridad.

Requisitos previos

Para seguir esta guía necesitas:

  • Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath, con al menos 2 vCPU, 4 GB de RAM y 30 GB de disco. El espacio que necesites crecerá con los archivos que suban profesores y alumnos.
  • Un usuario no root con privilegios sudo.
  • Un dominio o subdominio (en esta guía, moodle.example.com) con un registro DNS A que apunte a la IP del servidor. Sustituye moodle.example.com por tu dominio en todos los pasos.
  • Los puertos 80 y 443 abiertos.

Moodle 5.2 requiere PHP 8.3 y MariaDB 10.11 o posterior (o MySQL 8.4, o PostgreSQL 16). Ubuntu 24.04 incluye exactamente PHP 8.3 y MariaDB 10.11, así que todo sale de los repositorios oficiales de la distribución.

Paso 1: Instalar Nginx, PHP y MariaDB

Instala el servidor web, PHP-FPM con las extensiones que Moodle exige, MariaDB y Git:

sudo apt update
sudo apt install -y nginx mariadb-server git php8.3-fpm php8.3-mysql php8.3-xml php8.3-mbstring php8.3-curl php8.3-zip php8.3-gd php8.3-intl php8.3-soap

Las extensiones sodium, openssl, iconv, ctype, fileinfo y opcache ya vienen incluidas en los paquetes base de PHP en Ubuntu. Comprueba que las principales están cargadas:

php -m | grep -E '^(curl|gd|intl|mbstring|mysqli|sodium|soap|xml|zip)$'
curl
gd
intl
mbstring
mysqli
soap
sodium
xml
zip

Si usas UFW, abre HTTP y HTTPS:

sudo ufw allow 'Nginx Full'

Paso 2: Ajustar PHP para Moodle

Moodle exige que max_input_vars sea al menos 5000, y los formularios de subida necesitan límites mayores que los predeterminados. Edita el php.ini de PHP-FPM:

sudo nano /etc/php/8.3/fpm/php.ini

Busca y ajusta estas directivas (quita el ; inicial de max_input_vars):

max_input_vars = 5000
memory_limit = 256M
upload_max_filesize = 100M
post_max_size = 100M
max_execution_time = 300

Los scripts de línea de comandos de Moodle (instalación, cron, actualizaciones) usan el php.ini de la CLI, que también debe cumplir el requisito de max_input_vars:

sudo nano /etc/php/8.3/cli/php.ini
max_input_vars = 5000

Reinicia PHP-FPM y comprueba el valor:

sudo systemctl restart php8.3-fpm
php -r 'echo ini_get("max_input_vars"), PHP_EOL;'
5000

Paso 3: Crear la base de datos

Ejecuta el script de seguridad de MariaDB para eliminar usuarios anónimos y la base de datos de pruebas. En Ubuntu, root se autentica por socket y puedes mantenerlo así:

sudo mariadb-secure-installation

Abre la consola de MariaDB:

sudo mariadb

Crea la base de datos con el juego de caracteres utf8mb4, que Moodle necesita para emojis y alfabetos completos, y un usuario exclusivo. Sustituye your_strong_password por una contraseña robusta:

CREATE DATABASE moodle DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'moodle'@'localhost' IDENTIFIED BY 'your_strong_password';
GRANT ALL PRIVILEGES ON moodle.* TO 'moodle'@'localhost';
FLUSH PRIVILEGES;
EXIT;

Comprueba el acceso:

mariadb -u moodle -p -e "SHOW DATABASES;"
+--------------------+
| Database           |
+--------------------+
| information_schema |
| moodle             |
+--------------------+

Paso 4: Descargar Moodle con Git

Clonar la rama estable desde Git es el método que recomienda Moodle para servidores propios, porque las actualizaciones menores se reducen a un git pull. Clona solo la rama MOODLE_502_STABLE:

sudo git clone --branch MOODLE_502_STABLE --depth 1 https://github.com/moodle/moodle.git /var/www/moodle

Desde Moodle 5.1, el código que debe servirse por web está en el subdirectorio public; el resto (incluido config.php y las herramientas de línea de comandos en admin/cli) queda fuera de la raíz web. Compruébalo:

ls /var/www/moodle
CONTRIBUTING.md  COPYING.txt  Gruntfile.js  INSTALL.txt  README.md  TRADEMARK.txt  UPGRADING.md  admin  composer.json  composer.lock  config-dist.php  index.php  lib  npm-shrinkwrap.json  package.json  phpcs.xml.dist  phpunit.xml.dist  public  scripts  tsconfig.json

Crea el directorio de datos (moodledata), donde Moodle guarda los archivos subidos, la caché y las sesiones. Debe estar fuera de la raíz web y ser escribible por www-data:

sudo mkdir -p /var/moodledata
sudo chown -R www-data:www-data /var/moodledata
sudo chmod 750 /var/moodledata

El código pertenece a root, así que PHP no puede modificarlo:

sudo chown -R root:root /var/www/moodle

Paso 5: Configurar Nginx

Crea el bloque de servidor:

sudo nano /etc/nginx/sites-available/moodle
server {
    listen 80;
    listen [::]:80;
    server_name moodle.example.com;

    root /var/www/moodle/public;
    index index.php;

    client_max_body_size 100M;

    location / {
        try_files $uri $uri/ /r.php;
    }

    # Moodle usa PATH_INFO en URLs como /pluginfile.php/...
    location ~ [^/]\.php(/|$) {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_index index.php;
        fastcgi_pass unix:/run/php/php8.3-fpm.sock;
        include fastcgi_params;
        fastcgi_param PATH_INFO $fastcgi_path_info;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }

    location ~ /\. {
        deny all;
    }
}

La regla try_files ... /r.php envía al enrutador de Moodle las rutas que no son archivos reales, y el bloque de PHP pasa PATH_INFO, que Moodle usa para servir archivos. Activa el sitio, desactiva el de por defecto y recarga:

sudo ln -s /etc/nginx/sites-available/moodle /etc/nginx/sites-enabled/
sudo rm /etc/nginx/sites-enabled/default
sudo nginx -t
sudo systemctl reload nginx

Paso 6: Activar HTTPS con Let's Encrypt

Obtén el certificado antes de instalar Moodle, porque la dirección del sitio (wwwroot) se fija durante la instalación y conviene que sea https:// desde el principio:

sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d moodle.example.com

Comprueba la renovación automática:

sudo certbot renew --dry-run
Congratulations, all simulated renewals succeeded:
  /etc/letsencrypt/live/moodle.example.com/fullchain.pem (success)

Paso 7: Instalar Moodle desde la línea de comandos

El instalador de línea de comandos crea config.php y todas las tablas sin los tiempos de espera del navegador. Necesita escribir config.php en /var/www/moodle, así que da permiso de escritura temporal a www-data solo sobre ese directorio (sin -R):

sudo chown www-data /var/www/moodle

Ejecuta el instalador como www-data. Sustituye las contraseñas, el nombre del sitio y el correo por los tuyos; your_admin_password será la contraseña del usuario admin de Moodle:

sudo -u www-data php /var/www/moodle/admin/cli/install.php \
  --lang=es \
  --wwwroot=https://moodle.example.com \
  --dataroot=/var/moodledata \
  --dbtype=mariadb \
  --dbhost=localhost \
  --dbname=moodle \
  --dbuser=moodle \
  --dbpass='your_strong_password' \
  --fullname='Campus virtual' \
  --shortname='Campus' \
  --adminuser=admin \
  --adminpass='your_admin_password' \
  [email protected] \
  --agree-license \
  --non-interactive

La instalación tarda varios minutos: descarga el paquete de idioma español, crea las tablas e instala los plugins. Termina con un mensaje de instalación completada; si falla, el propio instalador indica qué requisito no se cumple.

Devuelve el directorio a root y protege config.php, que contiene la contraseña de la base de datos:

sudo chown root:root /var/www/moodle
sudo chown root:www-data /var/www/moodle/config.php
sudo chmod 640 /var/www/moodle/config.php

Como Nginx ya reenvía las rutas al enrutador, indícaselo a Moodle para que genere URL sin r.php. Edita config.php:

sudo nano /var/www/moodle/config.php

Añade esta línea antes de require_once(__DIR__ . '/lib/setup.php');:

$CFG->routerconfigured = true;

Abre https://moodle.example.com e inicia sesión con admin y la contraseña que elegiste. Ve a Administración del sitio > Servidor > Entorno para comprobar que todos los requisitos aparecen en verde.

Paso 8: Configurar el cron de Moodle

Moodle depende de su cron para enviar notificaciones y correos, procesar tareas en segundo plano, limpiar la caché y ejecutar las copias automáticas de cursos. Debe ejecutarse cada minuto como www-data:

echo '* * * * * www-data /usr/bin/php /var/www/moodle/admin/cli/cron.php > /dev/null 2>&1' | sudo tee /etc/cron.d/moodle

Ejecútalo una vez a mano para verificar que funciona:

sudo -u www-data php /var/www/moodle/admin/cli/cron.php
Server Time: Fri, 25 Sep 2026 11:15:01 +0000

Execute scheduled task: ...
Cron run completed correctly

Al cabo de unos minutos, la página Administración del sitio > Notificaciones deja de mostrar el aviso de que el cron no se ha ejecutado.

Paso 9: Configurar el correo saliente

Sin un servidor SMTP, Moodle intenta enviar correo con la función mail() de PHP, que en la mayoría de servidores no funciona. Ve a Administración del sitio > Servidor > Correo electrónico > Configuración de correo saliente y rellena:

  • Servidores SMTP: smtp.your_provider.com:587.
  • Seguridad SMTP: TLS.
  • Nombre de usuario y contraseña SMTP.
  • Dirección de no respuesta: por ejemplo, [email protected], en un dominio con SPF y DKIM configurados.

En la misma sección está la opción Probar la configuración del correo saliente para enviar un mensaje de prueba.

Paso 10: Programar copias de seguridad

Una copia completa de Moodle requiere la base de datos, el directorio moodledata y config.php. Crea un script:

sudo nano /usr/local/sbin/moodle-backup
#!/usr/bin/env bash
set -euo pipefail

backup_dir="/var/backups/moodle"
stamp="$(date +%Y%m%d-%H%M%S)"

mkdir -p "$backup_dir"

# Modo mantenimiento para que los datos sean coherentes
php /var/www/moodle/admin/cli/maintenance.php --enable

# Reactivar el sitio aunque falle un paso
trap 'php /var/www/moodle/admin/cli/maintenance.php --disable' EXIT

mariadb-dump --single-transaction --default-character-set=utf8mb4 moodle \
  | gzip > "$backup_dir/moodle-db-$stamp.sql.gz"

# La caché y los archivos temporales se regeneran solos
tar -czf "$backup_dir/moodle-data-$stamp.tar.gz" \
  --exclude='cache' --exclude='localcache' --exclude='temp' --exclude='sessions' \
  -C /var moodledata

cp /var/www/moodle/config.php "$backup_dir/config-$stamp.php"

find "$backup_dir" -type f -name 'moodle-*' -mtime +7 -delete
find "$backup_dir" -type f -name 'config-*' -mtime +7 -delete

El script se ejecuta como root, que accede a MariaDB por socket sin contraseña. Hazlo ejecutable, pruébalo y prográmalo para las 3:00, cuando menos uso suele haber:

sudo chmod 750 /usr/local/sbin/moodle-backup
sudo /usr/local/sbin/moodle-backup
sudo ls -lh /var/backups/moodle
echo '0 3 * * * root /usr/local/sbin/moodle-backup' | sudo tee /etc/cron.d/moodle-backup
-rw-r----- 1 root root 5.0K Sep 25 11:30 config-20260925-113000.php
-rw-r--r-- 1 root root  22M Sep 25 11:30 moodle-data-20260925-113000.tar.gz
-rw-r--r-- 1 root root 6.4M Sep 25 11:30 moodle-db-20260925-113000.sql.gz

Copia /var/backups/moodle a otro servidor con regularidad. Las copias de cursos individuales se gestionan aparte, desde Administración del sitio > Cursos > Copia de seguridad.

Paso 11: Actualizar Moodle

Las versiones menores de la rama 5.2 se publican en la misma rama de Git. Para actualizar, haz una copia de seguridad, descarga los cambios y ejecuta el actualizador:

sudo /usr/local/sbin/moodle-backup
cd /var/www/moodle
sudo git pull
sudo -u www-data php admin/cli/upgrade.php --non-interactive

Si el actualizador no tiene nada que hacer, lo indicará y terminará sin cambios. Para una versión mayor (por ejemplo, 5.3), cambia a la rama nueva con git fetch y git checkout siguiendo las notas de actualización oficiales, y revisa antes que tus plugins sean compatibles.

Solución de problemas

El instalador o el entorno indican que falta una extensión de PHP. Instala el paquete php8.3-<extensión> correspondiente y reinicia php8.3-fpm.

Las imágenes o los archivos de los cursos no cargan. Suele faltar PATH_INFO. Revisa que el bloque location ~ [^/]\.php(/|$) tenga fastcgi_split_path_info y fastcgi_param PATH_INFO, y que Certbot lo haya conservado en el bloque HTTPS.

Error al escribir en moodledata. Comprueba que /var/moodledata pertenece a www-data y que el cron se ejecuta como www-data, no como root; si el cron se ejecutó como root, corrige la propiedad con sudo chown -R www-data:www-data /var/moodledata.

Conclusión

Tienes Moodle 5.2 funcionando en Ubuntu 24.04 con Nginx, PHP-FPM y MariaDB, servido por HTTPS, con el cron cada minuto, correo saliente y copias de seguridad diarias. Como siguientes pasos, crea las categorías y los cursos, configura el registro de usuarios o la autenticación con tu proveedor de identidad en Administración del sitio > Plugins > Autenticación, y valora añadir Redis como caché de sesiones cuando crezca el número de alumnos concurrentes.