Skip to main content
Version: main (5.1)

Code Restructure

In version 5.1, Moodle started the process of restructuring its codebase into different directories.

In the initial phase most code has been moved out of the directory root, and into a public directory.

For the most part this change has minimal impact on developers. Most existing tooling has already been updated to support the new locations of plugins, however some changes may be required.

Moodle reconfiguration

In almost all cases there is no need to reconfigure Moodle at all for this change. The existing $CFG->wwwroot should continue to behave as before, as should the $CFG->dirroot.

A new read-only variable, $CFG->root has been introduced which points to the root of the Moodle installation.

Web server reconfiguration

The purpose of this restructure is to move all web-accessible content into a new public directory, which in turn allows Moodle to have content which is not web accessible. In the future this will be used to support installation of other software which should not be publicly available.

This change will require some reconfiguration of web servers.

For production systems which only need to do deal with individually configured Moodle systems, or a set of Moodle sites hosted in identical environments, this change should be minimal. It usually requires the reconfiguration of the DocumentRoot directive in Apache, or the root directive in nginx.

Updating the Apache DocumentRoot
--- a/httpd.conf
+++ b/httpd.conf
- DocumentRoot /srv/moodle
+ DocumentRoot /srv/moodle/public

Developer configuration examples

For developer systems it is reasonably common to switch between a wide variety of Moodle versions and configurations.

The following configurations allow developers to support multiple versions of Moodle from within subdirectories, without manual mapping of the paths. For example:

$CFG->wwwrootWeb Root
https://example.com/m405/srv/moodle/m405
https://example.com/m500/srv/moodle/m500
https://example.com/m501/srv/moodle/m501/public

In addition to the directory configuration, this configuration also supports:

  • SSL
  • The Moodle Router

This configuration is broken into two files:

  • a moodle_listeners.conf which can be included from the your main configuration file, and which allows the overall configuration of the listeners; and
  • a moodle_listener.conf which contains the individual listener configuration.

This makes it easier to support SSL configuration on your server.

Generating SSL Certificates

If you have a domain that you control, you may be able to use a DNS-based CertBot plugin such as Route53 or Cloudflare.

moodle_listeners.conf
<VirtualHost [YOUR_SERVERNAME]:80>
Include /opt/homebrew/etc/moodle_listener.conf
</VirtualHost>

<VirtualHost [YOUR_SERVERNAME]:443>
# So you have an SSL Certificate?
# Set the details below.
SSLEngine on
SSLCertificateFile "/etc/letsencrypt/live/[YOUR_HOSTNAME]/fullchain.pem"
SSLCertificateKeyFile "/etc/letsencrypt/live/[YOUR_HOSTNAME]/privkey.pem"

Include /opt/homebrew/etc/httpd/moodle_listener.conf
</VirtualHost>

moodle_listener.conf
#######################################
# The file is used to handle Moodle sites served from a sub folder of the domain.
#######################################

#######################################
# Things you need to set up before using this configuration:
#######################################

# Update your configuration to match the host name(s) that you use.
# You can have as many as you like and/or require.
#######################
# UPDATE ME
ServerName [YOUR_SERVERNAME]
#######################

# You can add any aliases you like here too.
# You probably want to keep this one though.
ServerAlias localhost

# Set the root directory for your Moodle sites.
# You need to set it in a few places below too.
#######################
# UPDATE ME
DocumentRoot /srv/moodle
#######################

# Configure the directory configuration.
#######################
# UPDATE ME
<Directory /srv/moodle>
#######################
# Do not allow directory listing.
# Allow following symbolic links.
Options -Indexes +FollowSymLinks
# Do not allow .htaccess files to override settings.
AllowOverride None
# Allow access to all users.
Require all granted
</Directory>

# Repeat the same for any public folder too.
#######################
# UPDATE ME
<DirectoryMatch "^/srv/moodle/[^/]+(/public)?$">
#######################
Options -Indexes +FollowSymLinks
AllowOverride None
Require all granted
</DirectoryMatch>

<IfModule mod_rewrite.c>
RewriteEngine On

# Enable rewrite logging for debugging purposes.
# LogLevel warn mod_rewrite.c:trace7

#######################
# UPDATE ME
# Route through a known fixed folder
DocumentRoot "/srv/moodle"
#######################

# Use mod_rewrite to handle requests.
# We cannot use FallbackResource here because we need to check if the /public folder exists.
RewriteEngine On

#####################
# Ruleset 1.
# Check if this request is for a site which has a public folder.
#####################
# Check whether the requested file exists as-is.
RewriteCond %{SCRIPT_FILENAME} !-f
# Extract the top-level folder from the request URI. This is the Moodle site name.
RewriteCond %{REQUEST_FILENAME} ^/([^/]+)(/.*)?$
# If the public folder exists for that site, rewrite the request to go through it.
RewriteCond %{DOCUMENT_ROOT}/%1/public -d
RewriteRule ^/([^/]+)(/.*)?$ /$1/public$2 [C] # Rewrite to public folder - CHAIN to the next rule.

#####################
# Ruleset 1.1.
# The public folder exists.
# See if we can access the file directly.
# If not, rewrite to the r.php (router) inside the site/public folder.
#####################
# Extract the file path before the .php extension, if any (pathinfo removed).
RewriteCond %{REQUEST_FILENAME} ^(.+\.php)?(/.*)?$
# AND the requested file does not exist as-is.
# The %1 is the file path before the .php extension, if any (pathinfo removed).
# It is fetched from the RewriteCond above.
# %2 is the pathinfo, if any.
RewriteCond %{DOCUMENT_ROOT}%1 !-f
# AND the requested URI is not a file.
# $1 is the site name, $2 is the file path.
# These come from the RewriteRule below that this rule applies to.
RewriteCond %{DOCUMENT_ROOT}/$1$2 !-f
# AND the requested URI is not a directory.
RewriteCond %{DOCUMENT_ROOT}/$1$2 !-d
# Rewrite the request to go through the r.php (router) in the site/public folder.
RewriteRule ^/([^/]+)(/.*)?$ /$1/public/r.php [L]

#####################
# Rule set 2.
# The public folder does _not_ exist.
# See if we can access the file directly.
# If not, rewrite to the r.php (router) in the site folder.
#####################
# Check whether the requested file exists as-is.
RewriteCond %{SCRIPT_FILENAME} !-f
# Extract the top-level folder from the request URI. This is the Moodle site name.
RewriteCond %{REQUEST_FILENAME} ^/([^/]+)(/.*)?$
# If the public folder DOES NOT exist for that site.
RewriteCond %{DOCUMENT_ROOT}/%1/public !-d
# Extract the file path before the .php extension, if any (pathinfo removed).
RewriteCond %{REQUEST_FILENAME} ^(.+\.php)?(/.*)?$
# AND the requested file does not exist as-is.
# The %1 is the file path before the .php extension, if any (pathinfo removed).
# It is fetched from the RewriteCond above.
# %2 is the pathinfo, if any.
RewriteCond %{DOCUMENT_ROOT}%1 !-f
# AND the requested URI is not a file.
# $1 is the site name, $2 is the file path.
# These come from the RewriteRule below that this rule applies to.
RewriteCond %{DOCUMENT_ROOT}/$1$2 !-f
# AND the requested URI is not a directory.
RewriteCond %{DOCUMENT_ROOT}/$1$2 !-d
# Rewrite the request to go through the r.php (router) in the site folder.
RewriteRule ^/([^/]+)(/.*)?$ /$1/r.php [L]

#######################
# UPDATE ME
<Directory "/srv/moodle">
#######################
# Follow symbolic links.
Options FollowSymLinks
# Do not allow .htaccess files to override settings.
AllowOverride None
# Allow access to all users.
Require all granted
# Set the index file.
DirectoryIndex index.php
</Directory>
</IfModule>

<IfModule dir_module>
DirectoryIndex index.php index.html
</IfModule>

<FilesMatch \.php$>
SetHandler application/x-httpd-php
</FilesMatch>