Overview

You’ve deployed your application. Now you need to know:

This guide covers FOSS monitoring tools from simple to comprehensive. You don’t need to run Prometheus if a lightweight uptime checker suffices.

Difficulty: Intermediate (some tools require Docker or manual setup) Time to implement: 15 minutes (lightweight) to 2 hours (full stack)


Lightweight: Uptime Kuma

For most personal projects and small VPS setups, Uptime Kuma is the sweet spot. It’s lightweight, self-hosted, and monitors HTTP/TCP/DNS/ping endpoints with a beautiful UI.

Install with Docker

docker run -d \
  --name uptime-kuma \
  -p 3001:3001 \
  -v uptime-kuma-data:/app/data \
  --restart unless-stopped \
  louislam/uptime-kuma:1

Access at http://your-server-ip:3001.

Set Up Your First Monitor

  1. Click Add New Monitor
  2. Choose HTTP(s) for a web service
  3. Enter the URL (e.g., https://yourapp.com)
  4. Set Heartbeat Interval (every 60 seconds is good)
  5. Enable TLS Info to check certificate expiration
  6. Add notification channels (email, Gotify, Telegram, etc.)

Features You’ll Use

Resource Usage

Uptime Kuma uses ~50-100 MB RAM and almost no CPU at idle. Perfect for a small VPS.


Lightweight: Stat Ping (For Quick Checks)

For basic server monitoring without a full UI, use uptimed and custom scripts:

Server Uptime Daemon

sudo apt install uptimed -y
sudo systemctl enable uptimed
sudo systemctl start uptimed

# Check uptime records
uprecords

Quick Resource Check Script

Create ~/health.sh:

#!/bin/bash
echo "=== Server Health Check ==="
echo "Uptime: $(uptime -p)"
echo "Load: $(cat /proc/loadavg)"
echo "Memory: $(free -h | grep Mem)"
echo "Disk: $(df -h / | tail -1)"
echo "Top 5 CPU processes: $(ps aux --sort=-%cpu | head -6)"
echo "Top 5 RAM processes: $(ps aux --sort=-%mem | head -6)"

Run with bash ~/health.sh or schedule via cron.


Medium: Netdata

Netdata is a distributed, real-time performance and health monitoring system. It gives you second-level metrics for CPU, RAM, disk, network, and running processes — with beautiful charts and zero configuration.

Install

bash <(curl -Ss https://my-netdata.io/kickstart.sh)

Netdata auto-detects everything and starts collecting immediately. Access at http://your-server-ip:19999.

Key Features

Configure Alarms

Netdata alarms go to /etc/netdata/health_alarm_notify.conf. To enable email:

# Edit the alarms config
sudo nano /etc/netdata/health_alarm_notify.conf

# Set receiver email
DEFAULT_RECIPIENT_EMAIL="you@yourdomain.com"

Resource Usage

Netdata uses ~5-10% of one CPU core at idle and ~150-200 MB RAM. On a small VPS, this is noticeable but manageable.

# Limit Netdata resources if needed
sudo nano /etc/netdata/netdata.conf
[global]
    update every = 5
    history = 3600

Full Stack: Grafana + Prometheus

For comprehensive observability, you want the full monitoring stack:

Architecture

Node Exporter (port 9100) ──┐
cAdvisor (port 8080) ───────┼──→ Prometheus (port 9090) ──→ Grafana (port 3000)

[Your App] (port 8000) ─────┘

Docker Compose Setup

Create monitoring/docker-compose.yml:

version: '3.8'
services:
  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus
    restart: unless-stopped
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
      - prometheus_data:/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'

  grafana:
    image: grafana/grafana:latest
    container_name: grafana
    restart: unless-stopped
    ports:
      - "3000:3000"
    volumes:
      - grafana_data:/var/lib/grafana
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=YOUR_STRONG_PASSWORD

  node-exporter:
    image: prom/node-exporter:latest
    container_name: node-exporter
    restart: unless-stopped
    ports:
      - "9100:9100"
    command:
      - '--path.procfs=/host/proc'
      - '--path.sysfs=/host/sys'
      - '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)'

  cadvisor:
    image: gcr.io/cadvisor/cadvisor:latest
    container_name: cadvisor
    restart: unless-stopped
    ports:
      - "8080:8080"
    volumes:
      - /:/rootfs:ro
      - /var/run:/var/run:ro
      - /sys:/sys:ro
      - /var/lib/docker/:/var/lib/docker:ro
      - /dev/disk/:/dev/disk:ro

volumes:
  prometheus_data:
  grafana_data:

volumes:
  from: {}

Prometheus Config

Create monitoring/prometheus.yml:

global:
  scrape_interval: 15s

scrape_configs:
  - job_name: 'node'
    static_configs:
      - targets: ['node-exporter:9100']

  - job_name: 'cadvisor'
    static_configs:
      - targets: ['cadvisor:8080']

  - job_name: 'prometheus'
    static_configs:
      - targets: ['localhost:9090']

Start Monitoring Stack

cd monitoring
docker compose up -d

# Access Grafana at http://your-server-ip:3000
# Default credentials: admin / admin (change immediately!)

# Prometheus at http://your-server-ip:9090

Import Dashboards

In Grafana:

  1. Click +Import
  2. Enter dashboard ID (e.g., 1860 for Node Exporter Full)
  3. Select Prometheus data source
  4. Click Import

Log Monitoring: Loki + Grafana

For log aggregation, add Loki:

  loki:
    image: grafana/loki:latest
    container_name: loki
    restart: unless-stopped
    ports:
      - "3100:3100"
    volumes:
      - ./loki-config.yml:/etc/loki/local-config.yaml

Add loki to Prometheus config as another scrape target.


Quick Reference: Which Tool When?

Use CaseToolRAM UsageSetup Time
Uptime monitoringUptime Kuma~100 MB5 min
Real-time metricsNetdata~150 MB5 min
Full observabilityGrafana + Prometheus~500 MB1-2 hr
Log aggregationLoki + Grafana~300 MB1 hr
Basic health checkCustom script~0 MB5 min

Alerting: Don’t Just Monitor, Alert

Monitoring without alerting is just pretty charts. Configure notifications:

Uptime Kuma Alerts

Netdata Alarms

Pre-configured for: CPU usage > 80%, RAM > 80%, disk > 80%, service down, etc.

Grafana Alerting

// Grafana alert rule example
- name: HighCPU
  condition: A > 80
  data:
    - refId: A
      query: avg(node_cpu_seconds_total{mode="user"})

Pro Tips

Use a Reverse Proxy

All these tools have web UIs. Don’t expose them directly to the internet — put them behind a reverse proxy with authentication:

# Example Caddy config for Uptime Kuma
yourstatus.com {
    reverse_proxy localhost:3001
    basicauth /* {
        user HASHED_PASSWORD
    }
}

Set Up Alert Fatigue Prevention

Resource Budget for Monitoring

On a 2 GB VPS:


Tired of managing servers?

This site helps you find the right FOSS hosting solution. If you'd rather have experts handle the infrastructure, OpsHelp offers fully managed hosting that supports open source.