Cheat Sheets › Diagnosing

Diagnosing a Problem

When a site is down, slow, or showing errors: narrow down which layer is broken, then look in the right place. Apache with PHP-FPM, databases on Amazon RDS. Amazon Linux 1 and Ubuntu 24.04 side by side.

READ-ONLY only looks; safe CHANGES THINGS be careful ON YOUR MAC in Terminal on your Mac ON THE SERVER after logging in Amazon Linux 1Ubuntu 24.04 where they differ

Start here

#1The method

Before typing anything, answer three questions. They usually point straight at the layer that's broken.

1. What changed?An update (yours or automatic), a config edit, a Moodle upgrade or plugin, a new certificate, a busy day like exams. Most problems start right after a change. (history.log on Ubuntu, yum history on Amazon Linux 1, and your own history show what changed.)
2. When did it start?The time lets you find the first error in the logs, which is usually the real cause. Later errors are often just side effects.
3. Who's affected?The most useful question. See the diagram below.
Who's affected tells you where to look
One page or user Moodle itself: a course, plugin, or permission One whole site its PHP-FPM version, its Apache config, or its database Every site on one server Apache, disk, memory, CPU, the server itself Every server your end (internet, IP), AWS, or a shared RDS database → section 8 → sections 5, 4, 6 → sections 2, 4 → sections 7, 6 Smallest to biggest: the wider the problem, the lower down it is: Moodle → site → server → everything.
GOLDEN RULELook before you change. Everything in sections 2–7 is read-only. Restarting things first can wipe out the clue (a full log, a stuck process) that tells you what actually went wrong.
↑ Back to top

#2The first five minutes

READ-ONLY

Run these in order. Each one rules something in or out, and none of them change anything.

1. What does the site actually return? ON YOUR MAC
curl -sS -o /dev/null -w "%{http_code} in %{time_total}s\n" https://school.example.com 200 in 0.84s
  • Replace the address with the site's. It prints the status code and how long the page took.
  • 200 = OK. 303 = a redirect, normal for Moodle's login page. 500, 502, 503, 504 = a server problem: see section 3.
  • An error instead of a code (Could not resolve host, Connection timed out, a certificate error) = section 7.
2. Can you log in to the server? ON YOUR MAC
ssh ubuntu1

If not, the server itself may be down or overloaded: check it in the AWS console (EC2 › Instances: is it running, and do status checks pass?).

3. Is the server overloaded? ON THE SERVER
uptime 14:52:10 up 41 days, 2:13, 1 user, load average: 0.52, 0.71, 0.66

Load averages for the last 1, 5, and 15 minutes. Compare with the number of CPUs (nproc). Much higher than that = overloaded; then run top to see what's busy.

4. Is a disk full?
df -h

Look at Use%. 100% on the main disk or the moodledata disk breaks sessions, uploads, and caching. Details: df, du.

5. Is memory running out?

Amazon Linux 1

free -m
(sizes in MB; works on every version, while -h may not)

Ubuntu 24.04

free -h

Watch available (on Amazon Linux 1, the free number on the -/+ buffers/cache line). Very low = out of memory; Linux may be killing PHP processes. See free.

6. Are Apache and PHP-FPM running?

Amazon Linux 1

sudo service httpd status

PHP-FPM: find the service names first (section 5), then sudo service NAME status for each.

Ubuntu 24.04

systemctl status apache2

Anything failed, including PHP-FPM:
systemctl --failed
7. What's the latest error?

Amazon Linux 1

sudo tail -n 30 /var/log/httpd/error_log

Ubuntu 24.04

sudo tail -n 30 /var/log/apache2/error.log

The main Apache error log. Sites with their own log files are covered in section 4. Read the times: errors from when the problem started matter; old ones may not.

BY NOWYou usually know whether it's one site or the whole server, and whether something obvious is full, stopped, or overloaded. Next, match what you're seeing in section 3.
↑ Back to top

#3Symptom → likely cause → where to look

You seeUsually meansLook at
Blank white pageA PHP error, with error display turned off. Often a typo in config.php or a plugin.PHP-FPM log, Apache error log (§4, §5)
500 Internal Server ErrorPHP crashed on that request, a bad .htaccess, or a file permission problem.Apache error log, then PHP-FPM log
502 Bad GatewayApache reached PHP-FPM, but it closed the connection or crashed.PHP-FPM log and status (§5)
503 Service UnavailableApache can't reach PHP-FPM at all (stopped, or its socket missing). Also shown when Moodle is in maintenance mode.PHP-FPM status (§5), Moodle (§8)
504 Gateway TimeoutPHP took too long: a heavy page, a slow database query, or all PHP workers busy.PHP-FPM log (§5), RDS (§6)
"Error reading from database" / "Database connection failed"The server can't reach RDS, wrong credentials, or RDS out of connections or storage.RDS (§6)
Everything very slowServer overloaded, PHP workers all busy, or the database is slow.§2 step 3, PHP-FPM log, RDS
Login keeps looping backSessions can't be saved: disk full, moodledata not writable, or a wwwroot http/https mismatch.df -h, moodledata (§8)
Uploads failFile larger than PHP allows, disk full, or moodledata not writable.PHP limits (§5), df -h, §8
"This site can't be reached"DNS, the server is off, or the security group blocks you.§7, EC2 console
Certificate / "Not secure" warningThe SSL certificate expired or doesn't match the address.§7
↑ Back to top

Check each layer

#4Is it Apache?

READ-ONLYON THE SERVER
1. Is the config valid?
sudo apachectl configtest Syntax OK

Anything other than Syntax OK names the file and line with the mistake. Same command on both systems.

2. Which log files are there?

Amazon Linux 1

sudo ls -lt /var/log/httpd/

Ubuntu 24.04

sudo ls -lt /var/log/apache2/

Newest first. Besides the main error and access logs, sites often have their own, named after the site. Use the one for the site with the problem.

3. Is a site's log set somewhere else?

Amazon Linux 1

grep -ri "ErrorLog" /etc/httpd/conf.d/

Ubuntu 24.04

grep -ri "ErrorLog" /etc/apache2/sites-enabled/

Shows each site's settings file and the error log it writes to.

4. Watch errors live while you reproduce the problem

Amazon Linux 1

sudo tail -f /var/log/httpd/error_log

Ubuntu 24.04

sudo tail -f /var/log/apache2/error.log

Click the broken thing in the browser; the error appears as it happens. Ctrl+C to stop.

5. Count status codes in the access log (how bad is it?)

Amazon Linux 1

sudo awk '{print $9}' /var/log/httpd/access_log | sort | uniq -c | sort -rn

Ubuntu 24.04

sudo awk '{print $9}' /var/log/apache2/access.log | sort | uniq -c | sort -rn
18342 200 2210 303 412 503 35 404

How many requests got each status code, most common first. Hundreds of 5xx codes = a real server-side problem, not a one-off. (Use the site's own access log if it has one.)

Apache messages worth knowing
AH01079: failed to make connection to backendApache can't reach PHP-FPM. Check PHP-FPM (§5). Behind most 503s.
AH01067: Failed to read FastCGI headerPHP-FPM crashed mid-request. Behind most 502s. PHP-FPM log (§5).
The timeout specified has expiredPHP took too long. Behind most 504s.
server reached MaxRequestWorkers settingApache itself is at its limit of simultaneous visitors. Tuning belongs on the Apache sheet.
Permission denied on a file pathApache can't read a file. Check ownership with ls -l.
↑ Back to top

#5Is it PHP (PHP-FPM)?

READ-ONLYON THE SERVER

With several PHP versions on one server, each version runs as its own PHP-FPM service with its own log. So first find which version the broken site uses, then check that one.

1. Which PHP-FPM services does this server have?

Amazon Linux 1

ls /etc/init.d/ | grep -i fpm

Ubuntu 24.04

systemctl list-units --type=service | grep -i fpm

One name per PHP version, for example php-fpm-7.3 or php8.1-fpm. The exact names depend on how PHP was installed, which is why you look them up instead of guessing.

2. Which version does the broken site use?

Amazon Linux 1

grep -rn -E "proxy:unix|fcgi://" /etc/httpd/conf.d/

Ubuntu 24.04

grep -rn -E "proxy:unix|fcgi://" /etc/apache2/sites-enabled/ /etc/apache2/conf-enabled/
/etc/apache2/sites-enabled/school.conf:14: SetHandler "proxy:unix:/run/php/php8.1-fpm.sock|fcgi://localhost"

Each line: the site's settings file, then the PHP-FPM "socket" it sends PHP work to. The version is in the socket's name. Here, the school site uses PHP 8.1.

What this searches forThe line in each site's Apache settings that hands PHP work to PHP-FPM.
grep -rn -ESearch every file in the folder and the folders inside it (-r), show line numbers (-n), and let | mean "or" (-E).
proxy:unixThe usual way: through a socket file, like php8.1-fpm.sock. The version is in its name.
fcgi://The other way: by address and port, like fcgi://127.0.0.1:9000. (FastCGI is the "language" Apache and PHP-FPM speak.)
Got a port number instead of a socket name?

A port like 9000 doesn't say which PHP version it is. Find the PHP-FPM settings file that listens on it:

sudo grep -rn "^listen *= *127.0.0.1:9000" /etc 2>/dev/null /etc/php-fpm-7.3.d/www.conf:38:listen = 127.0.0.1:9000

Replace 9000 with the port from step 2. The file's folder name shows the version, here 7.3. 2>/dev/null just hides "can't read" noise from unrelated files.

3. Is that version running?

Amazon Linux 1

sudo service NAME status
using the name from step 1

Ubuntu 24.04

systemctl status php8.1-fpm
using the name from step 1

is running / active (running) = up. Stopped or failed = that's why its sites give 503 errors.

4. Find its log
sudo find /var/log -iname '*fpm*'

Lists every PHP-FPM log on the server; pick the one for the version from step 2. On Ubuntu it's usually /var/log/php8.1-fpm.log. Then read the end of it: sudo tail -n 30 PATH.

PHP messages worth knowing
server reached pm.max_children settingAll PHP workers are busy, so new visitors wait, causing slowness and 504s. A sign of too many visitors for the settings, or slow pages tying workers up. Tuning belongs on the PHP-FPM sheet.
Allowed memory size of … bytes exhaustedOne request needed more memory than PHP allows (memory_limit). Common with big course restores or reports.
Maximum execution time of … seconds exceededA request ran longer than PHP allows (max_execution_time).
child … exited on signal 9 or 11A PHP worker was killed: 9 often means out of memory (§2 step 5); 11 is a crash, often from a PHP extension.
PHP Parse error: syntax errorA typo in a PHP file, often config.php after an edit. Names the file and line.
Check a site's PHP limits (uploads, memory)
php8.1 -i | grep -E "upload_max_filesize|post_max_size|memory_limit|max_execution_time"

Use the version from step 2. Shows the limits from the command-line settings. PHP-FPM uses its own settings file, which is usually the same but can differ; the PHP-FPM sheet covers where each lives.

⚠ RESTARTING PHP-FPMCHANGES THINGSIf a PHP-FPM service is stopped or stuck, restarting it is usually the fix to get sites back. But read its log first (step 4), so you know why it happened. Restart only that version: Amazon Linux 1 sudo service NAME restart; Ubuntu sudo systemctl restart php8.1-fpm. It interrupts that version's sites for a second or two.
↑ Back to top

#6Is it the database (RDS)?

READ-ONLYON THE SERVER

The databases live on Amazon RDS, a separate machine. So the questions are: can this server reach it, does it let the site in, and is RDS itself healthy?

1. Which database does the site use?
grep -E "dbtype|dbhost|dbname|dbuser" config.php $CFG->dbtype = 'mariadb'; $CFG->dbhost = 'mydb.abc123xyz.us-east-1.rds.amazonaws.com'; $CFG->dbname = 'school'; $CFG->dbuser = 'school_user';

Run inside the site's Moodle folder. dbhost is the RDS address ("endpoint"). This search deliberately leaves out the password line.

2. Can the server reach RDS at all?
timeout 5 bash -c '</dev/tcp/mydb.abc123xyz.us-east-1.rds.amazonaws.com/3306' && echo OPEN || echo BLOCKED
  • Put the site's dbhost in place of the example. 3306 is the MySQL/MariaDB port. Works on both systems; nothing to install.
  • OPEN = the network path is fine; the problem is login or RDS itself (steps 3, 4).
  • BLOCKED after 5 seconds = can't reach it: RDS is down or rebooting, or the RDS security group doesn't allow this server.
  • Name or service not known = a typo in dbhost, or the RDS instance was renamed or deleted.
3. Can the site's user log in? (needs a database client)
mysql -h mydb.abc123xyz.us-east-1.rds.amazonaws.com -u school_user -p school -e "SELECT 1;"
  • Asks for the password (from config.php's dbpass line; nothing shows as you type). SELECT 1 only asks the database to answer "1", so it changes nothing.
  • A small table with 1 = login works.
  • Access denied for user = wrong user name or password, or that user isn't allowed from this server.
  • Too many connections = RDS has hit its connection limit (step 4).
  • mysql: command not found = no client installed. Skip to step 4.
4. Check RDS itself, in the AWS console

RDS › Databases › pick the instance:

StatusShould say Available. Rebooting, Modifying, Storage-full, or Maintenance explains a lot.
Monitoring › CPU utilizationPinned near 100% = the database is the bottleneck (slow pages, 504s).
Monitoring › Database connectionsA sudden jump, or flat at a ceiling = connection limit.
Monitoring › Free storage spaceNear zero = writes fail; Moodle errors on almost everything.
Logs & events › Recent eventsReboots, failovers, maintenance, and storage warnings, with times. Compare with when the problem started.
MOODLE NOTEIf several sites share one RDS instance, one site's heavy report or course restore can slow all of them. If every site using that RDS is slow at once, look at RDS first; if only one is, look at that site.
↑ Back to top

#7Is it the network, DNS, or SSL certificate?

READ-ONLYON YOUR MAC

For "can't be reached" and certificate warnings. Run these on your Mac, since the question is what visitors see.

1. Does the name point anywhere?
dig +short school.example.com
  • One or more addresses = the name works. Nothing = the DNS record is missing or wrong.
  • Your Mac may remember an old answer. Ask a public service instead: dig +short school.example.com @1.1.1.1. If that works but yours doesn't, it's just your Mac's memory (it clears on its own within minutes).
  • The address should match the server's Elastic IP in the EC2 console (or end in cloudfront.net / elb.amazonaws.com if it's behind one).
2. Is the server answering on the web port?
nc -zv -G 5 school.example.com 443
  • succeeded! = something is listening on 443 (HTTPS). The network is fine; look at Apache (§4).
  • Operation timed out = blocked or down: the server is stopped, or its security group doesn't allow port 443.
  • Connection refused = the server is up, but Apache isn't running (§2 step 6).
3. When does the certificate expire, and which names does it cover?
echo | openssl s_client -connect school.example.com:443 -servername school.example.com 2>/dev/null | openssl x509 -noout -subject -dates subject=CN=school.example.com notBefore=Sep 3 00:00:00 2026 GMT notAfter=Oct 2 23:59:59 2027 GMT
  • Replace the address in both places. notAfter is the expiry date; in the past = that's your warning.
  • subject CN= is the main name on the certificate. A different name = the browser warns it doesn't match.
Where the certificate lives decides the fix
On CloudFront or a load balancer (from AWS Certificate Manager)AWS renews it automatically, as long as its DNS validation record still exists. Check Certificate Manager in the console for its status.
On the server itself (for example Let's Encrypt)Renewed by a tool on the server, usually certbot. sudo certbot certificates lists them and their expiry dates.
EVERY SITE AT ONCE?If every server seems unreachable at the same moment, check your own internet and VPN first, then the AWS Health Dashboard. It's rarely all your servers at once.
↑ Back to top

#8Is it Moodle itself?

CHANGES THINGSON THE SERVER

When the server, PHP, and database look fine, but the site misbehaves. Run Moodle's command-line scripts from inside the site's Moodle folder, as the web server user, with the PHP version that site uses (§5).

Which PHP command runs that version?
ls /usr/bin/php* /usr/bin/php /usr/bin/php7.3 /usr/bin/php8.1

Use the one matching the site, like php8.1, in the commands below. (Names vary with how PHP was installed.) The web server user is apache on Amazon Linux 1, www-data on Ubuntu; the examples use Ubuntu.

Quick checks (read-only)
php8.1 -l config.phpTypo in config.php? No syntax errors detected = fine.
grep dataroot config.phpWhere moodledata is. Then ls -ld on that path: owner should be apache / www-data.
ls DATAROOT/climaintenance.htmlIf this file exists, the site is in maintenance mode (shows 503 to visitors). Replace DATAROOT with the path.
ps aux | grep cron.phpIs Moodle's cron running right now? One that started hours ago is probably stuck.
Site administration › NotificationsIn the browser: warns if cron hasn't run recently, and of pending upgrades.
Site administration › Reports › LogsIn the browser: what users were doing when it broke.
Purge caches (fixes many odd display problems)
sudo -u www-data php8.1 admin/cli/purge_caches.php

Safe; Moodle rebuilds them. The next few page loads are slower.

See the real error behind a blank page
sudo -u www-data php8.1 admin/cli/cfg.php --name=debug --set=32767
sudo -u www-data php8.1 admin/cli/cfg.php --name=debugdisplay --set=1

Turns on full error messages, shown on the page. Reload the broken page and read the error. 32767 is Moodle's "developer" level.

⚠ TURN IT OFF AGAINWhile on, every visitor sees error details, which can include file paths. As soon as you have the message:
sudo -u www-data php8.1 admin/cli/cfg.php --name=debugdisplay --set=0
sudo -u www-data php8.1 admin/cli/cfg.php --name=debug --set=0
Maintenance mode, on and off
sudo -u www-data php8.1 admin/cli/maintenance.php --enable
sudo -u www-data php8.1 admin/cli/maintenance.php --disable

Shows visitors a "site under maintenance" page while you work. Remember to disable it; a forgotten maintenance mode looks exactly like an outage.

RECENT CHANGE?A new or updated plugin is a common cause. Site administration › Plugins › Plugins overview can show recently changed plugins; compare with when the problem started.
↑ Back to top

Afterwards

#9Write it down

Five minutes now saves an hour next time. Keep a short note for each problem, in one place you can search, like a notes app or 1Password Secure Notes.

Template: copy these headings into your note
Date / time noticed: Site(s) and server: What users saw: (e.g. 504 on course pages) Who was affected: (one page / one site / whole server / everything) What changed just before: What I checked: (and what each showed) The cause: The fix: To stop it happening again:
TIPPaste the actual error lines from the logs into the note. Next time, searching your notes for part of an error message will find the fix.
↑ Back to top