Performance Tuning
Optimizing Moodle performance involves a combination of server-level configuration, Moodle application settings, and infrastructure decisions. This guide covers the key areas to focus on when improving the speed and responsiveness of your Moodle site.
PHP OPcache
OPcache is the single most important PHP optimization for Moodle. It caches compiled PHP bytecode in memory, eliminating the need to parse and compile PHP files on every request.
Recommended OPcache settings in php.ini:
opcache.enable = 1
opcache.memory_consumption = 256
opcache.max_accelerated_files = 10000
opcache.revalidate_freq = 60
opcache.use_cwd = 1
opcache.validate_timestamps = 1
opcache.save_comments = 1
opcache.enable_file_override = 0
On production sites where code changes are infrequent, you can set opcache.validate_timestamps = 0 for maximum performance. When doing so, you must manually restart PHP (or the web server) after code changes for them to take effect.
Database Tuning
MySQL/MariaDB
Key settings for MySQL/MariaDB performance:
[mysqld]
innodb_buffer_pool_size = 1G # Set to 70-80% of available RAM on dedicated DB server
innodb_log_file_size = 256M
innodb_flush_log_at_trx_commit = 2 # Better performance (slight risk on crash)
innodb_flush_method = O_DIRECT
query_cache_type = 0 # Disable query cache (deprecated in MySQL 8)
join_buffer_size = 256K
sort_buffer_size = 256K
tmp_table_size = 64M
max_heap_table_size = 64M
table_open_cache = 4000
thread_cache_size = 16
PostgreSQL
Key settings for PostgreSQL performance:
shared_buffers = 256MB # 25% of system RAM
effective_cache_size = 1GB # 50-75% of system RAM
work_mem = 16MB
maintenance_work_mem = 256MB
wal_buffers = 16MB
checkpoint_completion_target = 0.9
random_page_cost = 1.1 # Lower for SSD storage
Moodle Universal Cache (MUC)
Configure MUC as described in the Caching article. For best performance:
- Use Redis for application and session caches
- Configure local file cache as a backup store
- Map frequently-accessed cache definitions to the fastest store available
Theme Designer Mode
Ensure Theme designer mode is disabled on production sites at Site administration > Appearance > Themes > Theme settings. When enabled, this mode disables CSS and JavaScript caching, significantly increasing page load times. It should only be enabled during active theme development.
JavaScript and CSS Optimization
At Site administration > Appearance > AJAX and JavaScript and theme settings:
- Cache JavaScript: Ensure JavaScript caching is enabled
- Cache CSS: Ensure theme CSS caching is enabled
- Minify JavaScript: Enable JavaScript minification
- Minify CSS: Enable CSS minification
Content Delivery Network (CDN)
Offload static assets to a CDN for faster delivery to geographically distributed users. Configure at Site administration > Server > HTTP:
// In config.php, you can also set:
$CFG->slasharguments = true;
For CDN configuration, set up your CDN (Cloudflare, CloudFront, etc.) to cache static assets like CSS, JavaScript, fonts, and images. Configure the CDN to pull from your Moodle origin server.
Session Handling Optimization
Database sessions become a bottleneck on high-traffic sites. Switch to Redis sessions by adding to config.php:
$CFG->session_handler_class = '\core\session\redis';
$CFG->session_redis_host = '127.0.0.1';
$CFG->session_redis_port = 6379;
$CFG->session_redis_database = 0;
$CFG->session_redis_prefix = 'moodle_sess_';
$CFG->session_redis_acquire_lock_timeout = 120;
$CFG->session_redis_lock_expire = 7200;
Cron Optimization
- Run cron every minute for timely task execution
- Consider increasing the cron memory limit for large sites
- Monitor long-running tasks and optimize or split them
- Use the scheduled tasks page to identify slow tasks
Web Server Tuning
Apache
# Enable compression
<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE text/html text/css application/javascript application/json
</IfModule>
# Enable browser caching
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType text/css "access plus 1 year"
ExpiresByType application/javascript "access plus 1 year"
ExpiresByType image/png "access plus 1 year"
</IfModule>
# Use mpm_event for better concurrency
Nginx
gzip on;
gzip_types text/css application/javascript application/json image/svg+xml;
gzip_min_length 1000;
location ~* .(css|js|png|jpg|gif|ico|woff2)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
Monitoring Performance
- Enable
$CFG->perfdebug = 15temporarily to see query counts and page generation times - Use the Site administration > Server > Performance overview (if available) or third-party monitoring tools
- Monitor database slow query logs
- Use tools like New Relic, Blackfire, or Xdebug for profiling