Build a Grafana Dashboard
Build a Grafana dashboard for metrics — Linux · networking · telemetry.
Focus: build a grafana dashboard for metrics
You've spent days configuring exporters, wiring up Prometheus scrape jobs, and staring at raw metric endpoints — but when your manager asks "how's the system doing?", you still can't answer without a terminal and a prayer. That's the problem this lesson solves: raw telemetry is data, not insight. By building a Grafana dashboard for metrics, you turn scattered time series into a living, at-a-glance view of your Linux hosts and network — the difference between monitoring and actually seeing what's happening.
The problem this lesson solves
Raw metrics are noisy. A single host can expose hundreds of series: CPU idle ticks, memory fragmentation, TCP retransmits, disk I/O latencies. Even with Prometheus querying, you're stuck writing ad-hoc queries in a browser — slow, error-prone, and impossible to share. Dashboards give your team a single pane of glass, but poorly built dashboards are just as bad: too many metrics, clashing units, no context, and nobody dares change a panel. This lesson teaches you to build a Grafana dashboard for metrics that's useful — focused on your questions, not just your data.
Core concept / mental model
Think of a Grafana dashboard as a control room, not a data dump. Every panel answers a question: Is the disk filling? Are we dropping packets? Is the API latency climbing? The dashboard is your mental model of the system — laid out left to right, top to bottom, like reading a story: start with broad health, drill into specific subsystems.
- Data source — where the metrics live (Prometheus, InfluxDB, CloudWatch, etc.)
- Panel — a single visualization (graph, gauge, table, stat)
- Row — a group of panels with a shared theme (e.g. "Network")
- Variables — dashboard-level placeholders (e.g.
$host) that let you filter panels without editing them
A dashboard is only as good as its defaults. When you open it, the first 10 seconds should answer: Is anything wrong right now? Green/red status panels on top, trends below, and a time series selector that actually works.
How it works step by step
Building a Grafana dashboard for metrics follows a repeatable flow — from connecting data to publishing a shareable link.
-
Install Grafana and start the service. - Use your distro's package manager (e.g.
apt install grafanaon Debian/Ubuntu,dnfon RHEL). - Start and enable the service withsystemctl enable --now grafana-server. -
Access the web UI and log in. - Default URL:
http://localhost:3000- Default credentials:admin/admin(you'll be forced to change it on first login). -
Add a data source. - Navigate to Configuration → Data Sources → Add data source. - Choose Prometheus (or your stack's source) and set the URL (e.g.
http://localhost:9090). - Click Save & Test — Grafana verifies connectivity and shows a green "Data source is working" message. -
Create a dashboard. - Dashboards → New → New Dashboard → Add a new panel. - In the query editor, pick your data source and write a PromQL query, e.g.
rate(node_cpu_seconds_total{mode="idle"}[5m])to show idle CPU. - Configure the visualization type, title, and unit; adjust the time range tolast 15 minutesfor a sensible default. -
Add more panels for each metric group — CPU, memory, disk, network.
-
Set up variables so the dashboard becomes reusable across hosts and environments.
-
Save, share, and iterate — export JSON or build a provisioning file if you want version-controllable dashboards.
Hands-on walkthrough
Let's build a functional dashboard for a single Linux host. We'll assume Prometheus is already scraping node_exporter (if not, refer to the previous lesson on setting up exporters).
Step 1: Install and run Grafana
# On Debian/Ubuntu
sudo apt update && sudo apt install -y grafana
sudo systemctl enable --now grafana-server
# Verify
systemctl status grafana-server --no-pager
Step 2: Log in and add Prometheus
Open http://localhost:3000, log in with admin/admin, then set a strong password. Go to Configuration → Data Sources → Add data source, pick Prometheus, and set the URL to http://localhost:9090. Click Save & Test — you should see the green success banner.
Step 3: Create your first panel — CPU usage
From Dashboards → New → Add panel:
Query editor:
- Data source: Prometheus
- Query: 100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)
- Legend: {{instance}}
- Unit: percent (0-100)
- Visualisation: Time series
This shows the non-idle CPU percentage — a more intuitive "busy" metric. Add a threshold (e.g. red above 85) by clicking on Thresholds in the panel edit.
Step 4: Add memory, disk, and network panels
Memory used:
- Query: (node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes) / node_memory_MemTotal_bytes * 100
- Unit: percent
Disk space used:
- Query: (1 - (node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"})) * 100
- Unit: percent
- Tip: filter to mountpoint="/" to avoid tons of per-disk series
Network receive bytes:
- Query: rate(node_network_receive_bytes_total[5m])
- Unit: B/s (or bits/s — pick and be consistent!)
Arrange panels into a sensible layout: status gauges on top, time series below.
Step 5: Add a host variable
Now make the dashboard reusable for multiple hosts.
- Dashboard settings → Variables → Add variable
- Name:
host - Type:
Query - Data source: Prometheus
- Query:
label_values(node_uname_info, instance) - Enable Multi-value and Include All option
- Update each panel's query to filter by
instance=~"$host"
Query example after variable:
100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle", instance=~"$host"}[5m])) * 100)
Now use the dropdown at the top of the dashboard to switch between hosts — without touching a single panel.
Step 6: Time range & refresh
Set the default time range to last 15 minutes and auto-refresh to 30s (dashboards settings → General). This makes the dashboard ready the moment you open it.
Expected output
When you save and open the dashboard, you'll see:
- Four (or more) panels with live charts
- A host dropdown filtering everything
- Threshold colors (e.g. red CPU when above 85%)
- A clean, shareable URL like http://localhost:3000/d/<uid>/my-host-dashboard
Compare options / when to choose what
Grafana supports many data sources, and your choice affects both dashboard design and query syntax. Here's a quick comparison:
| Data source | Best for | Query language | Notes |
|---|---|---|---|
| Prometheus | Pull-based metrics, Kubernetes, cloud-native | PromQL | Most common with Grafana; great with node_exporter |
| InfluxDB | Push-based, IoT, older stacks | Flux or InfluxQL | Good for high-cardinality event data |
| CloudWatch | AWS services (EC2, RDS, Lambda) | CloudWatch Metrics math | Native AWS metrics, but lag and cost can be issues |
| Loki | Logs, not metrics | LogQL | Use for log correlation, not usually for host metrics |
For a Linux networking telemetry stack, Prometheus is the go-to — mature, well-documented, and designed for this exact use case. If you're already in AWS and only need EC2 metrics, CloudWatch might be simpler — no extra service to run. InfluxDB shines for high-write-rate IoT data.
Troubleshooting & edge cases
Panel shows "No data"
- Check the data source is reachable from the Grafana server: curl http://localhost:9090/api/v1/targets from the Grafana host.
- Verify your query matches the metric name — common typo: node_cpu_seconds_total vs node_cpu.
- Look for time range issues: if you set last 1 minute, node_exporter only scrapes every 15s — you may need at least 2-3 minutes of data.
Missing host variables
- label_values only works if the label instance exists on the metric. Run curl 'http://localhost:9090/api/v1/query?query=node_uname_info' to verify. If no results, your exporter isn't running.
- Ensure the variable name in the query is wrapped with ~ and " — exact match won't work with multi-value.
Login page loops or says "invalid credentials"
- Check trunk access: default credentials are admin/admin — after first login you must change it. If locked out, reset with grafana-cli admin reset-admin-password newpass.
- If you're behind a reverse proxy, set root_url in /etc/grafana/grafana.ini to match your public URL.
Dashboard loads slowly
- Too many panels with heavy queries. Reduce the time range, add rate and avg to cut cardinality, or use recording rules for expensive PromQL queries.
- Consider enabling caching (Grafana's caching plugin) or using a dedicated read replica if using a SQL-based source.
Wrong units or values
- Double-check units: node_memory_MemTotal_bytes is bytes, not megabytes. Use Grafana's unit dropdown (bytes → GB) instead of manual division when possible.
- For network rates, remember rate gives per-second — a 5m rate of bytes is the right approach; don't sum without rate.
What you learned & what's next
You now know how to build a Grafana dashboard for metrics from scratch — from connecting Prometheus to designing panels that actually answer questions. You've mastered the core loop: query, visualize, filter, iterate. You can explain the difference between data sources, you've countered common pitfalls like no-data panels and misconfigured variables, and you've made your dashboard reusable with variables.
This lesson covers the visualization side of telemetry. Next in the track, we'll move to alerting — turning these dashboards into proactive alarms (e.g. page on CPU > 90% for 10 minutes). Alerting is where monitoring stops being passive and starts saving your sleep.
Keep this dashboard as your foundation — you'll build alert rules on top of the same queries.
Practice recap
Build a two-panel dashboard for memory used and disk I/O on your local host using only PromQL queries you've learned. Add a $host variable that filters both panels, then set a threshold red at 90%. If you get stuck, revisit the troubleshooting section — then move on to the next lesson on alerting.
Common mistakes
- Creating panels from raw counters without using
rate(), leading to always-increasing graphs that are impossible to read. - Forgetting to filter on
instance=~"$host"after adding a variable — so the dropdown does nothing and panels show all hosts mixed. - Setting units inconsistent between panels (e.g. bytes vs bits) — the chart is correct but the legend is misleading.
- Using a too-short default time range (like
last 1 minute) when scrapes every 15s — results in empty or sparse panels on first load. - Posting sensitive dashboards to public Grafana instances without changing default admin password.
Variations
- Provisioning dashboards as JSON in a Git repo and loading them via Grafana provisioning config — enables code review and CI/CD.
- Using the Grafana CLI or API to create dashboards programmatically instead of clicking through the UI.
- Building panels from a SQL data source (e.g. PostgreSQL) instead of Prometheus — different query syntax but same visualization principles.
Real-world use cases
- A SRE team monitors a microservices cluster: CPU, memory, network, and disk panels per host, filtered by Kubernetes node.
- A network admin tracks bandwidth and packet loss across multiple routers using SNMP exporters and a Grafana dashboard with a
$routervariable. - A startup uses Grafana to visualize customer-facing API latency and error rates from a Prometheus + Node.js exporter, triggering alerts via Alertmanager.
Key takeaways
- A Grafana dashboard is a control room, not a data dump — every panel should answer a question.
- Start with broad health checks on top, drill down into subsystems below.
- Use variables to make a dashboard reusable across hosts and environments.
- Match the data source to the use case: Prometheus for cloud-native, CloudWatch for AWS, InfluxDB for high-write IoT.
- Always use
rate()for counters and consistent units to keep graphs meaningful. - Version-control your dashboard JSON for collaboration and reproducibility.
Keep learning
Related tutorials, quizzes, and articles for this topic.
Discussion
Questions, corrections, and tips help everyone reading this page.
0 comments
Add a comment
No comments yet — start the thread.