# Moodle

**Moodle** (Modular Object-Oriented Dynamic Learning Environment) és una plataforma d'aprenentatge en línia de codi obert, més coneguda com a LMS (Learning Management System). Permet als docents crear cursos virtuals, gestionar activitats, avaluacions i comunicació amb l'alumnat.

![Moodle logo](https://proferamon.com/tic/imatges/moodle/moodle01.png)

Aquest document descriu el procés d'instal·lació de Moodle 5.2 sobre un servidor Ubuntu 26.04 LTS, utilitzant Apache 2 com a servidor web, MariaDB com a base de dades i PHP. La comunicació es fa xifrada mitjançant HTTPS amb un certificat autosignat.

# 1. Requisits del sistema

## 1.1. Maquinari recomanat

| Component | Mínim recomanat |
|-----------|----------------|
| Processador | 2 nuclis (x86_64) |
| Memòria RAM | 2 GB (4 GB recomanat) |
| Emmagatzematge | 20 GB lliures per al sistema + espai per a fitxers de curs |
| Xarxa | Connexió a Internet per descarregar paquets |

## 1.2. Programari

| Programari | Versió |
|------------|--------|
| Sistema operatiu | Ubuntu 26.04 LTS |
| Servidor web | Apache 2 |
| Llenguatge | PHP 8.3 |
| Base de dades | MariaDB |
| Moodle | 5.2 (branca estable) |

# 2. Actualitza el sistema

Abans d'instal·lar qualsevol paquet, cal assegurar-se que el sistema està completament actualitzat per evitar conflictes de dependències.

Actualitza la llista de paquets:

```bash
sudo apt update
```

Actualitza els paquets instal·lats:

```bash
sudo apt upgrade
```

# 3. Configura del nom d'amfitrió

Estableix el nom curt:

```bash
sudo hostnamectl set-hostname moodle
```

Edita `/etc/hosts` per afegir l'FQDN:

```bash
sudo nano /etc/hosts
```

Afegeix:

```nano
10.0.2.10 moodle.thos.local moodle
```

Verifica la resolució:

```bash
hostname -f
```

Resposta esperada:

```ini
moodle.thos.local
```

# 4. Instal·la els paquets necessaris

En Ubuntu 26.04, i als seus dopòsits oficials només hi ha PHP 8.5, cap versió anterior. Per tenir PHP 8.3 (la recomanada per Moodle 5.x en el moment que s'escriu aquest document) necessites el PPA de tercers d'Ondřej Surý, que és l'estàndard de facto per mantenir múltiples versions de PHP a Ubuntu/Debian.

Instal·la els prerequisits per afegir un dipòsit APT extern:

```bash
sudo apt install apt-transport-https lsb-release ca-certificates curl gnupg
```

Descarrega i converteix la clau GPG del dipòsit Sury:

```bash
curl -fsSL https://packages.sury.org/php/apt.gpg | sudo gpg --dearmor -o /usr/share/keyrings/deb.sury.org-php.gpg
```

Registra el dipòsit Sury com a font de paquets APT, associant-lo a la clau GPG que acabes d'importar:

```bash
echo "deb [signed-by=/usr/share/keyrings/deb.sury.org-php.gpg] https://packages.sury.org/php/ $(lsb_release -sc) main" | sudo tee /etc/apt/sources.list.d/php.list
```

Actualitza la llista de paquets:

```bash
sudo apt update
```

Instal·la Apache, PHP 8.3 amb totes les extensions requerides per Moodle, MariaDB i eines addicionals:

```bash
sudo apt install apache2 php8.3 mariadb-server libapache2-mod-php8.3 \
  php8.3-mysql php8.3-curl php8.3-zip php8.3-xml php8.3-mbstring \
  php8.3-gd php8.3-intl php8.3-soap php8.3-ldap unzip php8.3-ctype \
  php8.3-dom php8.3-iconv php8.3-simplexml composer
```

Assegura MariaDB:

```bash
sudo mariadb-secure-installation
```

Respon afirmativament a totes les preguntes (establir contrasenya root, eliminar usuaris anònims, desactivar accés remot de root, eliminar la base de dades de test i recarregar privilegis).

## 4.1. Descripció dels paquets principals

| Paquet | Funció |
|--------|--------|
| `apache2` | Servidor web HTTP/HTTPS |
| `php8.3` | Intèrpret PHP |
| `mariadb-server` | Base de dades relacional (compatible MySQL) |
| `libapache2-mod-php8.3` | Mòdul PHP per a Apache |
| `php8.3-mysql` | Connector PHP ↔ MariaDB |
| `php8.3-gd` | Processament d'imatges |
| `php8.3-mbstring` | Suport per a caràcters multibyte (UTF-8) |
| `php8.3-xml / dom / simplexml` | Processament XML (requerit per Moodle) |
| `php8.3-intl` | Internacionalització i localització |
| `php8.3-ldap` | Autenticació contra servidors LDAP/AD |
| `php8.3-soap` | Serveis web SOAP |
| `unzip` | Descomprimir l'arxiu de Moodle |
| `composer` | Gestor de dependències PHP |

# 5. Descarrega i instal·la Moodle

## 5.1. Descarrega el paquet d'instal·lació

Descarrega la darrera versió estable de Moodle des del lloc oficial:

```bash
wget -c https://download.moodle.org/download.php/direct/stable502/moodle-latest-502.zip
```

## 5.2. Descomprimeix el paquet

Extreu el contingut directament al directori web d'Apache:

```bash
sudo unzip -q moodle-latest-502.zip -d /var/www/
```

## 5.3. Esborra el fitxer descarregat

Esborra el fitxer que ja no és necessari:

```bash
rm moodle-latest-502.zip
```

## 5.4. Crea el directori de dades

Moodle necessita un directori extern al DocumentRoot per emmagatzemar fitxers pujats, la cau i altres dades. Ha d'estar fora del directori accessible via web per motius de seguretat:

```bash
sudo mkdir /var/www/moodledata
```

> [!WARNING]
> El directori `moodledata` **NO** ha d'estar dins de `/var/www/html` ni ser accessible directament des del navegador, ja que conté dades confidencials dels usuaris.

## 5.5. Assigna permisos

El servidor web (Apache) s'executa amb l'usuari `www-data`. Cal donar-li la propietat dels directoris de Moodle i de dades:

```bash
sudo chown -R www-data:www-data /var/www/moodledata /var/www/moodle
```

# 6. Configura PHP

Moodle requereix que el paràmetre `max_input_vars` sigui superior al valor per defecte (1000) per gestionar correctament els formularis de configuració de cursos complexos. S'ha d'establir en 5000:

Edita el fitxer de configuració de PHP:

```bash
sudo nano -l /etc/php/8.3/apache2/php.ini
```

Modifica la línia 436. Descomenta i estableix el valor a 5000:

```nano
max_input_vars = 5000
```

Modifica la línia 1071. Descomenta i estableix el valor a 0:

```nano
pcre.jit=0
```

# 7. Crea la base de dades

Moodle necessita una base de dades i un usuari dedicat amb tots els permisos sobre aquesta. Accedeix a la consola de MariaDB com a `root`:

```bash
sudo mysql -u root -p
```

Dins de la consola SQL, crea la base de dades, l'usuari i assigna-li els privilegis necessaris:

```sql
CREATE DATABASE moodle CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
GRANT ALL PRIVILEGES ON moodle.* TO umoodle@localhost IDENTIFIED BY 'contrasenya';
FLUSH PRIVILEGES;
EXIT
```

> [!WARNING] 
> En un entorn de producció, substitueix `contrasenya` per una contrasenya segura. Recorda que haureu d'introduir-la durant l'assistent d'instal·lació web de Moodle.

# 8. Crea el certificat SSL autosignat

Per habilitar HTTPS, es genera un certificat autosignat vàlid per 365 dies. Això xifra la comunicació entre el client i el servidor, tot i que el navegador mostrarà un avís de seguretat donat que no està signat per una autoritat de certificació reconeguda.

```bash
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
  -keyout /etc/ssl/private/moodle-autosignat.key \
  -out /etc/ssl/certs/moodle-autosignat.crt \
  -subj "/C=ES/ST=Catalunya/L=Mataro/O=IES Thos i Codina/OU=SMX/CN=moodle.thos.local/emailAddress=ramon@thosicodina.cat"
```

# 9. Configura Apache

## 9.1. Crea la configuració HTTPS de Moodle

```bash
sudo nano /etc/apache2/sites-available/moodle-ssl.conf
```

```nano
<VirtualHost *:443>
	ServerAdmin webmaster@localhost
	ServerName moodle.thos.local
	DocumentRoot /var/www/moodle/public
	<Directory /var/www/moodle/public>
		AllowOverride All
		Require all granted
	</Directory>
	ErrorLog ${APACHE_LOG_DIR}/error.log
	CustomLog ${APACHE_LOG_DIR}/access.log combined
	SSLEngine on
	SSLCertificateFile      /etc/ssl/certs/moodle-autosignat.crt
	SSLCertificateKeyFile   /etc/ssl/private/moodle-autosignat.key
	<FilesMatch "\.(?:cgi|shtml|phtml|php)$">
		SSLOptions +StdEnvVars
	</FilesMatch>
	<Directory /usr/lib/cgi-bin>
		SSLOptions +StdEnvVars
	</Directory>
</VirtualHost>
```

## 9.2. Crea la configuració HTTP (redirecció)

```bash
sudo nano /etc/apache2/sites-available/moodle.conf
```

```nano
<VirtualHost *:80>
        ServerName moodle.thos.local
        Redirect permanent / https://moodle.thos.local/
</VirtualHost>
```

## 9.3. Habilita mòduls i llocs

Habilita els mòduls:

```bash
sudo a2enmod rewrite headers env dir mime ssl
```

Habilita les pàgines de Moodle:

```bash
sudo a2ensite moodle.conf moodle-ssl.conf
```

Verifica la configuració:

```bash
sudo apache2ctl configtest
```

Sortida esperada:

```ini
Syntax OK
```

## 9.4. Reinicia Apache i verifica

Reinicia Apache:

```bash
sudo systemctl restart apache2.service
```

Comprova l'estat:

```bash
sudo systemctl status apache2.service
```

Resposta esperada:

```ini
● apache2.service - The Apache HTTP Server
     Loaded: loaded (/usr/lib/systemd/system/apache2.service; enabled; preset: enabled)
     Active: active (running) since Wed 2026-07-08 12:42:59 UTC; 5s ago
 Invocation: 84093042a3504747b82bf98142b51952
       Docs: https://httpd.apache.org/docs/2.4/
   Main PID: 15810 (apache2)
     Status: "Processing requests..."
      Tasks: 6 (limit: 1718)
     Memory: 17.1M (peak: 17.1M)
        CPU: 58ms
     CGroup: /system.slice/apache2.service
             ├─15810 /usr/sbin/apache2 -k start -DFOREGROUND
             ├─15813 /usr/sbin/apache2 -k start -DFOREGROUND
             ├─15814 /usr/sbin/apache2 -k start -DFOREGROUND
             ├─15815 /usr/sbin/apache2 -k start -DFOREGROUND
             ├─15816 /usr/sbin/apache2 -k start -DFOREGROUND
             └─15817 /usr/sbin/apache2 -k start -DFOREGROUND

de jul. 08 12:42:59 moodle systemd[1]: Starting apache2.service - The Apache HTTP Server...
de jul. 08 12:42:59 moodle systemd[1]: Started apache2.service - The Apache HTTP Server.
```

# 10. Configuració des del navegador

Un cop finalitzats tots els passos anteriors, cal completar la instal·lació de Moodle mitjançant l'assistent web:

1-. Obre el navegador i accedeix a **https://moodle.thos.local**

2-. Si el navegador mostra un avís de seguretat pel certificat autosignat, fes clic a `Avançat` i accepta el risc per continuar.

![Avís](https://proferamon.com/tic/imatges/moodle/moodle02.png)

---

![Accepta el risc](https://proferamon.com/tic/imatges/moodle/moodle03.png)

3-. Tria l'idioma.

![Tria l'idioma](https://proferamon.com/tic/imatges/moodle/moodle04.png)

4-. Confirma el directori de dades: **/var/www/moodledata**

![Confirma el directori](https://proferamon.com/tic/imatges/moodle/moodle05.png)

5-. Selecciona el tipus de base de dades: **MariaDB (nativa / millor rendiment)**

![Controlador de base de dades](https://proferamon.com/tic/imatges/moodle/moodle06.png)

6-. Introdueix les dades de connexió a la base de dades:

   >- **Servidor de base de dades:** localhost
   >- **Nom de la base de dades:** moodle
   >- **Usuari de la base de dades:** umoodle
   >- **Contrasenya de la base de dades:** contrasenya

![Paràmetres de la base de dades](https://proferamon.com/tic/imatges/moodle/moodle07.png)

7-. En aquest punt torna al terminal i fes aquestes modificacions:

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

Abans de la línia 27 `require_once(__DIR__ . '/lib/setup.php');` escriu:

```nano
$CFG->routerconfigured = true;
```

Desplaça't a la carpeta de Moodle:

```bash
cd /var/www/moodle 
```

Instal·la les dependències PHP d'un projecte gestionat amb Composer (el gestor de paquets/dependències de PHP, equivalent a npm en Node o pip en Python), a partir del fitxer composer.json/composer.lock que hi ha al directori actual:

```bash
sudo composer install --no-dev --classmap-authoritative
```

```ini
Do not run Composer as root/super user! See https://getcomposer.org/root for details
Continue as root/super user [yes]? 
Composer could not detect the root package (moodle/moodle) version, defaulting to '1.0.0'. See https://getcomposer.org/root-version
Installing dependencies from lock file
Verifying lock file contents can be installed on current platform.
Package operations: 48 installs, 0 updates, 0 removals
  - Downloading adodb/adodb-php (v5.22.11)
  - Downloading psr/http-message (2.0)
  - Downloading symfony/polyfill-mbstring (v1.33.0)
  - Downloading mtdowling/jmespath.php (2.8.0)
  - Downloading ralouphie/getallheaders (3.0.3)
  - Downloading psr/http-factory (1.1.0)
  - Downloading guzzlehttp/psr7 (2.8.0)
  - Downloading guzzlehttp/promises (2.3.0)
  - Downloading symfony/deprecation-contracts (v3.6.0)
  - Downloading psr/http-client (1.0.3)
  - Downloading guzzlehttp/guzzle (7.10.0)
  - Downloading aws/aws-crt-php (v1.2.7)
  - Downloading aws/aws-sdk-php (3.356.22)
  - Downloading composer/pcre (3.3.2)
  - Downloading ezyang/htmlpurifier (v4.18.0)
  - Downloading firebase/php-jwt (v6.11.1)
  - Downloading composer/ca-bundle (1.5.10)
  - Downloading maxmind/web-service-common (v0.11.1)
  - Downloading maxmind-db/reader (v1.12.1)
  - Downloading geoip2/geoip2 (v3.2.0)
  - Downloading html2text/html2text (4.3.2)
  - Downloading kevinrob/guzzle-cache-middleware (7.0.0)
  - Downloading lbuchs/webauthn (v2.2.0)
  - Downloading maennchen/zipstream-php (3.2.0)
  - Downloading matthiasmullie/path-converter (1.1.3)
  - Downloading matthiasmullie/minify (1.3.75)
  - Downloading michelf/php-markdown (2.0.0)
  - Downloading psr/log (3.0.2)
  - Downloading monolog/monolog (3.9.0)
  - Downloading mustache/mustache (v3.0.0)
  - Downloading openspout/openspout (v4.28.5)
  - Downloading psr/container (2.0.2)
  - Downloading php-di/invoker (2.3.6)
  - Downloading laravel/serializable-closure (v2.0.10)
  - Downloading php-di/php-di (7.0.8)
  - Downloading phpmailer/phpmailer (v6.9.3)
  - Downloading phpxmlrpc/phpxmlrpc (4.11.1)
  - Downloading psr/cache (3.0.0)
  - Downloading psr/clock (1.0.0)
  - Downloading psr/event-dispatcher (1.0.0)
  - Downloading psr/simple-cache (3.0.0)
  - Downloading redeyeventures/geopattern (v1.1.2)
  - Downloading simplepie/simplepie (1.8.1)
  - Downloading psr/http-server-handler (1.0.2)
  - Downloading psr/http-server-middleware (1.0.2)
  - Downloading nikic/fast-route (v1.3.0)
  - Downloading slim/slim (4.13.0)
  - Downloading spatie/php-cloneable (1.0.2)
  - Installing adodb/adodb-php (v5.22.11): Extracting archive
  - Installing psr/http-message (2.0): Extracting archive
  - Installing symfony/polyfill-mbstring (v1.33.0): Extracting archive
  - Installing mtdowling/jmespath.php (2.8.0): Extracting archive
  - Installing ralouphie/getallheaders (3.0.3): Extracting archive
  - Installing psr/http-factory (1.1.0): Extracting archive
  - Installing guzzlehttp/psr7 (2.8.0): Extracting archive
  - Installing guzzlehttp/promises (2.3.0): Extracting archive
  - Installing symfony/deprecation-contracts (v3.6.0): Extracting archive
  - Installing psr/http-client (1.0.3): Extracting archive
  - Installing guzzlehttp/guzzle (7.10.0): Extracting archive
  - Installing aws/aws-crt-php (v1.2.7): Extracting archive
  - Installing aws/aws-sdk-php (3.356.22): Extracting archive
  - Installing composer/pcre (3.3.2): Extracting archive
  - Installing ezyang/htmlpurifier (v4.18.0): Extracting archive
  - Installing firebase/php-jwt (v6.11.1): Extracting archive
  - Installing composer/ca-bundle (1.5.10): Extracting archive
  - Installing maxmind/web-service-common (v0.11.1): Extracting archive
  - Installing maxmind-db/reader (v1.12.1): Extracting archive
  - Installing geoip2/geoip2 (v3.2.0): Extracting archive
  - Installing html2text/html2text (4.3.2): Extracting archive
  - Installing kevinrob/guzzle-cache-middleware (7.0.0): Extracting archive
  - Installing lbuchs/webauthn (v2.2.0): Extracting archive
  - Installing maennchen/zipstream-php (3.2.0): Extracting archive
  - Installing matthiasmullie/path-converter (1.1.3): Extracting archive
  - Installing matthiasmullie/minify (1.3.75): Extracting archive
  - Installing michelf/php-markdown (2.0.0): Extracting archive
  - Installing psr/log (3.0.2): Extracting archive
  - Installing monolog/monolog (3.9.0): Extracting archive
  - Installing mustache/mustache (v3.0.0): Extracting archive
  - Installing openspout/openspout (v4.28.5): Extracting archive
  - Installing psr/container (2.0.2): Extracting archive
  - Installing php-di/invoker (2.3.6): Extracting archive
  - Installing laravel/serializable-closure (v2.0.10): Extracting archive
  - Installing php-di/php-di (7.0.8): Extracting archive
  - Installing phpmailer/phpmailer (v6.9.3): Extracting archive
  - Installing phpxmlrpc/phpxmlrpc (4.11.1): Extracting archive
  - Installing psr/cache (3.0.0): Extracting archive
  - Installing psr/clock (1.0.0): Extracting archive
  - Installing psr/event-dispatcher (1.0.0): Extracting archive
  - Installing psr/simple-cache (3.0.0): Extracting archive
  - Installing redeyeventures/geopattern (v1.1.2): Extracting archive
  - Installing simplepie/simplepie (1.8.1): Extracting archive
  - Installing psr/http-server-handler (1.0.2): Extracting archive
  - Installing psr/http-server-middleware (1.0.2): Extracting archive
  - Installing nikic/fast-route (v1.3.0): Extracting archive
  - Installing slim/slim (4.13.0): Extracting archive
  - Installing spatie/php-cloneable (1.0.2): Extracting archive
Generating optimized autoload files
17 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
```

Continua amb l'assistent web.

8-. Llegeix i accepta els termes de la llicència.

![Llicència](https://proferamon.com/tic/imatges/moodle/moodle08.png)

9-. L'assistent comprovarà els requisits del sistema. Si tot és correcte, fes clic a `Continua`.

![Comprovacions del servidor](https://proferamon.com/tic/imatges/moodle/moodle09.png)

10-. Moodle instal·larà les taules de la base de dades. Això pot trigar uns minuts. Prem *Continua* en acabar.

![Creació de les taules](https://proferamon.com/tic/imatges/moodle/moodle10.png)

11-. Configura el compte d'administrador: nom, cognom, correu electrònic i contrasenya.

![Configura el compte d'administrador](https://proferamon.com/tic/imatges/moodle/moodle11.png)

12-. Configura les dades del lloc: nom, descripció i idioma per defecte.

![Configura les dades del lloc](https://proferamon.com/tic/imatges/moodle/moodle12.png)

13-. Configura el correu del compte de suport.

![Configura correu de suport](https://proferamon.com/tic/imatges/moodle/moodle13.png)

# 11. Assegurament postinstal·lació

Després d'acabar la configuració al navegador, cal aplicar permisos restrictius als fitxers de Moodle per evitar modificacions no autoritzades.

## 11.1. Canvia el propietari del directori de Moodle

Es transfereix la propietat del directori principal i del fitxer de configuració a root, de manera que Apache (`www-data`) no pugui modificar-los:

```bash
sudo chown root:root /var/www/moodle/
```

```bash
sudo chown root:root /var/www/moodle/config.php
```

## 11.2. Restringeix els permisos del fitxer de configuració

El fitxer `config.php` conté les credencials de la base de dades. S'estableix com a només lectura:

```bash
sudo chmod 644 /var/www/moodle/config.php
```

> **Nota:** La combinació `chown root` + `chmod 644` assegura que Apache pot llegir el fitxer `config.php`, però no pot modificar-lo, protegint les credencials de la base de dades.


# 12. Verifica la instal·lació

Un cop completada la instal·lació, verifica que tot funciona correctament:

```bash
# Estat d'Apache
sudo systemctl status apache2.service

# Estat de MariaDB
sudo systemctl status mariadb.service

# Versió de PHP
sudo php -v

# Connexió a la base de dades
mysql -u umoodle -p contrasenya
```

Finalment, accedeix a **https://moodle.thos.local** des del navegador i comprova que Moodle carrega correctament.

![Tauler de control de Moodle](https://proferamon.com/tic/imatges/moodle/moodle14.png)

# 13. Resolució de problemes habituals

| Problema | Solució |
|---|--------|
| Apache no s'inicia | Comprova els errors amb: `journalctl -xe | grep apache2` |
| Error 403 Forbidden | Verifica els permisos de `/var/www/moodle` i el bloc `Directory` a `moodle-ssl.conf` |
| Avís de certificat SSL | Normal amb certificats autosignats. Accepta l'excepció al navegador |
| Error de connexió a la BD | Verifica usuari i contrasenya. Comprova que MariaDB està en marxa |
| `max_input_vars` massa baix | Verifica que `php.ini` té `max_input_vars = 5000` i reinicia Apache |
| `moodledata` no accessible | Comprova que `/var/www/moodledata` existeix i és propietat de `www-data` |

> Per a qualsevol dubte, consulta la documentació oficial a [https://docs.moodle.org](https://docs.moodle.org).

#### Versions d'aquest document

+ HTML - [moodle.html](https://proferamon.com/tic/moodle.html)
+ PDF - [moodle.pdf](https://proferamon.com/tic/docs/moodle.pdf)
+ ODT - [moodle.odt](https://proferamon.com/tic/odt/moodle.odt)
+ MD - [moodle.md](https://proferamon.com/tic/md/moodle.md)
 
[Domini Públic (CC0)](https://creativecommons.org/publicdomain/zero/1.0/deed.ca) 

