Add Basic Monitoring to Your Dokploy Server
27 Oct 2025You do not need Prometheus and Grafana to know your server is about to fall over. For a single VPS, here is a setup that takes twenty minutes and covers the failures that actually happen.
What actually kills small servers
In rough order of frequency:
- Disk full (Docker images and logs)
- Out of memory (a build or a runaway container)
- A container crash-looping unnoticed
- Certificate expiry
Notice that CPU is not on the list. Monitor for these four, not for a dashboard you will never open.
Built-in Dokploy monitoring
Dokploy ships basic metrics. Go to Monitoring in the sidebar for CPU, memory, disk, and network per container. It is enough to answer “which container is eating the box right now”.
Turn on the server threshold alerts under Settings → Notifications. Set:
- Disk usage above 80%
- Memory usage above 85%
Route them to Slack or email. These two alerts catch most of the list above.
A disk check you can trust
Dokploy’s disk metric covers the volume it knows about. Add a cron that checks everything:
sudo tee /usr/local/bin/disk-alert.sh >/dev/null <<'EOS'
#!/bin/bash
THRESHOLD=80
df -h --output=pcent,target | tail -n +2 | while read pct mount; do
val=${pct%\%}
if [ "$val" -ge "$THRESHOLD" ]; then
curl -s -X POST "$SLACK_WEBHOOK" \
-H 'Content-Type: application/json' \
-d "{\"text\":\"Disk $mount at $pct on $(hostname)\"}"
fi
done
EOS
sudo chmod +x /usr/local/bin/disk-alert.sh
Run it hourly:
echo "0 * * * * root SLACK_WEBHOOK='https://hooks.slack.com/...' /usr/local/bin/disk-alert.sh" | sudo tee /etc/cron.d/disk-alert
Catch crash loops
A container that restarts every thirty seconds can go unnoticed for days. This finds them:
docker ps --format '{{.Names}}\t{{.Status}}' | grep -i 'restarting\|unhealthy'
Wrap it in the same alert pattern. If it outputs anything, something is wrong.
External uptime check
Everything above runs on the server. If the server dies, so does your monitoring. You need one check from outside.
Uptime Kuma self-hosted on a different provider works, or a free tier from any uptime service. Point it at a real endpoint that touches your database:
app.get('/health', async (req, res) => {
try {
await db.query('SELECT 1')
res.json({ ok: true })
} catch (e) {
res.status(503).json({ ok: false })
}
})
A health check that only proves the web server is listening tells you nothing useful.
When to add more
Add Prometheus when you have more than one server, or when you start asking questions like “was the latency spike before or after the deploy”. Until then, four alerts and an external ping cover you.