Harden your Moodle LMS platform against cyber attacks. Set strict directory controls on dataroot volumes, deploy advanced HTTP defense headers, enforce Fail2ban login restrictions, and run automated platform security audits.
dataroot directory stores student files, submissions, and session data. If placed inside Apache's document root, attackers can directly access or run uploaded scripts. Moving this outside of web paths is crucial.
# Move dataroot outside Apache document root
sudo mv /var/www/moodl_ulo2026Demo/moodledata /var/moodledata
# Ensure permissions restrict access to www-data exclusively
sudo chown -R www-data:www-data /var/moodledata
sudo chmod -R 770 /var/moodledata
# Create a blocking .htaccess as a second line of defense
echo "Order deny,allow
Deny from all" | sudo tee /var/moodledata/.htaccess
sudo nano /etc/apache2/sites-available/000-default-le-ssl.conf
# Inside the <VirtualHost *:443> block, paste the following rules:
Header always set X-Frame-Options "SAMEORIGIN"
Header always set X-Content-Type-Options "nosniff"
Header always set X-XSS-Protection "1; mode=block"
Header always set Content-Security-Policy "upgrade-insecure-requests"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
# Restart Apache to apply the protection headers
sudo systemctl restart apache2
/login/index.php) is a constant target for brute-force dictionaries. Fail2ban scans access logs and automatically drops requests from active attack IPs at the firewall level.
# Install Fail2ban package
sudo apt install fail2ban -y
# Create Moodle login parser filter
sudo nano /etc/fail2ban/filter.d/moodle-login.conf
# Add rules:
# [Definition]
# failregex = ^<HOST> - - .*POST /login/index.php.* HTTP/.* 200
# Create the jail parameters config file
sudo nano /etc/fail2ban/jail.d/moodle.local
# Add:
# [moodle-login]
# enabled = true
# port = http,https
# filter = moodle-login
# logpath = /var/log/apache2/access.log
# maxretry = 5
# bantime = 3600
sudo systemctl restart fail2ban
mod_remoteip to parse the actual client IP headers correctly.
www-data.
# Transfer codebase ownership from www-data to root/deploy user
sudo chown -R root:root /var/www/moodl_ulo2026Demo
# Let www-data only read files
sudo find /var/www/moodl_ulo2026Demo -type d -exec chmod 755 {} \;
sudo find /var/www/moodl_ulo2026Demo -type f -exec chmod 644 {} \;
# Leave write permissions only on caching directories (when not using Redis)
# sudo chown -R www-data:www-data /var/www/moodl_ulo2026Demo/cache
# Run Moodle Security Diagnostic CLI Check
sudo -u www-data php /var/www/moodl_ulo2026Demo/admin/cli/security_checks.php
expose_php = Off
display_errors = Off
log_errors = On
allow_url_fopen = Off
disable_functions = exec,system,shell_exec,passthru
Enforce HTTPS globally: Forces browsers to interact strictly over SSL channels.
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
fail2ban-client status moodle-login
find /var/www/moodl_ulo2026Demo -name "*.php" -perm /o+w
sudo certbot --apache -d classroom.demodemo.com