Back to tutorials
Tutorial

VPS Monitoring Tutorial: Set Up Uptime, Alerts, and Resource Tracking on Ubuntu (2026)

VPS monitoring tutorial for 2026: set up uptime checks, CPU/RAM/disk alerts, and logs on Ubuntu with practical commands.

By Anurag Singh
Updated on Jun 05, 2026
Category: Tutorial
Share article
VPS Monitoring Tutorial: Set Up Uptime, Alerts, and Resource Tracking on Ubuntu (2026)

Your VPS can look “up” while customers see a white screen, timeouts, or a checkout that won’t load. This VPS monitoring tutorial gives you a solid baseline. You’ll run uptime checks from outside the server, resource alerts from inside it, and a log routine that gets you to the cause fast.

This stack matches real hosting failures. You’ll monitor SSH reachability, HTTP status, and TLS expiry.

You’ll also track CPU/RAM pressure, disk space and inodes, plus the services that keep WordPress and PHP sites running. That includes Nginx/Apache, PHP-FPM, and MySQL/MariaDB.

Everything runs cleanly on Ubuntu Server 24.04 LTS and stays easy to maintain in 2026.

What you’ll build (and why this specific setup works)

  • External uptime monitoring with Uptime Kuma (HTTP/HTTPS, keyword checks, ping, TCP port checks).
  • Internal metrics + alert rules with Prometheus + Node Exporter (CPU, RAM, disk, network, load, pressure stall info).
  • Dashboards with Grafana (prebuilt Node Exporter dashboards, plus a couple of useful panels).
  • Log triage with journalctl + Nginx/Apache logs (so alerts lead to fixes).

If you want a server that stays predictable during spikes, set up monitoring before you start “tuning.” Graphs and timelines let you make targeted changes.

That includes changes like the ones in our Nginx performance optimization tutorial. You can also prove the change worked.

Prerequisites and sizing checklist

You’ll need one Ubuntu VPS to host the monitoring stack.

For a small fleet (1–10 VPS), a 2 vCPU / 4 GB RAM server is usually enough. Keep retention modest (7–15 days).

For 30+ servers, step up to 4 vCPU / 8 GB. Increase disk to match.

  • Ubuntu Server 24.04 LTS (monitoring host)
  • At least 40–80 GB disk (Grafana + Prometheus data)
  • One domain or subdomain (optional but recommended): monitor.example.com
  • Ports: 22 (SSH), 80/443 (web), plus internal-only 3000/9090/9100 where possible

If you don’t want to maintain the OS, patches, and firewall rules yourself, a managed VPS hosting plan from HostMyCode can keep both monitoring and production workloads steady.

If you prefer full control, start with a standard HostMyCode VPS.

Step 1: Harden the monitoring host basics (fast, not fancy)

Dashboards don’t belong on a wide-open box with password SSH and exposed ports. Keep it simple. Patch, use SSH keys, and lock the firewall down.

Update and reboot if needed

sudo apt update
sudo apt -y upgrade
sudo reboot

Confirm SSH keys and disable password auth (recommended)

If you haven’t hardened SSH yet, follow this guide: VPS hardening tutorial.

At a minimum, set:

sudo nano /etc/ssh/sshd_config.d/99-hardening.conf

PasswordAuthentication no
PermitRootLogin no
sudo systemctl reload ssh

Enable UFW with explicit ports

Only expose 80/443 publicly. Keep Prometheus (9090) and Node Exporter (9100) private.

sudo apt -y install ufw
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status verbose

For a more complete hosting-friendly UFW pattern (including Fail2Ban-friendly rules), use: UFW firewall setup tutorial.

Step 2: Install Docker and Uptime Kuma for external checks

Uptime Kuma is your first line of defense. It measures what users experience.

These checks run from the monitoring host, not from inside the server you’re testing.

Install Docker Engine (Ubuntu 24.04)

sudo apt -y install ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg

echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo $VERSION_CODENAME) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

sudo apt update
sudo apt -y install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo systemctl enable --now docker

Run Uptime Kuma

sudo mkdir -p /opt/uptime-kuma

sudo docker run -d \
  --name uptime-kuma \
  --restart=always \
  -p 3000:3000 \
  -v /opt/uptime-kuma:/app/data \
  louislam/uptime-kuma:1

Kuma is now available at http://YOUR_SERVER_IP:3000. Don’t keep it exposed like this.

Put it behind HTTPS and basic auth with Nginx.

Step 3: Reverse proxy Kuma with Nginx + HTTPS

Monitoring dashboards collect sensitive details. That can include hostnames, admin URLs, and internal notes.

Treat this like an admin panel. Lock it down.

Install Nginx

sudo apt -y install nginx
sudo systemctl enable --now nginx

Create basic auth credentials

sudo apt -y install apache2-utils
sudo htpasswd -c /etc/nginx/.htpasswd monitoradmin

Nginx site config for monitor.example.com

sudo nano /etc/nginx/sites-available/monitor.example.com
server {
  listen 80;
  server_name monitor.example.com;

  location / {
    proxy_pass http://127.0.0.1:3000;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;

    auth_basic "Monitoring";
    auth_basic_user_file /etc/nginx/.htpasswd;
  }
}
sudo ln -s /etc/nginx/sites-available/monitor.example.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

Issue a Let’s Encrypt certificate

Use the same certbot approach you’d use for any VPS site. For the full walkthrough, see: SSL certificate setup guide.

sudo apt -y install certbot python3-certbot-nginx
sudo certbot --nginx -d monitor.example.com

Your dashboard is now on https://monitor.example.com, protected by HTTPS and basic auth.

Step 4: Add Uptime Kuma monitors that catch real hosting outages

Set up checks that match how sites actually fail. “Ping works” doesn’t mean checkout works.

  • HTTP(s) 200 check: https://www.example.com/
  • Keyword check: match a string that only appears on a healthy page (for example, a footer brand line). This catches “200 OK” error templates.
  • TCP port check: 443 and 22 for basic reachability.
  • Certificate expiry: Kuma can warn before TLS certs expire (set 14/7/3 day reminders).
  • DNS check (practical): monitor the apex and www hostnames to catch mispointed records after migrations.

Alert routing: email and Slack/Telegram

If you plan to page yourself by email from your VPS, treat deliverability as a setup task. Don’t leave it for later.

Configure SPF/DKIM/DMARC, then test with real inboxes.

Also confirm reverse DNS for the sending IP. Many providers penalize you without it: reverse DNS setup guide.

Step 5: Install Prometheus + Node Exporter for internal resource monitoring

Kuma answers “is it down?” Prometheus helps you answer “what changed?”

It helps you catch disk filling up, RAM exhaustion, or CPU steal time spikes on a noisy host.

This section installs Prometheus and Grafana on the monitoring host. Then you’ll install Node Exporter on each VPS you want to watch.

Install Prometheus and Grafana from Ubuntu packages

Ubuntu 24.04 ships stable builds that work well for small and mid-size fleets. If you later need a specific upstream release, you can switch then.

For most setups, the Ubuntu packages are a sensible starting point.

sudo apt -y install prometheus prometheus-node-exporter grafana
sudo systemctl enable --now prometheus
sudo systemctl enable --now grafana-server

Grafana listens on port 3000 by default. Don’t expose it directly.

Put it behind Nginx on a separate subdomain (or keep it private on a VPN). Below, you’ll move Grafana to port 3001 to avoid conflicting with Kuma.

Move Grafana to port 3001 (avoid clashing with Kuma)

sudo nano /etc/grafana/grafana.ini

Set:

[server]
http_addr = 127.0.0.1
http_port = 3001
sudo systemctl restart grafana-server

Reverse proxy Grafana with Nginx + basic auth

sudo htpasswd -c /etc/nginx/.htpasswd-grafana grafanaadmin
sudo nano /etc/nginx/sites-available/grafana.example.com
server {
  listen 80;
  server_name grafana.example.com;

  location / {
    proxy_pass http://127.0.0.1:3001;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;

    auth_basic "Grafana";
    auth_basic_user_file /etc/nginx/.htpasswd-grafana;
  }
}
sudo ln -s /etc/nginx/sites-available/grafana.example.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
sudo certbot --nginx -d grafana.example.com

Log in at https://grafana.example.com. The default Grafana credentials are typically admin / admin.

Change them right away.

Install Node Exporter on each monitored VPS

On each target VPS (the servers running your sites), install Node Exporter:

sudo apt update
sudo apt -y install prometheus-node-exporter
sudo systemctl enable --now prometheus-node-exporter

By default it binds on :9100. Don’t expose it to the internet.

Lock Node Exporter down to the monitoring host

On the target VPS, allow port 9100 only from your monitoring host IP.

sudo ufw allow from MONITORING_HOST_IP to any port 9100 proto tcp
sudo ufw status

If you use firewalld instead of UFW (common on AlmaLinux/Rocky), add a rich rule or source-limited port rule.

The requirement doesn’t change: source limit it.

Add scrape targets to Prometheus

On the monitoring host:

sudo nano /etc/prometheus/prometheus.yml

Add your servers under scrape_configs:

scrape_configs:
  - job_name: "node"
    static_configs:
      - targets:
          - "server1.example.com:9100"
          - "server2.example.com:9100"
          - "203.0.113.10:9100"
sudo systemctl restart prometheus

Quick sanity check from the monitoring host:

curl -s http://server1.example.com:9100/metrics | head

Step 6: Add dashboards you’ll actually use

You don’t need dozens of dashboards. You need one view that answers, fast: is it CPU, RAM, disk, or network?

Then add a WordPress-specific view if you host WordPress.

Import a Node Exporter dashboard

In Grafana:

  1. Go to Connections → Data sources and add Prometheus with URL http://127.0.0.1:9090.
  2. Go to Dashboards → New → Import.
  3. Import a Node Exporter dashboard (common community dashboards include “Node Exporter Full”).

Two panels worth adding: disk inode usage and CPU steal

Disk space alerts catch the obvious failures. Inode exhaustion wastes hours.

The disk can look “fine,” but uploads, cache writes, or plugin updates start failing.

  • Inodes used (%) (per filesystem): (node_filesystem_files_free / node_filesystem_files) * 100 (invert to show used)
  • CPU steal (%) (virtualization contention): rate(node_cpu_seconds_total{mode="steal"}[5m])

If steal time stays high, your VM is fighting for CPU at the hypervisor layer. That’s usually your cue to move to a larger VPS or a dedicated box.

Step 7: Create alert rules that map to hosting incidents

Charts are for diagnosis. Alerts are for action.

In 2026, the simplest setup on Ubuntu is Grafana Alerting (rules + contact points) with Prometheus as the data source.

Recommended starter alerts (copy and tune)

  • Disk space: warn at 80%, critical at 90% for / and for your web/data volumes.
  • Inodes: warn at 70%, critical at 85%.
  • RAM pressure: sustained low available memory (or swap activity) for 10 minutes.
  • Load spike: load average > (vCPU count × 1.5) for 10 minutes.
  • HTTP error rate: if you have a blackbox check (optional), alert when 5xx appears repeatedly.

Example PromQL snippets

Disk used (%) (exclude tmpfs):

100 * (1 - (node_filesystem_avail_bytes{fstype!~"tmpfs|overlay"} / node_filesystem_size_bytes{fstype!~"tmpfs|overlay"}))

Memory available (%):

100 * (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)

Swap activity (page-in rate):

rate(node_vmstat_pswpin[5m])

Give alerts a duration window (5–15 minutes) so you don’t get paged for harmless spikes.

Step 8: Tie alerts to fixes with a log triage routine

Build a repeatable loop: alert → confirm → isolate → fix.

The commands below are a dependable starting set for WordPress and PHP hosting.

Quick commands for incident response

  • Disk space and inodes
    df -h
    df -i
    sudo du -xh /var | sort -h | tail -n 20
  • Top CPU/RAM consumers
    top
    ps aux --sort=-%mem | head
    ps aux --sort=-%cpu | head
  • Nginx / Apache errors
    sudo tail -n 200 /var/log/nginx/error.log
    sudo tail -n 200 /var/log/apache2/error.log
  • PHP-FPM status
    sudo systemctl status php8.3-fpm --no-pager
    sudo journalctl -u php8.3-fpm -n 200 --no-pager
  • Kernel and OOM kills
    sudo journalctl -k -n 200 --no-pager
    sudo journalctl -k | grep -i "out of memory" | tail

If you see repeated 429/403 from bots or credential stuffing on /wp-login.php, rate limiting often calms things down fast.

Use the specific config patterns in our Nginx rate limiting tutorial.

Step 9: Add one migration-safe check (prevents the classic outage)

Migrations usually fail at DNS or TLS, not during file transfer.

Add these Kuma checks before you move anything:

  • Monitor the old server IP and the new server IP (temporary direct checks)
  • Monitor https://example.com and https://www.example.com separately
  • Add a keyword check that confirms the correct site version (e.g., “Release: 2026.06.05” in the footer)

For a migration sequence that consistently lands near-zero downtime, follow: Server migration tutorial.

Operational checklist (printable)

  • Uptime Kuma behind HTTPS + basic auth
  • At least: HTTP check, keyword check, TCP 443 check, cert expiry warning
  • Prometheus scraping Node Exporter for each VPS
  • Node Exporter port 9100 restricted to monitoring host IP
  • Grafana behind HTTPS + basic auth (or VPN-only)
  • Alerts: disk %, inode %, memory available %, swap activity, sustained load
  • Documented “alert → logs → fix” routine in your ops notes

Summary: your next 60 minutes of monitoring work

Start with Kuma monitors for your storefront and admin endpoints. Then add Node Exporter on the servers that matter most.

After you’ve collected a week of “normal,” adjust thresholds to your workload instead of guessing.

If you’re doing this for customer sites (or multiple WordPress installs), you’ll get the cleanest signal from a dedicated monitoring node on a stable network.

HostMyCode lets you scale from a small HostMyCode VPS to dedicated servers as your monitoring and hosting fleet grows.

If you run client sites, treat monitoring as part of the service—not an add-on. A dedicated monitoring VPS keeps alerts and dashboards online even when a production server is struggling. Start with a HostMyCode VPS, or choose managed VPS hosting if you want help with OS maintenance and secure defaults.

FAQ

Should I run monitoring on the same VPS as my websites?

For a personal site, you can. For client sites or anything revenue-critical, don’t.

If the web VPS runs out of disk or locks up, your monitoring goes down too. You lose visibility when you need it most.

How many servers can one small monitoring VPS handle?

As a practical baseline, a 2 vCPU / 4 GB RAM monitoring VPS can handle about 10–20 Node Exporter targets with 15s–30s scrape intervals and 7–15 days retention.

As you add targets, keep an eye on Prometheus disk usage and memory.

What’s the single most useful alert for WordPress hosting?

Disk space plus inode usage. WordPress updates, caches, and backups can burn through inodes long before the disk “fills.”

Alerts at 70–85% inode usage prevent a lot of late-night outages.

Can I get alerts by email reliably from a VPS?

Yes, but only if you configure DNS (SPF/DKIM/DMARC) and rDNS correctly and avoid sending from a “new” IP with no reputation.

Use the deliverability tutorials linked above before you rely on email paging.

Do I need Grafana if I already have Uptime Kuma?

You can start with Kuma alone, but you’ll still end up guessing root cause.

Grafana + Prometheus pays for itself the first time you correlate a 502 spike with memory pressure or disk saturation.