[Moodle Migration][Phase 7] PHP 8.2 switch, 5.1 upgrade
Goal: move the upgraded 4.2.11 site to PHP 8.2, hop to 5.1+, adopt the new /public webroot, and leave cron/HTTPS solid.
Decisions
- Runtime PHP: 8.2 (5.1 requires â„8.2)
- DB: MariaDB 11.4 LTS (already in place)
- Web: Nginx (single PATH_INFO PHP block; no duplicates)
- Webroot after 5.1:
/var/www/moodle/public - Staging safety:
$CFG->noemailever = truestays on
Prereqs (sanity)
# make sure 8.2 has the required setting and extensions
echo 'max_input_vars = 5000' | sudo tee /etc/php/8.2/cli/conf.d/50-moodle.ini >/dev/null
echo 'max_input_vars = 5000' | sudo tee /etc/php/8.2/fpm/conf.d/50-moodle.ini >/dev/null
sudo systemctl restart php8.2-fpm
php8.2 -i | grep -i max_input_vars
php8.2 -m | egrep -i 'mbstring|curl|zip|gd|intl|xml|xmlreader|dom|sodium' || true
Put site into maintenance
sudo -u www-data php8.2 /var/www/moodle/admin/cli/maintenance.php --enable
Code swap to 5.1 (git)
# keep an instant rollback
sudo mv /var/www/moodle /var/www/moodle-40211
# fetch 5.1.x
sudo git clone -b MOODLE_501_STABLE --depth=1 https://github.com/moodle/moodle.git /var/www/moodle
# carry over config, fix ownership
sudo cp /var/www/moodle-40211/config.php /var/www/moodle/config.php
sudo chown -R www-data:www-data /var/www/moodle
Composer vendors (required for git installs)
We ran Composer under PHP 8.2 CLI to avoid distro Composer quirks with PHP 8.0.
cd /var/www/moodle
sudo -u www-data php8.2 /usr/bin/composer install --no-dev --prefer-dist --optimize-autoloader
Switch Nginx to PHP 8.2 & adopt /public webroot
5.1 requires serving from
/public. Replace the vhost with a clean config: single PHP block, PATH_INFO-aware, 80â443 redirect, ACME intact.
sudo tee /etc/nginx/sites-available/moodle >/dev/null <<'EOF'
# HTTPS vhost
server {
listen 443 ssl;
server_name moodle.newroadgi.com;
root /var/www/moodle/public;
index index.php;
client_max_body_size 128m;
# TLS (Certbot-managed files)
ssl_certificate /etc/letsencrypt/live/moodle.newroadgi.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/moodle.newroadgi.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
# App routing
location / {
try_files $uri $uri/ /index.php?$query_string;
}
# Single PHP handler (PATH_INFO aware) on PHP 8.2
location ~ \.php(/|$) {
fastcgi_split_path_info ^(.+\.php)(/.*)$;
set $path_info $fastcgi_path_info;
try_files $fastcgi_script_name $fastcgi_script_name/ =404;
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
include fastcgi_params;
fastcgi_param PATH_INFO $path_info;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $document_root;
fastcgi_read_timeout 300;
}
# Basic hardening
location ~* ^/(?:\.git|\.hg|\.svn|vendor|node_modules)/ { deny all; }
location ~* /(config\.php|composer\.(json|lock)) { deny all; }
location ~ /\. { deny all; }
}
# HTTP vhost -> HTTPS + ACME
server {
listen 80;
server_name moodle.newroadgi.com;
root /var/www/moodle/public;
# ACME http-01
location ^~ /.well-known/acme-challenge/ {
default_type "text/plain";
try_files $uri =404;
}
# everything else to HTTPS
location / { return 301 https://$host$request_uri; }
}
EOF
sudo nginx -t && sudo systemctl reload nginx
Run the 5.1 upgrader (PHP 8.2)
sudo -u www-data php8.2 /var/www/moodle/admin/cli/upgrade.php
# answer Y â success
Post-upgrade tidy
# purge caches
sudo -u www-data php8.2 /var/www/moodle/admin/cli/purge_caches.php
# bring site back
sudo -u www-data php8.2 /var/www/moodle/admin/cli/maintenance.php --disable
Cron on PHP 8.2 (clear âcron not runningâ / âadhoc queueâ warnings)
# flip cron to 8.2 and restart cron daemon
sudo sed -i 's|/usr/bin/php8\.0|/usr/bin/php8\.2|' /etc/cron.d/moodle
sudo systemctl restart cron
# run once now and re-check
sudo -u www-data php8.2 /var/www/moodle/admin/cli/cron.php
sudo -u www-data php8.2 /var/www/moodle/admin/cli/checks.php | tail -n 20
Theme
- Keep stock (Boost/Boost Union) for now (cleanest).
- If restoring a custom theme, copy from
.../theme/<yourtheme>into/var/www/moodle/theme/<yourtheme>, run upgrade, purge caches, then select it in Site administration â Appearance â Theme selector. Make sure itâs 5.1-compatible.
Rollback (fast)
# if you had to roll back code only
sudo mv /var/www/moodle /var/www/moodle-501
sudo mv /var/www/moodle-40211 /var/www/moodle
sudo nginx -t && sudo systemctl reload nginx
Contraints and fixes
-
Composer blew up under PHP 8.0 with
AnsiColorModeparse error â Run Composer using PHP 8.2 CLI:sudo -u www-data php8.2 /usr/bin/composer install ... -
âMoodle 4.4 or later requires at least PHP 8.1 (currently 8.0.30)â after switching to 8.2 â Certbotâs 443 vhost still referenced php8.0-fpm.sock. Fix:
sed -i 's|php8.0-fpm.sock|php8.2-fpm.sock|g' /etc/nginx/sites-available/moodleâ reload Nginx. -
Broken CSS over HTTPS â There were two PHP blocks; the simple
location ~ \.php$ { ... }captured requests and broke PATH_INFO. Fix: delete the simple block and keep only the PATH_INFO block (see config above). -
âThe Moodle root directory must not be publicly accessibleâ after 5.1 â 5.1 expects webroot at
/public. Fix: setroot /var/www/moodle/public;for both 80 and 443; reload Nginx. -
Environment CRITICALs under PHP 8.2 â Missing
max_input_vars=5000in 8.2 (we had set it only for 8.0). Fix: add to/etc/php/8.2/{cli,fpm}/conf.d/50-moodle.ini, restartphp8.2-fpm, re-run checks. -
Cron warnings (ânot run in N minutesâ, âadhoc queue oldâ) â Cron still used PHP 8.0. Fix: switch
/etc/cron.d/moodleto php8.2, restart cron, run once manually. -
Theme changed after code swaps â Custom theme wasnât copied (by design for a clean hop) or not 5.1-compatible. Fix: stay on stock, or install a 5.1-ready theme later.