How to Build Grafana Dashboards for Linux Server Metrics on RHEL 7
Grafana is the de facto standard for visualising time-series data collected by Prometheus, InfluxDB, Graphite, and dozens of other data sources. A well-constructed Grafana dashboard can surface CPU saturation, memory pressure, disk I/O bottlenecks, and network anomalies at a glance, dramatically reducing the mean time to identify the root cause of an incident. This guide goes beyond basic panel creation to cover PromQL queries for key Linux metrics, dashboard variables and templating, annotations for deployment events, linking between dashboards, and the import/export workflow for sharing dashboards as JSON. All examples target a RHEL 7 server with Node Exporter and Prometheus already running.
Prerequisites
- RHEL 7 server with Grafana installed and running (port 3000)
- A Prometheus data source already configured in Grafana
- Node Exporter running on the target servers (port 9100)
- Basic familiarity with the Grafana UI and Prometheus
Step 1: Understand Grafana Panel Types
Choosing the right panel type for each metric is the foundation of an effective dashboard. Grafana provides many panel types, but a handful cover almost every Linux monitoring use case.
- Time series (Graph) — the workhorse panel. Shows metric values over time as a line, bar, or area chart. Ideal for CPU usage, network throughput, request rates, and any metric that changes continuously.
- Stat — displays a single current value in large text with optional colour thresholds and a sparkline. Perfect for a “current CPU load” or “uptime” indicator on a summary row.
- Gauge — a radial or horizontal gauge showing how close a value is to a maximum. Excellent for disk space usage percentage where you want visual proximity to a limit.
- Table — renders query results as a sortable table. Useful for listing all hosts with their current metric values in a single view.
- Heatmap — visualises the distribution of a metric across time using a colour intensity grid. Ideal for request latency percentiles and I/O wait histograms.
- Bar chart — compares values across categories at a point in time. Good for per-disk IOPS comparisons or per-service memory usage rankings.
Step 2: PromQL Queries for Core Linux Metrics
The following PromQL expressions cover the metrics you will need for a complete Linux server dashboard. All queries assume the $instance template variable is set (described in Step 4).
CPU Metrics
# Overall CPU utilisation (all modes except idle)
100 - (avg by (instance) (rate(node_cpu_seconds_total{instance="$instance", mode="idle"}[5m])) * 100)
# Per-mode CPU breakdown (user, system, iowait, steal)
avg by (mode) (rate(node_cpu_seconds_total{instance="$instance", mode!="idle"}[5m])) * 100
# CPU I/O wait — key indicator of disk or NFS bottlenecks
avg by (instance) (rate(node_cpu_seconds_total{instance="$instance", mode="iowait"}[5m])) * 100
# Load average (1-minute)
node_load1{instance="$instance"}
# Load average relative to CPU count (load per core)
node_load1{instance="$instance"} / count by (instance) (node_cpu_seconds_total{instance="$instance", mode="idle"})
Memory Metrics
# Used memory (excluding buffers/cache — "available" definition)
node_memory_MemTotal_bytes{instance="$instance"} - node_memory_MemAvailable_bytes{instance="$instance"}
# Memory utilisation percentage
(1 - (node_memory_MemAvailable_bytes{instance="$instance"} / node_memory_MemTotal_bytes{instance="$instance"})) * 100
# Swap utilisation
(node_memory_SwapTotal_bytes{instance="$instance"} - node_memory_SwapFree_bytes{instance="$instance"}) / node_memory_SwapTotal_bytes{instance="$instance"} * 100
# Cached memory
node_memory_Cached_bytes{instance="$instance"} + node_memory_Buffers_bytes{instance="$instance"}
Disk Metrics
# Disk space used percentage per mount point
(1 - node_filesystem_avail_bytes{instance="$instance", fstype!~"tmpfs|overlay|squashfs"} /
node_filesystem_size_bytes{instance="$instance", fstype!~"tmpfs|overlay|squashfs"}) * 100
# Disk read throughput (bytes/sec)
rate(node_disk_read_bytes_total{instance="$instance", device="$device"}[5m])
# Disk write throughput (bytes/sec)
rate(node_disk_written_bytes_total{instance="$instance", device="$device"}[5m])
# Disk IOPS (read + write operations per second)
rate(node_disk_reads_completed_total{instance="$instance", device="$device"}[5m]) +
rate(node_disk_writes_completed_total{instance="$instance", device="$device"}[5m])
# Disk I/O utilisation percentage (time spent on I/O)
rate(node_disk_io_time_seconds_total{instance="$instance", device="$device"}[5m]) * 100
Network Metrics
# Network receive throughput (bytes/sec)
rate(node_network_receive_bytes_total{instance="$instance", device="$device"}[5m])
# Network transmit throughput (bytes/sec)
rate(node_network_transmit_bytes_total{instance="$instance", device="$device"}[5m])
# Network error rate (receive errors per second)
rate(node_network_receive_errs_total{instance="$instance", device="$device"}[5m])
# TCP connections currently established
node_netstat_Tcp_CurrEstab{instance="$instance"}
Step 3: Create a New Dashboard and Add Panels
In the Grafana UI, click + → Dashboard → Add new panel. Select the Prometheus data source. Paste a PromQL query from Step 2 into the query editor. In the Panel section on the right, configure the panel type, title, units, and thresholds.
For the CPU utilisation panel:
- Panel type: Time series
- Title:
CPU Utilisation (%) - Unit: Percent (0-100) under Standard options → Unit
- Min:
0, Max:100 - Thresholds: green < 70, yellow 70–90, red > 90
For the disk space gauge panel:
- Panel type: Gauge
- Title:
Disk Usage — $device - Unit: Percent (0-100)
- Thresholds: green < 75, yellow 75–90, red > 90
Step 4: Add Dashboard Variables for Templating
Dashboard variables allow a single dashboard to serve all servers and devices by replacing hardcoded label values with dropdown selectors. Navigate to Dashboard settings (gear icon) → Variables → New variable.
Datasource Variable
Name: datasource
Type: Data source
Label: Data Source
Query: Prometheus
Instance Variable (server selector)
Name: instance
Type: Query
Label: Instance
Query: label_values(node_uname_info, instance)
Refresh: On dashboard load
Sort: Alphabetical (asc)
Multi: false (single select)
Device Variable (disk/network interface)
Name: device
Type: Query
Label: Device
Query: label_values(node_disk_io_time_seconds_total{instance="$instance"}, device)
Refresh: On time range change
Multi: true (allow selecting multiple devices)
After saving variables, use $instance and $device in all your PromQL queries (as shown in Step 2). The dashboard title can also reference variables: set it to Linux Server — $instance.
Step 5: Link Dashboards Together
When you have multiple dashboards (overview, detailed CPU, detailed storage), linking between them with the current variable values pre-filled improves navigation. In Dashboard settings → Links, add a dashboard link:
- Type: Dashboard
- Title:
Storage Details - Tags:
linux(to link to all dashboards with that tag) - Enable Include current time range and Include current template variable values
You can also add data links to individual panels (right-click a panel → Edit → Data links) so clicking a time series point navigates to a detailed drill-down dashboard with the relevant filters pre-applied.
Step 6: Add Annotations for Deployment Events
Annotations overlay vertical markers on time series panels to show when deployments, configuration changes, or incidents occurred. Navigate to Dashboard settings → Annotations → Add annotation query.
Name: Deployments
Data source: Prometheus
Query: changes(process_start_time_seconds{instance="$instance"}[10m]) > 0
Step: 60s
Tags: deploy
Alternatively, you can push annotations directly to Grafana’s built-in annotation store via its HTTP API from your CI/CD pipeline:
# Push an annotation from a deployment script
curl -s -X POST
-H "Content-Type: application/json"
-H "Authorization: Bearer <grafana-api-key>"
-d '{
"dashboardId": 5,
"panelId": 1,
"time": '"$(date +%s000)"',
"tags": ["deploy", "production"],
"text": "v2.4.1 deployed to production"
}'
http://grafana.example.com:3000/api/annotations
Step 7: Import Community Dashboards from grafana.com
Grafana Labs maintains a community dashboard library at https://grafana.com/grafana/dashboards/. Instead of building dashboards from scratch, you can import popular pre-built dashboards and then customise them.
Recommended dashboard IDs for RHEL 7 / Node Exporter:
- 1860 — Node Exporter Full (the most comprehensive Linux metrics dashboard)
- 405 — Grafana Node Exporter Server Metrics
- 11074 — Node Exporter for Prometheus Dashboard
To import: click + → Import, enter the dashboard ID, select your Prometheus data source when prompted, and click Import. The dashboard is immediately available with all its panels configured.
Step 8: Export a Dashboard as JSON
To back up a dashboard, share it with a colleague, or store it in version control, export it as JSON.
# Via the Grafana HTTP API (replace 5 with your dashboard ID or use UID)
curl -s
-H "Authorization: Bearer <grafana-api-key>"
"http://grafana.example.com:3000/api/dashboards/uid/linux-server-overview"
| python -m json.tool > linux-server-overview.json
# To import it back (on another Grafana instance or after a restore)
curl -s -X POST
-H "Content-Type: application/json"
-H "Authorization: Bearer <grafana-api-key>"
-d @linux-server-overview.json
"http://grafana.example.com:3000/api/dashboards/import"
In the UI, use Dashboard settings (gear) → JSON Model to view and copy the raw JSON, or use the Share → Export option to download a .json file.
Conclusion
You now have the skills to build production-quality Grafana dashboards for RHEL 7 servers. By selecting the right panel type for each metric, writing accurate PromQL expressions for CPU, memory, disk, and network data, and leveraging dashboard variables to make a single dashboard serve an entire fleet, you can create monitoring views that are both informative and efficient to maintain. Annotations tie metrics to real-world events like deployments, making post-incident analysis far more effective. Community dashboards provide an excellent starting point that you can refine for your specific environment, and the JSON export workflow ensures your dashboards are version-controlled and reproducible across environments.