Websites & apps

Install Moodle on a Linux VPS with Nginx and PHP-FPM

Install the Moodle LMS on a VPS: PHP and database requirements, moodledata outside the web root, Nginx with slash arguments, the CLI installer, cron every minute and caching.

IntermediateLinux VPS3 min read

Moodle is the most widely used open-source learning management system. A small school can start on cPanel with Softaculous, but larger installs run best on a VPS. This guide shows how to install Moodle on a Linux VPS with Nginx and PHP-FPM.

Before you start

  • A VPS sized for your users: 2 GB RAM for a few dozen concurrent users, more as you grow. Root access.
  • Check the requirements of the Moodle version you install (PHP, MySQL/MariaDB/PostgreSQL versions).
  • A domain with DNS pointing to the VPS.

Install PHP and set required options

Install PHP-FPM with: curl, gd, intl, mbstring, mysql (or pgsql), soap, xml, zip, opcache, sodium, redis. Then set in php.ini (both FPM and CLI):

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

max_input_vars = 5000 is required; the installer refuses to continue without it.

Create the database

mysql -e "CREATE DATABASE moodle DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE USER 'moodle'@'localhost' IDENTIFIED BY 'strong-password'; GRANT ALL ON moodle.* TO 'moodle'@'localhost';"

Get Moodle and create moodledata

Clone the stable branch you want with Git (easier upgrades):

git clone -b MOODLE_405_STABLE git://git.moodle.org/moodle.git /var/www/moodle

Replace the branch name with the current stable branch. Create the data directory outside the web root:

mkdir /var/moodledata && chown www-data:www-data /var/moodledata && chmod 770 /var/moodledata

The code itself should be owned by root or your deploy user and only readable by the web server.

Configure Nginx

server {
    server_name lms.example.com;
    root /var/www/moodle;
    index index.php;
    client_max_body_size 100M;

    location / {
        try_files $uri $uri/ =404;
    }

    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 ~ /\.(?!well-known) { deny all; }
    location ~ (/vendor/|/node_modules/|composer\.json|/readme|/README|/upgrade\.txt|/db/install\.xml|/fixtures/|/behat/|phpunit\.xml) { deny all; }
}

The PATH_INFO lines enable Moodle's "slash arguments", required for many file URLs. Add SSL with Certbot before installing so wwwroot uses https.

Run the installer

cd /var/www/moodle && sudo -u www-data php admin/cli/install.php --wwwroot=https://lms.example.com --dataroot=/var/moodledata --dbtype=mariadb --dbname=moodle --dbuser=moodle --dbpass=strong-password --fullname="My LMS" --shortname=LMS --adminuser=admin --adminpass='Strong-Pass-1' --adminemail=admin@example.com --agree-license --non-interactive

Use --dbtype=mysqli for MySQL or pgsql for PostgreSQL. The installer writes config.php; afterwards make it read-only (chmod 444 config.php). The web installer at your URL is an alternative.

Set up cron

Moodle needs cron every minute for notifications, grading and scheduled tasks:

* * * * * /usr/bin/php /var/www/moodle/admin/cli/cron.php >/dev/null 2>&1

Add it to the www-data crontab (crontab -u www-data -e).

Performance

  • Enable OPcache with enough memory.
  • Use Redis for sessions and the application cache (Site administration → Plugins → Caching).
  • Set up outgoing mail via SMTP in Site administration → Server → Email.
  • Check Site administration → Notifications and the Environment page for warnings.

Upgrading

Enable maintenance mode, back up the database, code and moodledata, then pull the new branch and run sudo -u www-data php admin/cli/upgrade.php.

Troubleshooting

  • max_input_vars must be at least 5000: set it in the PHP-FPM and CLI php.ini.
  • Images and files broken: slash arguments are not working; check the PATH_INFO lines.
  • Cron has not run for a while warning: the cron entry is missing or runs as the wrong user.
  • Uploads limited to 2 MB: raise PHP limits and client_max_body_size, then the course/site upload limits.

Moodle FAQ

How many users can a VPS handle?

It depends on concurrent activity: quizzes and assignment deadlines create peaks. Start modest and monitor.

Can I install Moodle on cPanel?

Yes, via Softaculous or manually, but cron every minute and moodledata size make a VPS better for busy sites.

Where are uploaded files stored?

In moodledata, which must be backed up together with the database.

Next steps

Was this guide helpful?

Still stuck?

Ask MdmHost AI for a quick answer, or open a ticket and our team will take a look. We are here 24/7.