VPS.TC
₺ | $
Server Status
Turkey Istanbul, Türkiye
Active
USA New York, USA
Active
Cart Total:
View Cart
How to Monitor a VPS with Prometheus and Grafana
Technology

How to Monitor a VPS with Prometheus and Grafana

Avatar of Defne Defne 16 min read 0 Comments
Share:

Quick Summary – Prometheus and Grafana Setup

Prometheus collects VPS metrics and Grafana turns them into dashboards and alerts. Keep the services separated by role, restrict their network access, and test the complete notification path.

  • Collect metrics — Use Node Exporter to expose CPU, memory, filesystem, network, and load metrics.
  • Set intervals — Start with a 15- or 30-second scrape interval instead of collecting unnecessarily often.
  • Restrict access — Allow port 9100 only from Prometheus and keep management interfaces behind a VPN, tunnel, or protected reverse proxy.
  • Use service users — Run Prometheus and Node Exporter with dedicated non-root users.
  • Create alerts — Begin with actionable alerts for unreachable targets, low disk space, and memory pressure.
  • Test recovery — Verify targets, historical data, notification delivery, retention, and restore procedures.

A reliable Prometheus and Grafana setup turns a VPS from a machine you occasionally inspect into a system that tells you when its condition changes. Run Node Exporter on the target, let Prometheus scrape it over a restricted path, and use Grafana for dashboards and alerts. The useful part is not the first graph; it is the tested notification that reaches you before a customer does.

What Prometheus and Grafana actually do

An open SSH connection does not mean your VPS is healthy. The disk can fill, memory can run out, or Nginx can become too busy to serve new requests. Prometheus collects measurements as time series; Grafana turns those measurements into dashboards, graphs, and alert views. A useful monitoring setup does more than show the current CPU percentage. It shows when the change began.

Prometheus fetches metrics over HTTP and stores them in its own time-series database. Grafana does not measure the system directly. It connects to a data source such as Prometheus and visualizes query results. For a small VPS environment, the basic architecture looks like this:

🚀 Boost Your Speed with VPS Server!

Speed up your projects with high-performance SSD storage and 99.9% uptime guarantee.

Get VPS Hosting
  • Prometheus: Collects, stores, and queries metrics with PromQL.
  • Node Exporter: Exposes Linux kernel and system-resource metrics.
  • Grafana: Displays dashboards and alert information.
  • systemd: Starts and manages services during normal operation and boot.

Prometheus normally uses a pull model: at regular intervals, it requests the target’s /metrics endpoint. That detail matters when you open only the required firewall access and verify that targets are reachable.

What to do – Plan CPU, memory, disk, network, service availability, and alert delivery as separate parts of the monitoring design.

From the field

Early in my hosting job, I restarted MySQL on a server I thought was a test machine. It was production. The incident is why I verify the hostname before changing monitoring, service, or firewall settings.

Plan the VPS resources before installing anything

Running Prometheus, Grafana, and Node Exporter on one VPS is possible in a small environment. Resource usage depends on the number of targets, scrape interval, retention period, and metric cardinality. You do not need a large cluster to monitor one Linux VPS, but monitoring data should not be left to grow like an unbounded log file.

☁️ Gain Flexibility with Cloud Server!

Experience the power of cloud with scalable resources and instant backups.

Cloud Server Plans
Component Default port Purpose Recommended access
Prometheus 9090/TCP Collects and queries metrics Management network or VPN only
Grafana 3000/TCP Dashboards and alerts Behind HTTPS or limited to trusted IPs
Node Exporter 9100/TCP Server metrics Prometheus server only

Prometheus disk usage grows with the number of samples, labels, and retention period. Collecting every five seconds may produce more detailed graphs, but it also creates unnecessary sample volume. For a first setup, a scrape_interval of 15 or 30 seconds is enough for most VPS workloads. Include Prometheus’s own data directory when estimating disk usage.

A supported distribution such as Ubuntu 22.04 or 24.04, current packages, and a separate monitoring VPS make a cleaner starting point. If the monitoring server shares a VPS with the service it monitors, a complete host failure can take away the alarms as well. For critical systems, keeping Prometheus and Grafana on a different VPS is safer.

For a first look at process and memory consumption, the commands in Linux Process Management: Using ps, top, and kill are still useful. Grafana’s memory requirements can also rise as its database, plugins, and dashboard count increase.

What to do – Put the monitoring components on a separate VPS when possible, and decide on data retention before installation.

Tip

Start with 15 or 30 seconds for scrape_interval. A five-second interval can add sample volume without giving you a useful operational advantage on a small VPS.

Prometheus and Grafana setup: install the core services

The following example uses binary installations on Debian or Ubuntu, with separate service users. Distribution repositories may carry older versions, so check the official Prometheus and Grafana release pages before production work. The Prometheus and Node Exporter versions below are examples from the releases I used while preparing this procedure; verify the available version and SHA256 checksum on the day you install them.

Create the Prometheus user and directories

sudo useradd --no-create-home --shell /usr/sbin/nologin prometheus
sudo mkdir -p /etc/prometheus /var/lib/prometheus
sudo chown prometheus:prometheus /var/lib/prometheus

Keep the Prometheus configuration in /etc/prometheus/prometheus.yml and the time-series data under /var/lib/prometheus. Running the service as root only increases the damage a process vulnerability could cause.

Install the Prometheus binaries

cd /tmp
curl -LO https://github.com/prometheus/prometheus/releases/download/v2.55.1/prometheus-2.55.1.linux-amd64.tar.gz
tar xzf prometheus-2.55.1.linux-amd64.tar.gz
sudo cp prometheus-2.55.1.linux-amd64/prometheus /usr/local/bin/
sudo cp prometheus-2.55.1.linux-amd64/promtool /usr/local/bin/
sudo cp -r prometheus-2.55.1.linux-amd64/consoles /etc/prometheus/
sudo cp -r prometheus-2.55.1.linux-amd64/console_libraries /etc/prometheus/
sudo chown -R prometheus:prometheus /etc/prometheus

In production, compare the archive’s SHA256 checksum with the value published on the official release page. HTTPS protects the download in transit; it does not, by itself, prove that the file is the intended one.

Write the basic configuration

sudo vim /etc/prometheus/prometheus.yml
global:
  scrape_interval: 15s
  evaluation_interval: 15s

rule_files:
  - /etc/prometheus/alerts.yml

scrape_configs:
  - job_name: prometheus
    static_configs:
      - targets: ['127.0.0.1:9090']

  - job_name: node
    static_configs:
      - targets: ['127.0.0.1:9100']

The job_name and instance labels will be used later in PromQL queries. Validate the configuration before starting the service:

sudo -u prometheus promtool check config /etc/prometheus/prometheus.yml

A valid file returns a SUCCESS message. Fix indentation errors or unknown fields before starting the service.

Collect VPS metrics with Node Exporter

Node Exporter exposes Linux system metrics such as CPU, memory, filesystems, network traffic, and load in a format Prometheus can read. The basic flow is simple: run the exporter, then let Prometheus scrape port 9100.

sudo useradd --no-create-home --shell /usr/sbin/nologin node_exporter
cd /tmp
curl -LO https://github.com/prometheus/node_exporter/releases/download/v1.8.2/node_exporter-1.8.2.linux-amd64.tar.gz
tar xzf node_exporter-1.8.2.linux-amd64.tar.gz
sudo cp node_exporter-1.8.2.linux-amd64/node_exporter /usr/local/bin/
sudo chown node_exporter:node_exporter /usr/local/bin/node_exporter

Create the systemd unit:

sudo vim /etc/systemd/system/node_exporter.service
[Unit]
Description=Prometheus Node Exporter
After=network-online.target

[Service]
User=node_exporter
Group=node_exporter
Type=simple
ExecStart=/usr/local/bin/node_exporter

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now node_exporter
curl -s http://127.0.0.1:9100/metrics | head

The output should include metric help and type lines beginning with # HELP and # TYPE. Do not leave this endpoint exposed to the public internet. A firewall rule allowing only the Prometheus server to reach TCP port 9100 is enough.

If you also need application-specific Nginx metrics, plan an Nginx exporter or suitable metrics module after How to Install and Configure Nginx on Ubuntu. Node Exporter does not automatically provide request counts or upstream latency.

What to do – Run Node Exporter as its own user and allow TCP port 9100 only from the Prometheus server.

Run Prometheus safely with systemd

Create the Prometheus systemd unit:

sudo vim /etc/systemd/system/prometheus.service
[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 \
  --web.listen-address=127.0.0.1:9090 \
  --storage.tsdb.retention.time=15d \
  --storage.tsdb.retention.size=20GB

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now prometheus
sudo systemctl status prometheus --no-pager
curl -s http://127.0.0.1:9090/-/ready

An HTTP 200 response from /-/ready means Prometheus is ready to accept queries. If it does not start, read journalctl -u prometheus -n 50 --no-pager before restarting it. Incorrect paths, ownership, and YAML syntax usually show up there.

For Grafana, use the official signed Debian repository or a distribution package. Enable the service after installation:

sudo systemctl enable --now grafana-server
sudo systemctl status grafana-server --no-pager

Do not expose Grafana’s port 3000 directly to the public internet when a reverse proxy, HTTPS, and access restrictions can be used. If you put Grafana behind Nginx, check the domain, URL, and proxy headers separately; an access problem does not always mean that Grafana is stopped. Domain vs URL: What Is the Difference? is useful when those layers start getting mixed together.

Binding Prometheus to 127.0.0.1:9090 keeps its web interface off the external network. If Grafana runs on another VPS, redesign the listen address, firewall rules, and TLS requirements together. In many small environments, making management ports available only through an SSH tunnel or WireGuard is the lower-risk choice.

Early in my hosting job, I restarted MySQL on a machine I thought was a test server. It was production: twelve minutes of downtime and one angry customer email. Since then, I check the hostname before changing service bindings or firewall rules, and I keep production prompts visually distinct. Monitoring does not replace that habit, but it gives me another place to notice trouble.

What to do – Decide on the reverse proxy, firewall policy, and trusted access source before opening Prometheus or Grafana ports.

Caution

Do not expose Node Exporter on the public internet. Port 9100 should accept connections only from the Prometheus server, and Grafana should be protected with HTTPS and access controls.

Add Prometheus as Grafana’s data source

After the first Grafana login, open Connections, or Data sources in some versions, and add Prometheus. On the same VPS, use http://127.0.0.1:9090. If Grafana runs in a container while Prometheus runs on the host, 127.0.0.1 refers to the container, not the host. Use a reachable host address or service name instead.

Test the connection with Save & test. Then try these PromQL queries in Explore:

up
node_memory_MemAvailable_bytes
rate(node_cpu_seconds_total{mode="idle"}[5m])
100 - (node_filesystem_avail_bytes{mountpoint="/"} * 100 / node_filesystem_size_bytes{mountpoint="/"})

An up value of 1 means the target was reachable during the last scrape; 0 points to an access or exporter problem. The CPU query returns the idle ratio per core, so total utilization requires the right mathematical expression and panel unit. Filesystem queries may need filters for temporary filesystems.

Importing a ready-made dashboard is convenient, but do not trust an arbitrary JSON file. Inspect its metric names, variables, and queries. A mismatch between Prometheus, Node Exporter, or label versions can leave you with empty panels.

Start with the health of the VPS rather than placing too many series on one graph: CPU trend, available memory, the root filesystem, network traffic, and up status. If you are discussing TTFB down to individual milliseconds, first check that application and cache measurements actually exist.

Example

For a first dashboard, use CPU trend, available memory, root filesystem space, network traffic, and the up metric. Add application-specific metrics only after the basic target path works.

Choose alerts that lead to an action

Seeing a graph and receiving an incident notification are different things. Prometheus alerting rules define conditions; Alertmanager handles grouping, silencing, and delivery through email, webhooks, or other channels. For a small VPS, the first alerts should be measurable and actionable.

groups:
  - name: vps-health
    rules:
      - alert: InstanceDown
        expr: up{job="node"} == 0
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "Node Exporter is unreachable"

      - alert: RootFilesystemLow
        expr: 100 * node_filesystem_avail_bytes{mountpoint="/",fstype!~"tmpfs|overlay|squashfs"} / node_filesystem_size_bytes{mountpoint="/",fstype!~"tmpfs|overlay|squashfs"}  90
        for: 10m
        labels:
          severity: warning
        annotations:
          summary: "Available memory is low"

Narrow filesystem queries using the fstype, mountpoint, and device labels for your environment. Otherwise /run, container bind mounts, or virtual filesystems may produce noise. Set thresholds after observing normal behavior; that is how you avoid a night of false alarms.

Introduce the rule file through rule_files and validate it:

sudo -u prometheus promtool check rules /etc/prometheus/alerts.yml
sudo systemctl reload prometheus

Defining an alert is not enough. Test that the notification arrives and that the delivery status is visible in the email, webhook, or phone application. The monitoring system needs monitoring too. If Prometheus stops, Grafana may show old data for a while and create false confidence.

What to do – Document the threshold, waiting period, notification channel, and response step for every critical alert.

Set sensible retention for monitoring data

Prometheus stores data in its local TSDB by default. You can limit retention by time and disk size:

--storage.tsdb.retention.time=15d
--storage.tsdb.retention.size=20GB

Using both limits makes disk usage more predictable. A size limit helps prevent the data from consuming the entire disk, but leave space for the operating system, Grafana, and logs as well. Do not make Prometheus compete for the same disk with a busy application log directory.

For long-term capacity planning or many VPS targets, consider remote write, Thanos, or another long-term storage design. On a small VPS, establishing correct metrics and alert delivery comes first. A snapshot can help with recovery, but it is not the only backup of live Prometheus data. See What Is a VPS Snapshot? A Guide to Point-in-Time Backups for the distinction.

If you back up Prometheus data, test data consistency, the TSDB documentation, and the restore procedure separately. Also back up Grafana dashboard JSON, provisioning files, alert rules, and Prometheus configuration. Saving only the dashboard screen is not enough to rebuild the monitoring system.

What to do – Set time and size retention limits, reserve free disk space, and test a restore instead of treating a snapshot as the whole backup plan.

Verify the setup after installation

Start by checking the targets. In Prometheus, open Status > Targets and confirm that the Node Exporter target is UP. Then perform the same check from the command line:

curl -s http://127.0.0.1:9090/api/v1/targets | jq '.data.activeTargets[] | {instance,health,lastError}'

If health is up and lastError is empty, the scrape succeeded. connection refused usually points to a stopped Node Exporter or an incorrect address. context deadline exceeded suggests a firewall or network-delay problem.

Change the time range in Grafana panels and confirm that older data appears. Then deliberately trigger a test alert or use Alertmanager’s test mechanism. You should see the alert fire, get grouped, and close as separate stages.

On the monitoring VPS, regularly check journalctl -u prometheus, journalctl -u grafana-server, and disk usage. When a graph is empty, compare the target list, HTTP endpoint, labels, and query before restarting anything. Restarting without reading logs sometimes removes the only useful evidence.

If Grafana is published through DNS, check that the domain resolves to the correct address with dig +short. What Is DNS Propagation? How Long Does It Take? explains the difference between TTL behavior and what individual resolvers currently return.

What to do – Test target health, historical graphs, alert delivery, service logs, disk space, and DNS before calling the setup finished.

Check These Before Calling the Setup Complete

  • Create dedicated non-root users for Prometheus and Node Exporter.
  • Verify the downloaded release versions and SHA256 checksums.
  • Validate prometheus.yml and alert rules with promtool.
  • Allow Node Exporter access only from the Prometheus server.
  • Protect Grafana and Prometheus with suitable firewall and proxy rules.
  • Confirm targets, historical data, and alert delivery manually.
  • Test retention, backups, and a restore procedure.

Start with one VPS, one Node Exporter target, and three actionable alerts. Once the notification path works, add dashboards and application metrics based on questions you actually need to answer.

Explore VPS plans

Frequently Asked Questions

Can Prometheus and Grafana run on the same VPS?

Yes. This is reasonable for a small environment or a lab, especially when you are monitoring only a few targets. The trade-off is that a complete VPS failure can remove both the monitored service and the monitoring interface. For important systems, place Prometheus and Grafana on a separate VPS and restrict the connection between the monitoring server and exporters.

What is the difference between Prometheus and Grafana?

Prometheus collects and stores time-series metrics, then lets you query them with PromQL. Grafana reads data from Prometheus or another data source and presents it through dashboards, panels, and alert interfaces. Grafana does not replace the collector. You generally need a working Prometheus target before a Grafana panel can show useful server data.

Should port 9100 be open to the internet?

No. Node Exporter exposes host metrics and normally does not need public access. Allow TCP port 9100 only from the Prometheus server through a firewall or private network. Likewise, keep Prometheus's port 9090 restricted and protect Grafana with HTTPS, authentication, and an appropriate access policy.

How often should Prometheus scrape a VPS?

A 15- or 30-second scrape interval is a sensible starting point for most small VPS workloads. Shorter intervals can provide more detail, but they also create more samples and storage activity. Choose a shorter interval only when the operational question requires it, then observe disk usage and query performance instead of assuming more data is automatically better.

Why is a Grafana panel empty even though Node Exporter is running?

Check the target state in Prometheus first, then query up and inspect the panel's metric names, labels, and time range. Container networking can also make 127.0.0.1 point to the wrong machine. A dashboard built for a different Node Exporter or Prometheus version may reference labels or metrics that do not exist in your environment.

Is a VPS snapshot enough to back up Prometheus?

Not by itself. A snapshot can help with point-in-time recovery, but you should also preserve Prometheus configuration, alert rules, Grafana dashboards, provisioning files, and any required credentials. Test the restore procedure and confirm that the restored services can read their data and deliver an alert. An untested backup is only a hope with storage attached.

Sources

Avatar of Defne
Author

Defne