Skip to main content
Katapult

How to Set Up Prometheus & Grafana Monitoring on Ubuntu

1 Jul 2025 · 9 min read · Cloud, Devops & Infrastructure, Servers, Tutorials

Introduction

Keeping an eye on a production server is as important as shipping the code that runs on it. Without data you fly blind, guessing at CPU spikes, memory leaks, or a disk filling up in the middle of the night.

In this guide, you'll turn a fresh Ubuntu Virtual Machine [VM] on Katapult into a self-monitored machine using Prometheus for metrics collection and Grafana for dashboards. By the end you will:

  • scrape system-level metrics with Node Exporter
  • store and query them with Prometheus
  • explore live graphs in Grafana
  • know where to go next for alerting and extra exporters

We'll move step by step, starting from an up-to-date VM and ending with a dashboard that highlights the health of the host in real time.

Prerequisites

  • An Ubuntu Virtual Machine
  • A sudo-enabled user (not root)
  • Open outbound internet access (for package downloads)

Provision a Virtual Machine with Katapult Compute

  • Open the Katapult dashboard, in the sidebar choose Compute ▸ Virtual machines, then click Launch virtual machine.

Image

  • Select the data centre closest to your users or team.
  • For this walkthrough, the ROCK-3 plan (1 vCPU, 3 GB RAM, 25 GB NVMe) is enough. You can scale up later without rebuilding.

New Katapult users start with £100 free credit, so spinning up the 1 vCPU / 3 GB RAM VM needed for this guide (just £15 per month) costs you nothing while you test the stack.

  • Under Distributions pick Ubuntu 24.04. Although, this guide can be replicated in any Linux distro.

  • Keep the public IPv4 & IPV6 addresses that Katapult assigns.

  • Click Launch virtual machine. Provisioning takes less than a minute.

  • Once the VM is ready, you can SSH in like this:

   ssh root@<VM_IP>

Copy the root password shown in the VM details page and log in as root, then create a sudo user.

  • After logging in as root, create a new user with sudo privileges. Replace with your desired username:
# Create a new user

adduser <username>

# Add the user to the sudo group

usermod -aG sudo <username>

# Verify by switching to the new user and running a sudo command

su - <username>
whoami # should return the new username

That's it! Your fresh Ubuntu 24.04 VM is ready for the monitoring stack we'll set up next.

Architecture at a Glance

Before we get started, let's see how the monitoring pieces fit together on the VM. Metrics will flow through three small services:

[Grafana :3000] ───► [Prometheus :9090] ───► [Node Exporter :9100]
  • Node Exporter runs on the VM and exposes CPU, memory, disk, and network data over HTTP.
  • Prometheus pulls those metrics at regular intervals, stores them on disk, and offers a query API.
  • Grafana connects to Prometheus, turning raw numbers into time‑series graphs and dashboards.

The setup is self‑contained on one host, but you can point Prometheus at many exporters or move Grafana to another server later.

Update and Prep the VM

To get started, run these commands as a sudo-enabled user after logging in:

# Bring the system up to date
sudo apt update && sudo apt upgrade -y

# Install helper tools for downloads and archives
sudo apt install wget tar -y

# Add system users (no shell, no home) for the monitoring daemons
sudo useradd --system --no-create-home --shell /usr/sbin/nologin prometheus
sudo useradd --system --no-create-home --shell /usr/sbin/nologin node_exporter

# Create directories Prometheus will need
sudo mkdir -p /etc/prometheus /var/lib/prometheus
sudo chown -R prometheus:prometheus /etc/prometheus /var/lib/prometheus

Open the ports

  • Security group – open TCP 9090 (Prometheus) and TCP 3000 (Grafana) only to IPs you trust (your office VPN, a jump-box, or your own home IP). Avoid 0.0.0.0/0.
  • ufw on the VM – same idea, but host-level:
sudo ufw allow 9090/tcp 
sudo ufw allow 3000/tcp
  • HTTPS – both services ship with plain HTTP. You can put Nginx, Traefik, or Caddy in front, add a free Let's Encrypt cert, and protect Grafana with basic auth or OAuth.

That leaves us with a patched OS, reserved service accounts, and open ports—ready to drop in Prometheus next.

Install Prometheus

We'll install Prometheus through its precompiled binaries using the following steps:

  • We pull the tarball straight from the project's GitHub page and copy the binaries to /usr/local/bin:
   cd /tmp
   PROM_VERSION="3.4.1"
   wget https://github.com/prometheus/prometheus/releases/download/v${PROM_VERSION}/prometheus-${PROM_VERSION}.linux-amd64.tar.gz
   tar -xzf prometheus-${PROM_VERSION}.linux-amd64.tar.gz
   sudo cp prometheus-${PROM_VERSION}.linux-amd64/{prometheus,promtool} /usr/local/bin/

Make sure to download a binary that is compatible with your VM's architecture

  • In the downloaded folder, there is a prometheus.yml file which tells Prometheus to poll Node Exporter. We'll create ours by running the following commands:
   sudo tee /etc/prometheus/prometheus.yml > /dev/null <<'EOF'
   global:
     scrape_interval: 15s
     evaluation_interval: 15s
   scrape_configs:
     - job_name: 'node'
       static_configs:
         - targets: ['localhost:9100']
   EOF
   sudo chown prometheus:prometheus /etc/prometheus/prometheus.yml
  • Create a systemd unit file to run Prometheus as the prometheus user and restart it if the process exits:
   sudo tee /etc/systemd/system/prometheus.service >/dev/null <<'EOF'
   [Unit]
   Description=Prometheus
   Wants=network-online.target
   After=network-online.target

   [Service]
   User=prometheus
   Group=prometheus
   Type=simple
   ExecStart=/usr/local/bin/prometheus \
     --config.file=/etc/prometheus/prometheus.yml \
     --storage.tsdb.path=/var/lib/prometheus
   Restart=on-failure

   [Install]
   WantedBy=multi-user.target
   EOF
  • Reload systemd, start the service, and confirm it is active:
   sudo systemctl daemon-reload
   sudo systemctl enable --now prometheus
   sudo systemctl status prometheus

If the status shows "Active: running", Prometheus is now listening on http://<VM_IP>:9090.

Next, we'll install Node Exporter so Prometheus actually has metrics to scrape.

Install Prometheus Node Exporter

The Prometheus Node Exporter is a tiny Go binary that reads Linux metrics from /proc and makes them available on http://localhost:9100/metrics. Prometheus will scrape that endpoint every 15 seconds.

We'll install it for Prometheus through its precompiled binaries using the following steps:

  • Install v1.9.1, the latest stable release at the time of writing:
   cd /tmp
   NODE_EXPORTER_VERSION="1.9.1"

   wget https://github.com/prometheus/node_exporter/releases/download/v${NODE_EXPORTER_VERSION}/node_exporter-${NODE_EXPORTER_VERSION}.linux-${ARCH}.tar.gz
   tar -xzf node_exporter-${NODE_EXPORTER_VERSION}.linux-${ARCH}.tar.gz
   sudo cp node_exporter-${NODE_EXPORTER_VERSION}.linux-${ARCH}/node_exporter /usr/local/bin/

Why only one file? Everything Node Exporter needs is baked into that single static binary

  • Create a systemd unit file to the node exporter as the node_exporter user we created earlier:
   sudo tee /etc/systemd/system/node_exporter.service >/dev/null <<'EOF'
   [Unit]
   Description=Prometheus Node Exporter
   Wants=network-online.target
   After=network-online.target

   [Service]
   User=node_exporter
   Group=node_exporter
   Type=simple
   ExecStart=/usr/local/bin/node_exporter \
     --web.listen-address=:9100

   Restart=on-failure

   [Install]
   WantedBy=multi-user.target
   EOF
  • Reload systemd, start the service, and confirm it is active:
   sudo systemctl daemon-reload
   sudo systemctl enable --now node_exporter
   sudo systemctl status node_exporter --no-pager

You should see "Active: running". Node Exporter is now listening on http://<VM_IP>:9090/metrics.

  • You can also verify the metrics endpoint by running:
   curl http://localhost:9100/metrics

You should see output like this:

   # HELP go_gc_duration_seconds A summary of the wall-time pause (stop-the-world) duration in garbage collection cycles.
   # TYPE go_gc_duration_seconds summary
   go_gc_duration_seconds{quantile="0"} 2.117e-05
   go_gc_duration_seconds{quantile="0.25"} 7.5001e-05
   go_gc_duration_seconds{quantile="0.5"} 0.000383494
   go_gc_duration_seconds{quantile="0.75"} 0.000550436
   go_gc_duration_seconds{quantile="1"} 0.000787689
   go_gc_duration_seconds_sum 0.002410226
   go_gc_duration_seconds_count 7
   ....
  • Open http://<VM_IP>:9090/targets in your browser; the node job should display UP with a "last scrape" time below 15 seconds, confirming that Prometheus is successfully collecting metrics from Node Exporter.

Image

Prometheus is now gathering CPU, memory, disk, and network stats every scrape interval.

With the data pipeline in place, the final piece is a front-end: Grafana.

Install Grafana

Prometheus stores and serves raw time-series data, but its built-in web UI is not exactly interesting. Grafana fills that gap: it's an open-source visualisation layer that speaks PromQL, lets you build dashboards with click-and-drag panels, and ships with thousands of community templates. By wiring Grafana to Prometheus you turn numeric streams into real-time graphs, tables, and alerts—all through a polished browser interface running on port 3000.

We'll install Grafana from its official APT repository so future apt upgrade commands pull in the latest stable release automatically.

  • Add the Grafana repo and key:
   sudo apt install -y apt-transport-https software-properties-common gnupg
   sudo mkdir -p /etc/apt/keyrings/
   wget -q -O - https://apt.grafana.com/gpg.key | gpg --dearmor | sudo tee /etc/apt/keyrings/grafana.gpg > /dev/null
   echo "deb [signed-by=/etc/apt/keyrings/grafana.gpg] https://apt.grafana.com stable main" | sudo tee -a /etc/apt/sources.list.d/grafana.list
   sudo apt update
  • Install, start, and enable Grafana:
   sudo apt install -y grafana
   sudo systemctl daemon-reload
   sudo systemctl enable --now grafana-server
   sudo systemctl status grafana-server --no-pager

A green "Active: running" status means Grafana is up at http://<VM_IP>:3000.

With Grafana installed, open http://<VM_IP>:3000 in a browser to access the dashboard, sign in with admin / admin, and set a new password when prompted.

Image

Next, let's connect the Grafana dashboard to Prometheus!

Connect Grafana to Prometheus

You can connect the Prometheus service running in our VM to Grafana by following these steps:\n

  • Add Prometheus as a data source

    • In the sidebar choose Connections ▸ Data sources ▸ Add data source.
    • Select Prometheus.
    • Set the Prometheus Server URL to http://localhost:9090
    • Click Save & test. Grafana should reply with "Successfully Queried the Prometheus API"

Image

  • Import a starter dashboard
    • In the Grafana sidebar click Dashboards ▸ New ▸ Import.
    • Enter 1860 (Node Exporter Full) in the dashboard URL field and hit Load.
    • Select your Prometheus data source and click Import.

Image

  • You'll land on a live dashboard plotting CPU, memory, disk, and network metrics—the same data Node Exporter has been feeding into Prometheus.

Image

With Grafana in place, the monitoring stack is complete:

Grafana ───► Prometheus ───► Node Exporter

Add Remote Machines to Prometheus

So far Prometheus scrapes only the local VM. Let's widen the lens and pull in metrics from other hosts—databases, worker nodes, or anything else that can run Node Exporter.

  • Repeat the "Install Prometheus Node Exporter" steps on every machine you want to watch. Remember to Open port 9100 in the host's firewall or cloud security group so your Prometheus VM can reach it.

  • Back on the Prometheus VM, add the extra hosts to /etc/prometheus/prometheus.yml:

  scrape_configs:
    - job_name: 'node'
      # Override the global default and scrape targets from this job every 5 seconds.
      scrape_interval: 5s
      static_configs:
        - targets:
            - 'localhost:9100'        # the Prometheus VM itself
            - '10.0.0.12:9100'        # database server
            - 'worker-02.internal:9100' # background worker
  • You can list IPs, DNS names, or mix both. While you're here, label them so dashboards stay readable:
        - targets: ['10.0.0.12:9100']
          labels:
            role: db
            env: prod
  • Save the file, then reload Prometheus without a full restart:
  sudo systemctl reload prometheus
  • Open http://<PROM_VM_IP>:9090/targets. All new nodes should show UP. If one is DOWN, double-check the firewall and hostname.
  • The Node Exporter Full dashboard you imported earlier already has an $instance drop-down. Pick any host in that list to see its own CPU, memory, and disk graphs—no extra work required.

That's it! You now have one Prometheus installation scraping many exporters.

Benefits and Best Practices

Prometheus and Grafana give you live data on CPU, memory, disk, and network usage. With this information, you can get the following:

  • Instant visibility: CPU, memory, disk, and network graphs update every few seconds, so you spot spikes before users feel them.
  • Single-pane view: Prometheus scrapes; Grafana shows. One login for all host metrics keeps troubleshooting fast.
  • Low overhead: The three services together use under 200 MB RAM on a small VM and add almost no CPU load.
  • Scales out: Point Prometheus at exporters on other VMs, or move Grafana to its own host without changing anything you've learned here.

Grafana Dashboard Best Practices

Use these tips to build clear and useful Grafana dashboards.

Do Why
Keep panels focused – one graph per resource (CPU, memory, disk, network). Cuts visual noise so problems jump out.
Use short time ranges for live ops – 5 m to 1 h Makes spikes obvious so you can act fast.
Add thresholds – red at 80 % CPU, amber at 70 %, for example. Gives an instant "good/bad" read without reading numbers.
Use template variables (for example, $instance) Add a dropdown that lists every target your Prometheus job scrapes; pick a VM from the list and the same dashboard instantly shows that host's metrics. No need to copy or rebuild the dashboard for each machine.
Save versions after edits. Grafana's revision history lets you roll back a bad tweak.

Prometheus & Node Exporter Tips

  • Scrape every 15s for host metrics: Faster rarely adds value but costs disk.
  • Store 15–30 days of data locally: Ship older data to long-term storage if needed.
  • Label everything (instance, job, env) early: Re-labeling later is painful.
  • Snapshot before upgrades: Take a snapshot with Katapult so you can mount it or spin up a clone if an update misbehaves.

Learn more about Prometheus best practices in the official documentation.

Next steps

  • Add file-based service discovery or Consul for large fleets.
  • Add alerting – Pair Prometheus with alertmanager, then set rules such as "CPU > 80 % for 5 m". See the Prometheus Alerting docs.
  • Secure endpoints – Put nginx or Traefik in front with HTTPS and basic auth, or use Grafana's built-in OAuth.
  • Expand exporters – Try blackbox_exporter for ping checks or postgres_exporter for database metrics.

About the author

Shedrack A

Technical Copywriter

Start building today with £100 free credit

Sign up and you’ll be up and running on Katapult in less than a minute.