Grafana transforms raw Prometheus time-series data into actionable visual dashboards through a drag-and-drop interface backed by the powerful PromQL query language. On RHEL 8 with Prometheus and Node Exporter already collecting host metrics, you can build a professional server monitoring dashboard in under an hour — displaying CPU usage, memory consumption, disk I/O, and network throughput across multiple servers from a single pane of glass. This tutorial walks through creating a dashboard from scratch, writing the essential PromQL queries, choosing the right panel types, adding template variables for multi-host selection, and exporting the finished dashboard as a reusable JSON file.
Prerequisites
- RHEL 8 server with Prometheus installed and running
- Node Exporter running on each server you want to monitor (port 9100)
- Grafana installed and accessible in a browser — default port 3000
- Prometheus added as a data source in Grafana (Configuration → Data Sources → Add data source → Prometheus)
- Basic familiarity with the Grafana UI
Step 1 — Create a New Dashboard
Log in to Grafana and create a blank dashboard to hold all your server panels.
# In the Grafana UI:
# 1. Click the "+" icon in the left sidebar
# 2. Select "New dashboard"
# 3. Click "Add visualization"
# 4. Choose your Prometheus data source from the dropdown
# Save the dashboard immediately with a meaningful name:
# Press Ctrl+S (or Cmd+S on macOS) → enter "RHEL 8 Server Metrics" → Save
Giving the dashboard a name before adding panels prevents accidental loss of work if the browser is closed.
Step 2 — Add a CPU Usage Panel
Create the first panel to show CPU utilisation as a percentage. Use the Time series panel type for trend visibility over time.
# PromQL query — CPU usage % per instance (all cores averaged)
100 - (avg by (instance) (irate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)
# To show per-core breakdown:
100 - (irate(node_cpu_seconds_total{mode="idle",instance="$instance"}[5m]) * 100)
# Useful derived metrics:
# User space CPU:
avg by (instance) (irate(node_cpu_seconds_total{mode="user"}[5m])) * 100
# System (kernel) CPU:
avg by (instance) (irate(node_cpu_seconds_total{mode="system"}[5m])) * 100
# I/O wait:
avg by (instance) (irate(node_cpu_seconds_total{mode="iowait"}[5m])) * 100
In the panel editor, set the Unit to Percent (0-100), the Min to 0, and the Max to 100. Set a threshold at 80% (yellow) and 95% (red) in the Thresholds section.
Step 3 — Add Memory, Disk I/O, and Network Panels
Add three more visualizations covering the remaining key system resources. Use Time series for disk and network, and a Gauge or Stat panel for a quick at-a-glance memory percentage.
# --- Memory usage % ---
# Gauge panel — shows current value with a fill indicator
100 - ((node_memory_MemAvailable_bytes{instance="$instance"} /
node_memory_MemTotal_bytes{instance="$instance"}) * 100)
# --- Memory breakdown (Time series) ---
# Used:
node_memory_MemTotal_bytes{instance="$instance"} -
node_memory_MemAvailable_bytes{instance="$instance"}
# Cached:
node_memory_Cached_bytes{instance="$instance"}
# Buffers:
node_memory_Buffers_bytes{instance="$instance"}
# --- Disk I/O read/write bytes per second (Time series) ---
irate(node_disk_read_bytes_total{instance="$instance",device!=""}[5m])
irate(node_disk_written_bytes_total{instance="$instance",device!=""}[5m])
# --- Network receive/transmit bytes per second (Time series) ---
irate(node_network_receive_bytes_total{instance="$instance",device!~"lo"}[5m])
irate(node_network_transmit_bytes_total{instance="$instance",device!~"lo"}[5m])
For disk and network panels, set the Unit to bytes/sec so Grafana auto-scales to KB/s, MB/s, or GB/s. Apply negative Y-axis values to write/transmit series to create a classic “butterfly” bidirectional chart.
Step 4 — Add a Stat Panel Row for Key KPIs
Add a row of Stat panels at the top of the dashboard showing single current values for system uptime, total CPU cores, total RAM, and the number of running processes — giving operators a quick system fingerprint at a glance.
# System uptime (Stat panel — Unit: duration (s))
node_time_seconds{instance="$instance"} - node_boot_time_seconds{instance="$instance"}
# Total CPU logical cores (Stat panel — Unit: short)
count by (instance) (node_cpu_seconds_total{mode="idle",instance="$instance"})
# Total RAM in bytes (Stat panel — Unit: bytes)
node_memory_MemTotal_bytes{instance="$instance"}
# Number of running processes (Stat panel — Unit: short)
node_procs_running{instance="$instance"}
# Filesystem used % for root partition (Stat panel — Unit: percent)
100 - ((node_filesystem_avail_bytes{instance="$instance",mountpoint="/"}
/ node_filesystem_size_bytes{instance="$instance",mountpoint="/"}) * 100)
Step 5 — Add Template Variables for Multi-Server Selection
Template variables let a single dashboard serve all servers by adding a dropdown at the top. Navigate to Dashboard settings → Variables → Add variable.
# Variable settings in the Grafana UI:
# Name: instance
# Type: Query
# Data source: Prometheus
# Query: label_values(node_uname_info, instance)
# Regex: (leave blank to show all, or filter e.g. .*:9100)
# Multi-value: enable if you want to select multiple servers at once
# Include All: enable to add an "All" option
# After saving, all panels that reference {instance="$instance"}
# will update dynamically when you select a different server from the dropdown.
Add a second variable for device (disk device) and interface (network adapter) using label_values(node_disk_read_bytes_total{instance="$instance"}, device) to make disk and network panels filterable as well.
Step 6 — Export the Dashboard as JSON
Save and export the finished dashboard so it can be version-controlled or imported to other Grafana instances.
# In the Grafana UI:
# 1. Open the dashboard
# 2. Click the Share icon (top bar) → Export → Save to file
# This downloads dashboard.json to your browser
# Alternatively, use the Grafana HTTP API:
curl -s -u admin:admin
"http://localhost:3000/api/dashboards/uid/YOUR_DASHBOARD_UID"
| python3 -m json.tool > /tmp/rhel8_server_metrics_dashboard.json
# To import the JSON on another Grafana instance:
# Dashboards → Import → Upload JSON file → select your file → Import
Replace YOUR_DASHBOARD_UID with the UID shown in the dashboard URL (/d/UID/title). Store the exported JSON in your infrastructure repository alongside your Prometheus configuration files.
Conclusion
You now have a complete Grafana dashboard displaying CPU, memory, disk I/O, and network metrics for your RHEL 8 servers, with template variables enabling instant switching between hosts. The PromQL queries cover the most operationally relevant signals — including I/O wait, memory pressure, and network saturation — and the exported JSON file means this dashboard can be reproduced across environments with a single import. Combining this dashboard with Grafana alerting rules on the same metrics gives you both visibility and proactive notification from a single tool.
Next steps: How to Install and Configure cAdvisor for Container Monitoring on RHEL 8, How to Use Prometheus Blackbox Exporter for Endpoint Monitoring on RHEL 8, and How to Configure SNMP Monitoring on RHEL 8.