[Moodle Migration][Phase 5] Staging
Goal: land the restored 4.0.9 on a clean Ubuntu 24.04 VPS, lock it down, serve it at a staging hostname with HTTPS, and make it safe for client testing.
Decisions
- Web: Nginx
- DB: MariaDB 11.4 LTS (local only)
- PHP: dual β 8.0 (runtime for 4.0.x / 4.2), 8.2 (ready for 5.1)
- Hostname: moodle.newroadgi.com (A β VPS IP)
- Staging safety: disable mail, block bots, cron via cron.d
System firewall
sudo ufw allow OpenSSH
sudo ufw --force enable
sudo ufw allow 'Nginx Full'
sudo ufw status
MariaDB 11.4 (local-only) + safe defaults
curl -LsS https://r.mariadb.com/downloads/mariadb_repo_setup | \
sudo bash -s -- --mariadb-server-version=11.4
sudo apt update && sudo apt -y install mariadb-server
sudo systemctl enable --now mariadb
# local-only + utf8mb4
sudo tee /etc/mysql/mariadb.conf.d/60-moodle.cnf >/dev/null <<'EOF'
[mysqld]
bind-address = 127.0.0.1
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
innodb_file_per_table = 1
EOF
sudo systemctl restart mariadb
# harden & create db/user
sudo mariadb-secure-installation
sudo mariadb <<'SQL'
CREATE DATABASE moodle DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'moodleuser'@'localhost' IDENTIFIED BY 'REDACTED_STRONG_PW';
GRANT ALL PRIVILEGES ON moodle.* TO 'moodleuser'@'localhost';
FLUSH PRIVILEGES;
SQL
Quick checks
mariadb --version
ss -ltnp | grep 3306 # 127.0.0.1:3306 only
sudo mariadb -e "SHOW VARIABLES LIKE 'character_set_server';"
sudo mariadb -e "SHOW VARIABLES LIKE 'collation_server';"
Web roots & ownership
sudo mkdir -p /var/www/moodle /var/www/moodledata
# unpack your backups into those folders (flatten if nested)
# then:
sudo chown -R www-data:www-data /var/www/moodle /var/www/moodledata
sudo chmod 750 /var/www/moodledata
Nginx server block (PATH_INFO aware)
sudo tee /etc/nginx/sites-available/moodle >/dev/null <<'EOF'
server {
listen 80;
server_name moodle.newroadgi.com;
root /var/www/moodle; # (later moved to /var/www/moodle/public when we reached 5.1)
index index.php;
client_max_body_size 128m;
# ACME challenge (Letβs Encrypt)
location ^~ /.well-known/acme-challenge/ {
default_type "text/plain";
try_files $uri =404;
}
location / { try_files $uri $uri/ /index.php?$query_string; }
# Single PHP handler (PATH_INFO aware)
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.0-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; }
}
EOF
sudo ln -sf /etc/nginx/sites-available/moodle /etc/nginx/sites-enabled/moodle
sudo rm -f /etc/nginx/sites-enabled/default
sudo nginx -t && sudo systemctl reload nginx
Moodle config (restore)
Edit /var/www/moodle/config.php (from your backup) and confirm:
$CFG->dbtype = 'mariadb';
$CFG->dbname = 'moodle';
$CFG->dbuser = 'moodleuser';
$CFG->dbpass = 'REDACTED_STRONG_PW';
$CFG->dbhost = 'localhost';
$CFG->prefix = 'mdlf2_'; // your actual prefix
$CFG->wwwroot = 'http://moodle.newroadgi.com'; // switched to https after TLS
$CFG->dataroot = '/var/www/moodledata';
$CFG->noemailever = true; // staging: suppress all email
TLS (Letβs Encrypt) & switch to HTTPS
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
sudo certbot --nginx -d moodle.newroadgi.com --redirect
# then update config.php
$CFG->wwwroot = 'https://moodle.newroadgi.com';
Cron (per-minute, staging)
echo '* * * * * www-data /usr/bin/php8.0 /var/www/moodle/admin/cli/cron.php >/dev/null 2>&1' | \
sudo tee /etc/cron.d/moodle
sudo chmod 644 /etc/cron.d/moodle
sudo systemctl restart cron
(Optional) quick ops bundle
sudo mkdir -p /root/ops-backup
sudo cp /etc/mysql/mariadb.conf.d/60-moodle.cnf /root/ops-backup/
sudo bash -c 'dpkg -l > /root/ops-backup/packages.txt'
DATE=$(date +%F)
sudo tar -czf /root/ops-backup-$DATE.tgz -C /root ops-backup
sudo cp /root/ops-backup-$DATE.tgz ~/
sudo chown "$USER:$USER" ~/ops-backup-$DATE.tgz