Installing & running Prometheus

This section documents the current Prometheus 3.x line (latest 3.14.0) as published at the Prometheus documentation and the current Grafana 13.x line (latest 13.2.1) as published at the Grafana documentation, which are the references these pages are written and verified against. No specific patch version is pinned. Some capabilities (Grafana Enterprise-only features, Grafana Cloud-hosted services, and long-term-storage systems like Thanos/Cortex/Mimir) are linked, not documented in depth.

This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production, since both projects iterate quickly.

This section’s bibliography lists the reference material consulted while preparing these pages.

Prometheus is a single self-contained binary: no external database, no cluster to stand up before it scrapes its first target. This page covers getting that binary (or its Docker image) running, the minimal prometheus.yml it needs, the built-in expression browser used to sanity-check what it has collected, adding node_exporter as a real scrape target, and writing a first alerting rule.

Installing Prometheus

The binary tarball

Prometheus ships as a single statically linked binary plus a default config file, packaged per OS/ architecture on the downloads page. No package manager or root install is required:

tar xvfz prometheus-*.tar.gz
cd prometheus-*/
./prometheus --config.file=prometheus.yml
# https://prometheus.io/docs/prometheus/latest/installation/

The extracted directory contains the prometheus server binary, the promtool binary (used to check and unit-test config and rule files), a default prometheus.yml, and a console_libraries/ consoles pair used by the (largely superseded) console templates feature. By default the server listens on port 9090 and writes its time-series database under ./data.

Docker

The official image is published as prom/prometheus on Docker Hub. Bind-mount a config file over the image’s default one and publish port 9090:

docker run -d --name prometheus -p 9090:9090 \
  -v "$PWD/prometheus.yml:/etc/prometheus/prometheus.yml" \
  prom/prometheus
# https://prometheus.io/docs/prometheus/latest/installation/

The container’s entrypoint already points --config.file at /etc/prometheus/prometheus.yml, so the bind-mounted file is picked up on start. For anything beyond a single local instance — persistent volumes, resource limits, TLS — see Containers & Kubernetes Monitoring; for the docker run and bind-mount options themselves, see Running Containers.

A first prometheus.yml

Configuration is a single YAML file, reloadable without a restart via SIGHUP or the /-/reload HTTP endpoint (when --web.enable-lifecycle is set). The minimal skeleton scrapes Prometheus itself:

global:
  scrape_interval: 15s     # how often to scrape targets by default
  evaluation_interval: 15s # how often to evaluate rules

scrape_configs:
  - job_name: "prometheus"
    static_configs:
      - targets: ["localhost:9090"]
# https://prometheus.io/docs/prometheus/latest/getting_started/

Every entry under scrape_configs is a job: a named group of one or more targets scraped with the same interval, timeout, and metric relabeling rules. static_configs is the simplest way to list targets by hand; real deployments usually discover them dynamically instead, which is covered in Service Discovery & Relabeling. For the config file’s full syntax and every scrape/global option, see Getting started and validate a file before pointing the server at it:

promtool check config prometheus.yml

The expression browser

Once the server is running, http://localhost:9090 serves the built-in web UI — the expression browser. Its Graph tab runs an ad-hoc PromQL query against the local TSDB and renders it as a table or a chart; a first useful query is the up metric that Prometheus attaches to every scrape:

up

up is 1 when the most recent scrape of that target succeeded and 0 otherwise, labeled with the target’s job and instance — it is the single most useful metric for "is anything broken" and is the basis of the alerting rule below. The UI also exposes Status > Targets (per-job scrape health and the last error, if any), Status > Configuration (the effective, fully-resolved YAML currently loaded), and Status > Rules (recording and alerting rules with their current state). See First steps for a guided tour of these pages, and PromQL: Basics & Selectors for how to read and write queries like the one above.

Running node_exporter and scraping it

node_exporter exposes host-level metrics — CPU, memory, disk, network — as a /metrics HTTP endpoint that Prometheus scrapes like any other target. It ships as its own binary, separate from the Prometheus server, and needs no configuration to start:

tar xvfz node_exporter-*.tar.gz
cd node_exporter-*/
./node_exporter
# listens on :9100/metrics by default

Add it as a second job in prometheus.yml and reload the server:

scrape_configs:
  - job_name: "prometheus"
    static_configs:
      - targets: ["localhost:9090"]

  - job_name: "node"
    static_configs:
      - targets: ["localhost:9100"]
# https://prometheus.io/docs/prometheus/latest/getting_started/

After the next scrape interval, up{job="node"} should read 1 in the expression browser, and metrics such as node_cpu_seconds_total or node_memory_MemAvailable_bytes become queryable. node_exporter is one of many first-party and community exporters that adapt a system that does not natively speak Prometheus’s format; the general pattern, and the Pushgateway for short-lived batch jobs, is covered in Exporters & the Pushgateway.

A first alerting rule

Alerting rules live in separate YAML files, referenced from prometheus.yml via rule_files, and are evaluated by the Prometheus server itself on evaluation_interval — not by Alertmanager, which only receives and routes alerts that already fired. Point at a rules file:

rule_files:
  - "alert_rules.yml"
# https://prometheus.io/docs/prometheus/latest/getting_started/

A minimal rule that fires when a target has been unreachable for five straight minutes:

groups:
  - name: example
    rules:
      - alert: InstanceDown
        expr: up == 0
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "Instance {{ $labels.instance }} down"
          description: "{{ $labels.instance }} (job {{ $labels.job }}) has been down for 5 minutes."

for: 5m requires the up == 0 condition to hold continuously across evaluations before the alert leaves the pending state and becomes firing — it exists specifically to avoid paging on a single missed scrape. A firing rule shows up under Status > Rules and Alerts in the expression browser immediately, whether or not Alertmanager is configured to receive it. Validate the rules file the same way as the main config:

promtool check rules alert_rules.yml

Writing rules well — naming conventions, recording rules for expensive expressions, and multi-window alerting patterns — is covered in Recording & Alerting Rules; routing a firing alert to email/Slack/PagerDuty is Alertmanager's job, not the Prometheus server’s.

Continue with Architecture & Ecosystem for how the server, exporters, and Alertmanager fit together, and Data Model & Metric Types for what a metric like up or node_cpu_seconds_total actually is under the hood.