Nextcloud Monitoring Loop Fix | Generated by AI
Here’s the full post-mortem:
🔍 Root Cause — What Happened
The Chain of Events
- Uptime-Kuma (your uptime monitor) was polling
GET /apps/dashboard/on Nextcloud every ~6 minutes - This triggered Nextcloud’s Dashboard app to load → which calls
PresetManager::refreshPresetApps() PresetManageriterates through every installed app and all their config entries, cloning config objects and rebuilding defaults for each of 10+ “lexicon presets”- Somewhere in this chain (possibly a third-party app or a lexicon config bug in Nextcloud 33.0.0) it hit an infinite loop — every request ran for 3600+ seconds before PHP’s
max_execution_timekilled it - Each time Uptime-Kuma polled, a new Apache worker picked up the request and joined the loop
- Over ~1.5 hours, 9 Apache workers all saturated at 55-65% CPU each → load hit 11 → fan at full blast
Why it wasn’t obvious
- The parent Apache process (PID 4561) showed 0% CPU — it just managed workers
- All the hot processes were inside the Nextcloud container (docker namespace)
topon the host saw them, but they appeared as containerd-shim processes, not named Apache
✅ The Fix — What We Did
1. Emergency — Stop the bleeding
docker restart nextcloud-app-1
Cleared all 9 stuck Apache workers immediately. Load dropped from 11 → 3.68 in seconds, fan quieted.
2. Root cause — Uptime-Kuma polling the wrong URL
- Changed monitor from
http://192.168.1.36:8080/apps/dashboard/→http://192.168.1.36:8080/status.php /status.phpis Nextcloud’s dedicated health endpoint — returns{"installed":true,"maintenance":false}instantly, no app loading, no PHP heavy lifting
3. Patch the wound — Upgrade Nextcloud 33.0.0 → 33.0.2
- Downloaded new Nextcloud tarball
- Used
rsyncto overlay new source files onto the volume (preservingconfig/,data/,custom_apps/,themes/) - Ran
php occ upgrade— migrated DB schema, updated 13 apps - Backed up DB first with
pg_dump
🛡️ How to Prevent This
For Nextcloud specifically:
| Do | Don’t |
|---|---|
Use /status.php for health checks |
Poll /apps/dashboard/ or any UI route |
| Set Uptime-Kuma interval ≥ 60s for PHP apps | Rapid polling of PHP apps |
| Monitor container CPU individually | Only look at host load average |
General fan/noise prevention:
- Set up alerting on container CPU — run this cron to alert before it gets bad:
docker stats --no-stream --format ": " | awk -F: '$2>80 {print $1" high CPU"}' - Rotate logs — prevent log files in containers from filling disk and causing swap pressure
- Restart containers periodically — many PHP apps (Nextcloud, LibreChat) benefit from occasional restarts to clear memory leaks
🔧 Quick Diagnostic Commands
# Find what's hottest
docker stats --no-stream
# See all processes inside a container
docker top <container>
# Watch container CPU in real time
watch -n2 'docker stats --no-stream --format " "'
# Nextcloud health
curl -s http://localhost:8080/status.php
# Full system load
uptime && top -b -n1 | head -8
Any container at sustained >50% CPU for more than a few minutes = investigate immediately.