{"id":164041,"date":"2026-03-24T03:37:05","date_gmt":"2026-03-24T00:37:05","guid":{"rendered":"https:\/\/computingforgeeks.com\/install-prometheus-ubuntu-debian\/"},"modified":"2026-03-24T03:37:05","modified_gmt":"2026-03-24T00:37:05","slug":"install-prometheus-ubuntu-debian","status":"publish","type":"post","link":"https:\/\/computingforgeeks.com\/install-prometheus-ubuntu-debian\/","title":{"rendered":"Install Prometheus 3 on Ubuntu 24.04 \/ Debian 13"},"content":{"rendered":"\n<p>Prometheus 3 brings a completely redesigned UI, native OpenTelemetry support, and significant performance improvements over the 2.x series. This guide walks through a production-ready installation of Prometheus 3 with node_exporter on Ubuntu 24.04 and Debian 13, including alert rules, Grafana integration, and real-world troubleshooting tips.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What&#8217;s New in Prometheus 3?<\/h2>\n\n\n\n<p>Prometheus 3 is a major release with breaking changes and new features that matter for production deployments:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>New UI<\/strong> &#8211; The classic web interface has been completely rewritten with better query editing, improved navigation, and a modern look<\/li>\n<li><strong>Native OTLP ingestion<\/strong> &#8211; Prometheus can now receive metrics directly from OpenTelemetry collectors via the OTLP protocol, enabled with <code>--web.enable-otlp-receiver<\/code><\/li>\n<li><strong>Native histograms<\/strong> &#8211; A new histogram representation that reduces storage and query cost significantly compared to classic histograms<\/li>\n<li><strong>Remote Write 2.0<\/strong> &#8211; Improved protocol for sending metrics to remote storage backends with better efficiency<\/li>\n<li><strong>UTF-8 metric names<\/strong> &#8211; Metric and label names can now contain UTF-8 characters<\/li>\n<li><strong>Removed console templates<\/strong> &#8211; The <code>consoles\/<\/code> and <code>console_libraries\/<\/code> directories are no longer included in the tarball<\/li>\n<\/ul>\n\n\n\n<p>For the full list of changes, see the <a href=\"https:\/\/prometheus.io\/blog\/2024\/11\/14\/prometheus-3-0\/\" target=\"_blank\" rel=\"noopener\">official Prometheus 3.0 announcement<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Prerequisites<\/h2>\n\n\n\n<p>Before starting, make sure you have:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Ubuntu 24.04 or Debian 13 server with root or sudo access<\/li>\n<li>At least 2 GB RAM and 20 GB free disk space<\/li>\n<li>Firewall access to ports 9090 (Prometheus) and 9100 (node_exporter)<\/li>\n<li>A working Grafana instance &#8211; see <a href=\"https:\/\/computingforgeeks.com\/install-grafana-ubuntu-debian\/\">Install Grafana on Ubuntu \/ Debian<\/a> if you need one<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Step 1: Install Prometheus 3<\/h2>\n\n\n\n<p>Prometheus ships as a single static binary. We&#8217;ll download the latest release directly from GitHub and set it up with a dedicated system user.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Create the Prometheus user and directories<\/h3>\n\n\n\n<p>First, create a dedicated user for Prometheus with no login shell and no home directory. This follows the principle of least privilege for running services.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo useradd --no-create-home --shell \/bin\/false prometheus<\/code><\/pre>\n\n\n\n<p>Create the configuration and data directories:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo mkdir -p \/etc\/prometheus \/var\/lib\/prometheus\nsudo chown prometheus:prometheus \/var\/lib\/prometheus<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Download and install Prometheus<\/h3>\n\n\n\n<p>Fetch the latest version number dynamically from GitHub and download the appropriate binary:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>VER=$(curl -sI https:\/\/github.com\/prometheus\/prometheus\/releases\/latest | grep -i ^location | grep -o v[0-9.]* | sed s\/^v\/\/)\necho \"Installing Prometheus $VER\"\nwget https:\/\/github.com\/prometheus\/prometheus\/releases\/download\/v${VER}\/prometheus-${VER}.linux-amd64.tar.gz<\/code><\/pre>\n\n\n\n<p>At the time of writing, this pulls Prometheus <strong>3.10.0<\/strong>. Extract the archive and move the binaries into place:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>tar xvf prometheus-${VER}.linux-amd64.tar.gz\nsudo cp prometheus-${VER}.linux-amd64\/{prometheus,promtool} \/usr\/local\/bin\/\nsudo chown prometheus:prometheus \/usr\/local\/bin\/{prometheus,promtool}<\/code><\/pre>\n\n\n\n<p>Verify the installation by checking the version:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>prometheus --version<\/code><\/pre>\n\n\n\n<p>You should see the version and build info confirmed:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>prometheus, version 3.10.0 (branch: HEAD, revision: 4e546fca)\n  build user:       root@bba5c76a3954\n  build date:       20260315-10:42:25\n  go version:       go1.24.1\n  platform:         linux\/amd64\n  tags:             netgo,builtinassets,stringlabels<\/code><\/pre>\n\n\n\n<p><strong>Note:<\/strong> If you&#8217;re coming from Prometheus 2.x, notice that the tarball no longer includes <code>consoles\/<\/code> and <code>console_libraries\/<\/code> directories. The new UI replaces the old console templates entirely, so the <code>--web.console.templates<\/code> and <code>--web.console.libraries<\/code> flags are no longer needed.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 2: Configure Prometheus<\/h2>\n\n\n\n<p>Create the main Prometheus configuration file. This config sets up scrape targets for Prometheus itself, node_exporter, Blackbox exporter, and Alertmanager.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo vi \/etc\/prometheus\/prometheus.yml<\/code><\/pre>\n\n\n\n<p>Add the following configuration:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>global:\n  scrape_interval: 15s\n  evaluation_interval: 15s\n  scrape_timeout: 10s\n\nalerting:\n  alertmanagers:\n    - static_configs:\n        - targets:\n            - localhost:9093\n\nrule_files:\n  - \"\/etc\/prometheus\/rules\/*.yml\"\n\nscrape_configs:\n  - job_name: \"prometheus\"\n    static_configs:\n      - targets: [\"localhost:9090\"]\n\n  - job_name: \"node_exporter\"\n    static_configs:\n      - targets: [\"localhost:9100\"]\n        labels:\n          instance_name: \"prometheus-server\"\n\n  - job_name: \"blackbox_http\"\n    metrics_path: \/probe\n    params:\n      module: [http_2xx]\n    static_configs:\n      - targets:\n          - https:\/\/computingforgeeks.com\n          - https:\/\/google.com\n          - https:\/\/github.com\n    relabel_configs:\n      - source_labels: [__address__]\n        target_label: __param_target\n      - source_labels: [__param_target]\n        target_label: instance\n      - target_label: __address__\n        replacement: localhost:9115\n\n  - job_name: \"alertmanager\"\n    static_configs:\n      - targets: [\"localhost:9093\"]<\/code><\/pre>\n\n\n\n<p>Set the correct ownership on the config file:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo chown prometheus:prometheus \/etc\/prometheus\/prometheus.yml<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Step 3: Create Alert Rules<\/h2>\n\n\n\n<p>Production monitoring is useless without proper alerting. Create a rules directory and add alert rules for the most critical conditions.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo mkdir -p \/etc\/prometheus\/rules\nsudo vi \/etc\/prometheus\/rules\/node-alerts.yml<\/code><\/pre>\n\n\n\n<p>Add these production-tested alert rules:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>groups:\n  - name: node_alerts\n    rules:\n      - alert: InstanceDown\n        expr: up == 0\n        for: 2m\n        labels:\n          severity: critical\n        annotations:\n          summary: \"Instance {{ $labels.instance }} is down\"\n          description: \"{{ $labels.job }} target {{ $labels.instance }} has been unreachable for more than 2 minutes.\"\n\n      - alert: HighCPUUsage\n        expr: 100 - (avg by(instance) (rate(node_cpu_seconds_total{mode=\"idle\"}[5m])) * 100) > 85\n        for: 5m\n        labels:\n          severity: warning\n        annotations:\n          summary: \"High CPU usage on {{ $labels.instance }}\"\n          description: \"CPU usage has been above 85% for 5 minutes. Current value: {{ $value | printf \\\"%.1f\\\" }}%\"\n\n      - alert: HighMemoryUsage\n        expr: (1 - (node_memory_MemAvailable_bytes \/ node_memory_MemTotal_bytes)) * 100 > 90\n        for: 5m\n        labels:\n          severity: warning\n        annotations:\n          summary: \"High memory usage on {{ $labels.instance }}\"\n          description: \"Memory usage has been above 90% for 5 minutes. Current value: {{ $value | printf \\\"%.1f\\\" }}%\"\n\n      - alert: DiskSpaceLow\n        expr: (1 - (node_filesystem_avail_bytes{mountpoint=\"\/\"} \/ node_filesystem_size_bytes{mountpoint=\"\/\"})) * 100 > 85\n        for: 10m\n        labels:\n          severity: warning\n        annotations:\n          summary: \"Disk space low on {{ $labels.instance }}\"\n          description: \"Root filesystem usage is above 85%. Current value: {{ $value | printf \\\"%.1f\\\" }}%\"<\/code><\/pre>\n\n\n\n<p>Validate the rules file using promtool:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>promtool check rules \/etc\/prometheus\/rules\/node-alerts.yml<\/code><\/pre>\n\n\n\n<p>A clean validation looks like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Checking \/etc\/prometheus\/rules\/node-alerts.yml\n  SUCCESS: 4 rules found<\/code><\/pre>\n\n\n\n<p>Set ownership on the rules directory:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo chown -R prometheus:prometheus \/etc\/prometheus\/rules<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Step 4: Create the Systemd Service<\/h2>\n\n\n\n<p>Create a systemd unit file that runs Prometheus with production-ready flags, including OTLP support and a 30-day data retention period.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo vi \/etc\/systemd\/system\/prometheus.service<\/code><\/pre>\n\n\n\n<p>Add the following service definition:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>[Unit]\nDescription=Prometheus 3 Monitoring System\nDocumentation=https:\/\/prometheus.io\/docs\/introduction\/overview\/\nWants=network-online.target\nAfter=network-online.target\n\n[Service]\nType=simple\nUser=prometheus\nGroup=prometheus\nExecReload=\/bin\/kill -HUP $MAINPID\nExecStart=\/usr\/local\/bin\/prometheus \\\n  --config.file=\/etc\/prometheus\/prometheus.yml \\\n  --storage.tsdb.path=\/var\/lib\/prometheus \\\n  --storage.tsdb.retention.time=30d \\\n  --web.listen-address=0.0.0.0:9090 \\\n  --web.enable-lifecycle \\\n  --web.enable-otlp-receiver\nRestart=always\nRestartSec=5\nSyslogIdentifier=prometheus\nLimitNOFILE=65536\n\n[Install]\nWantedBy=multi-user.target<\/code><\/pre>\n\n\n\n<p>The <code>--web.enable-otlp-receiver<\/code> flag is new in Prometheus 3 and lets you ingest metrics from OpenTelemetry collectors directly into Prometheus. The <code>--web.enable-lifecycle<\/code> flag allows reloading the config via HTTP POST to <code>\/-\/reload<\/code>.<\/p>\n\n\n\n<p>Start and enable the service:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo systemctl daemon-reload\nsudo systemctl enable --now prometheus<\/code><\/pre>\n\n\n\n<p>Verify Prometheus is running:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo systemctl status prometheus<\/code><\/pre>\n\n\n\n<p>The service should show active (running) with the TSDB successfully opened:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\u25cf prometheus.service - Prometheus 3 Monitoring System\n     Loaded: loaded (\/etc\/systemd\/system\/prometheus.service; enabled; preset: enabled)\n     Active: active (running) since Mon 2026-03-24 10:15:23 UTC; 5s ago\n       Docs: https:\/\/prometheus.io\/docs\/introduction\/overview\/\n   Main PID: 2341 (prometheus)\n      Tasks: 8 (limit: 4557)\n     Memory: 42.3M\n        CPU: 1.245s\n     CGroup: \/system.slice\/prometheus.service\n             \u2514\u25002341 \/usr\/local\/bin\/prometheus --config.file=\/etc\/prometheus\/prometheus.yml ...<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Step 5: Install Node Exporter<\/h2>\n\n\n\n<p>Node exporter collects hardware and OS-level metrics from the host &#8211; CPU, memory, disk, network, filesystem, and more. It&#8217;s the most common exporter and should run on every server you monitor.<\/p>\n\n\n\n<p>Create a dedicated user for node_exporter:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo useradd --no-create-home --shell \/bin\/false node_exporter<\/code><\/pre>\n\n\n\n<p>Download and install the latest node_exporter release:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>VER=$(curl -sI https:\/\/github.com\/prometheus\/node_exporter\/releases\/latest | grep -i ^location | grep -o v[0-9.]* | sed s\/^v\/\/)\necho \"Installing node_exporter $VER\"\nwget https:\/\/github.com\/prometheus\/node_exporter\/releases\/download\/v${VER}\/node_exporter-${VER}.linux-amd64.tar.gz\ntar xvf node_exporter-${VER}.linux-amd64.tar.gz\nsudo cp node_exporter-${VER}.linux-amd64\/node_exporter \/usr\/local\/bin\/\nsudo chown node_exporter:node_exporter \/usr\/local\/bin\/node_exporter<\/code><\/pre>\n\n\n\n<p>At the time of writing, this installs node_exporter <strong>1.10.2<\/strong>. Create the systemd service file:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo vi \/etc\/systemd\/system\/node_exporter.service<\/code><\/pre>\n\n\n\n<p>Add the following service definition with extra collectors enabled:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>[Unit]\nDescription=Prometheus Node Exporter\nDocumentation=https:\/\/github.com\/prometheus\/node_exporter\nWants=network-online.target\nAfter=network-online.target\n\n[Service]\nType=simple\nUser=node_exporter\nGroup=node_exporter\nExecStart=\/usr\/local\/bin\/node_exporter \\\n  --collector.systemd \\\n  --collector.processes\nRestart=always\nRestartSec=5\nSyslogIdentifier=node_exporter\n\n[Install]\nWantedBy=multi-user.target<\/code><\/pre>\n\n\n\n<p>The <code>--collector.systemd<\/code> flag exposes systemd service states as metrics, which is very useful for alerting on failed services. The <code>--collector.processes<\/code> flag provides process-level metrics including counts by state.<\/p>\n\n\n\n<p>Start and enable node_exporter:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo systemctl daemon-reload\nsudo systemctl enable --now node_exporter<\/code><\/pre>\n\n\n\n<p>Confirm it&#8217;s running and listening on port 9100:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo systemctl status node_exporter<\/code><\/pre>\n\n\n\n<p>The service should show active (running):<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\u25cf node_exporter.service - Prometheus Node Exporter\n     Loaded: loaded (\/etc\/systemd\/system\/node_exporter.service; enabled; preset: enabled)\n     Active: active (running) since Mon 2026-03-24 10:18:45 UTC; 3s ago\n       Docs: https:\/\/github.com\/prometheus\/node_exporter\n   Main PID: 2567 (node_exporter)\n      Tasks: 5 (limit: 4557)\n     Memory: 12.1M\n        CPU: 0.089s\n     CGroup: \/system.slice\/node_exporter.service\n             \u2514\u25002567 \/usr\/local\/bin\/node_exporter --collector.systemd --collector.processes<\/code><\/pre>\n\n\n\n<p>Test that metrics are being exposed by curling the metrics endpoint:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>curl -s http:\/\/localhost:9100\/metrics | head -5<\/code><\/pre>\n\n\n\n<p>You should see metric lines starting with <code>#<\/code> comments and metric values:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># HELP go_gc_duration_seconds A summary of the pause duration of garbage collection cycles.\n# TYPE go_gc_duration_seconds summary\ngo_gc_duration_seconds{quantile=\"0\"} 2.3457e-05\ngo_gc_duration_seconds{quantile=\"0.25\"} 3.1245e-05\ngo_gc_duration_seconds{quantile=\"0.5\"} 4.5678e-05<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Step 6: Configure Firewall Rules<\/h2>\n\n\n\n<p>Open the necessary ports in UFW for Prometheus and node_exporter:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo ufw allow 9090\/tcp comment \"Prometheus\"\nsudo ufw allow 9100\/tcp comment \"Node Exporter\"\nsudo ufw reload<\/code><\/pre>\n\n\n\n<p>Verify the rules are active:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo ufw status verbose<\/code><\/pre>\n\n\n\n<p>The output should list both ports as ALLOW:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Status: active\n\nTo                         Action      From\n--                         ------      ----\n22\/tcp                     ALLOW       Anywhere\n9090\/tcp                   ALLOW       Anywhere                   # Prometheus\n9100\/tcp                   ALLOW       Anywhere                   # Node Exporter<\/code><\/pre>\n\n\n\n<p>In production, restrict port 9100 to only your Prometheus server IP instead of allowing it from anywhere. Node exporter exposes detailed system information that you don&#8217;t want publicly accessible.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 7: Access the Prometheus 3 Web UI<\/h2>\n\n\n\n<p>Open your browser and navigate to <code>http:\/\/your-server-ip:9090<\/code>. The Prometheus 3 UI has been completely redesigned with a modern interface.<\/p>\n\n\n\n<p>Navigate to <strong>Status > Targets<\/strong> to verify all configured targets are being scraped successfully. All targets should show a green &#8220;UP&#8221; state:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1920\" height=\"941\" src=\"https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/03\/prometheus3-targets.png\" alt=\"Prometheus 3 targets page showing all scrape targets with UP status including prometheus, node_exporter, blackbox, and alertmanager\" class=\"wp-image-164031\" title=\"\" srcset=\"https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/03\/prometheus3-targets.png 1920w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/03\/prometheus3-targets-300x147.png 300w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/03\/prometheus3-targets-1024x502.png 1024w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/03\/prometheus3-targets-768x376.png 768w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/03\/prometheus3-targets-1536x753.png 1536w\" sizes=\"auto, (max-width: 1920px) 100vw, 1920px\" \/><figcaption class=\"wp-element-caption\">Prometheus 3 targets page &#8211; all endpoints reporting UP<\/figcaption><\/figure>\n\n\n\n<p>Try a basic query in the new query interface. Enter <code>up<\/code> in the expression editor and click Execute to see the status of all targets:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1920\" height=\"941\" src=\"https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/03\/prometheus3-query-ui.png\" alt=\"Prometheus 3 query UI showing the new expression editor with autocomplete and results table\" class=\"wp-image-164032\" title=\"\" srcset=\"https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/03\/prometheus3-query-ui.png 1920w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/03\/prometheus3-query-ui-300x147.png 300w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/03\/prometheus3-query-ui-1024x502.png 1024w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/03\/prometheus3-query-ui-768x376.png 768w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/03\/prometheus3-query-ui-1536x753.png 1536w\" sizes=\"auto, (max-width: 1920px) 100vw, 1920px\" \/><figcaption class=\"wp-element-caption\">The redesigned query UI in Prometheus 3 with autocomplete support<\/figcaption><\/figure>\n\n\n\n<p>Check the <strong>Alerts<\/strong> tab to confirm your alert rules are loaded. They should show as inactive (green) when conditions are healthy:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1920\" height=\"941\" src=\"https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/03\/prometheus3-alerts.png\" alt=\"Prometheus 3 alerts page showing InstanceDown, HighCPU, HighMemory, and DiskSpace rules in inactive state\" class=\"wp-image-164033\" title=\"\" srcset=\"https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/03\/prometheus3-alerts.png 1920w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/03\/prometheus3-alerts-300x147.png 300w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/03\/prometheus3-alerts-1024x502.png 1024w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/03\/prometheus3-alerts-768x376.png 768w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/03\/prometheus3-alerts-1536x753.png 1536w\" sizes=\"auto, (max-width: 1920px) 100vw, 1920px\" \/><figcaption class=\"wp-element-caption\">Alert rules loaded and showing inactive (healthy) state<\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Step 8: Connect Grafana to Prometheus<\/h2>\n\n\n\n<p>With Prometheus collecting metrics, the next step is visualizing them in Grafana. If you don&#8217;t have Grafana installed yet, follow our <a href=\"https:\/\/computingforgeeks.com\/install-grafana-ubuntu-debian\/\">Grafana installation guide for Ubuntu\/Debian<\/a> first.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Add Prometheus as a data source<\/h3>\n\n\n\n<p>In Grafana, go to <strong>Connections > Data Sources > Add data source<\/strong> and select Prometheus. Set the connection URL to <code>http:\/\/localhost:9090<\/code> (or your Prometheus server IP if Grafana runs on a different host). Click <strong>Save &#038; Test<\/strong> to verify the connection.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Import the Node Exporter Full dashboard<\/h3>\n\n\n\n<p>The community-maintained &#8220;Node Exporter Full&#8221; dashboard (ID: <strong>1860<\/strong>) is the most popular dashboard for node_exporter metrics. It provides comprehensive views of CPU, memory, disk, network, and filesystem usage.<\/p>\n\n\n\n<p>Go to <strong>Dashboards > New > Import<\/strong>, enter dashboard ID <code>1860<\/code>, select your Prometheus data source, and click Import. The dashboard should immediately populate with live data from your server.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1920\" height=\"941\" src=\"https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/03\/grafana-node-exporter-dashboard.png\" alt=\"Grafana Node Exporter Full dashboard showing system overview with CPU, memory, disk, and network panels populated with live data\" class=\"wp-image-164036\" title=\"\" srcset=\"https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/03\/grafana-node-exporter-dashboard.png 1920w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/03\/grafana-node-exporter-dashboard-300x147.png 300w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/03\/grafana-node-exporter-dashboard-1024x502.png 1024w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/03\/grafana-node-exporter-dashboard-768x376.png 768w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/03\/grafana-node-exporter-dashboard-1536x753.png 1536w\" sizes=\"auto, (max-width: 1920px) 100vw, 1920px\" \/><figcaption class=\"wp-element-caption\">Node Exporter Full dashboard in Grafana with live metrics from the Prometheus server<\/figcaption><\/figure>\n\n\n\n<p>Scroll down to see detailed CPU and memory usage panels with historical data:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1920\" height=\"941\" src=\"https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/03\/grafana-node-exporter-cpu-mem.png\" alt=\"Grafana dashboard panels showing CPU usage breakdown by mode and memory usage with available, used, and cached breakdown\" class=\"wp-image-164037\" title=\"\" srcset=\"https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/03\/grafana-node-exporter-cpu-mem.png 1920w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/03\/grafana-node-exporter-cpu-mem-300x147.png 300w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/03\/grafana-node-exporter-cpu-mem-1024x502.png 1024w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/03\/grafana-node-exporter-cpu-mem-768x376.png 768w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/03\/grafana-node-exporter-cpu-mem-1536x753.png 1536w\" sizes=\"auto, (max-width: 1920px) 100vw, 1920px\" \/><figcaption class=\"wp-element-caption\">Detailed CPU and memory panels from the Node Exporter dashboard<\/figcaption><\/figure>\n\n\n\n<p>The TSDB Status page under <strong>Status > TSDB Status<\/strong> shows useful storage statistics including the number of time series, label pair cardinality, and memory usage:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1920\" height=\"941\" src=\"https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/03\/prometheus3-tsdb-status.png\" alt=\"Prometheus 3 TSDB status page showing time series count, label pairs, and storage block statistics\" class=\"wp-image-164034\" title=\"\" srcset=\"https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/03\/prometheus3-tsdb-status.png 1920w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/03\/prometheus3-tsdb-status-300x147.png 300w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/03\/prometheus3-tsdb-status-1024x502.png 1024w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/03\/prometheus3-tsdb-status-768x376.png 768w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/03\/prometheus3-tsdb-status-1536x753.png 1536w\" sizes=\"auto, (max-width: 1920px) 100vw, 1920px\" \/><figcaption class=\"wp-element-caption\">TSDB status page showing storage statistics and series cardinality<\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Useful PromQL Queries to Get Started<\/h2>\n\n\n\n<p>With Prometheus collecting node_exporter metrics, here are some essential PromQL queries you can run in the query UI or use in Grafana dashboards:<\/p>\n\n\n\n<p><strong>Current CPU usage percentage (averaged across all cores):<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>100 - (avg by(instance) (rate(node_cpu_seconds_total{mode=\"idle\"}[5m])) * 100)<\/code><\/pre>\n\n\n\n<p><strong>Memory usage percentage:<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>(1 - (node_memory_MemAvailable_bytes \/ node_memory_MemTotal_bytes)) * 100<\/code><\/pre>\n\n\n\n<p><strong>Root filesystem usage percentage:<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>(1 - (node_filesystem_avail_bytes{mountpoint=\"\/\"} \/ node_filesystem_size_bytes{mountpoint=\"\/\"})) * 100<\/code><\/pre>\n\n\n\n<p><strong>Network traffic rate (bytes per second on all interfaces):<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>rate(node_network_receive_bytes_total{device!=\"lo\"}[5m])<\/code><\/pre>\n\n\n\n<p><strong>System uptime in days:<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>(time() - node_boot_time_seconds) \/ 86400<\/code><\/pre>\n\n\n\n<p>These queries form the foundation of most monitoring dashboards. The <code>rate()<\/code> function is essential for counter metrics &#8211; it calculates the per-second rate of increase, which is what you actually want to see for counters like CPU seconds and network bytes.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">How to Reload Configuration Without Restarting<\/h2>\n\n\n\n<p>Prometheus supports hot reloading of configuration. After editing <code>prometheus.yml<\/code> or alert rules, you can reload without downtime using either method:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo systemctl reload prometheus<\/code><\/pre>\n\n\n\n<p>Or send an HTTP POST to the lifecycle endpoint (requires <code>--web.enable-lifecycle<\/code>):<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>curl -X POST http:\/\/localhost:9090\/-\/reload<\/code><\/pre>\n\n\n\n<p>Always validate your config before reloading to avoid breaking a running instance:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>promtool check config \/etc\/prometheus\/prometheus.yml<\/code><\/pre>\n\n\n\n<p>A successful validation returns:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Checking \/etc\/prometheus\/prometheus.yml\n  SUCCESS: \/etc\/prometheus\/prometheus.yml is valid prometheus config file<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">How to Add More Monitoring Targets<\/h2>\n\n\n\n<p>To monitor additional servers, install node_exporter on each target host and add them to the <code>node_exporter<\/code> job in <code>prometheus.yml<\/code>. Each target is just an IP:port entry in the static_configs targets list:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>  - job_name: \"node_exporter\"\n    static_configs:\n      - targets: [\"localhost:9100\"]\n        labels:\n          instance_name: \"prometheus-server\"\n      - targets: [\"10.0.1.20:9100\"]\n        labels:\n          instance_name: \"web-01\"\n      - targets: [\"10.0.1.21:9100\"]\n        labels:\n          instance_name: \"web-02\"\n      - targets: [\"10.0.1.30:9100\"]\n        labels:\n          instance_name: \"db-01\"<\/code><\/pre>\n\n\n\n<p>After adding new targets, validate and reload:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>promtool check config \/etc\/prometheus\/prometheus.yml\nsudo systemctl reload prometheus<\/code><\/pre>\n\n\n\n<p>For large environments with many targets, consider using file-based service discovery instead of static configs. Create a JSON file with your targets and reference it in the scrape job &#8211; Prometheus watches the file for changes and picks up new targets automatically without reloading.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">How to Secure Prometheus in Production<\/h2>\n\n\n\n<p>Prometheus 3 supports basic authentication and TLS natively. For production deployments, you should enable both to prevent unauthorized access to your monitoring data.<\/p>\n\n\n\n<p>Create a web configuration file for Prometheus:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo vi \/etc\/prometheus\/web.yml<\/code><\/pre>\n\n\n\n<p>Add basic authentication (generate the bcrypt hash with <code>htpasswd -nBC 10 admin<\/code>):<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>basic_auth_users:\n  admin: '$2y$10$example_bcrypt_hash_here'<\/code><\/pre>\n\n\n\n<p>Then add <code>--web.config.file=\/etc\/prometheus\/web.yml<\/code> to your systemd service ExecStart. After restarting, the Prometheus UI and API will require authentication. Update your Grafana data source configuration to include the username and password.<\/p>\n\n\n\n<p>For TLS, add the certificate paths to the same web.yml file. This is especially important if Prometheus is accessible over a network rather than just localhost.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Using Grafana Alloy as an Alternative Collector<\/h2>\n\n\n\n<p>If you&#8217;re looking for a more flexible metrics collection agent that supports OpenTelemetry natively, consider <a href=\"https:\/\/computingforgeeks.com\/install-grafana-alloy-ubuntu-debian\/\">Grafana Alloy<\/a>. Alloy can replace node_exporter and push metrics to Prometheus using remote write, which is useful in environments where you can&#8217;t open inbound ports on target hosts.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Troubleshooting Common Issues<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Prometheus fails to start with &#8220;permission denied&#8221;<\/h3>\n\n\n\n<p>If Prometheus can&#8217;t write to its data directory, check the ownership:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ls -la \/var\/lib\/prometheus<\/code><\/pre>\n\n\n\n<p>The directory must be owned by the prometheus user. Fix it with:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo chown -R prometheus:prometheus \/var\/lib\/prometheus<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Targets show as DOWN in the UI<\/h3>\n\n\n\n<p>When a target shows DOWN, click on the error message in the Targets page. Common causes:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>&#8220;connection refused&#8221;<\/strong> &#8211; The exporter service is not running. Check with <code>systemctl status node_exporter<\/code><\/li>\n<li><strong>&#8220;context deadline exceeded&#8221;<\/strong> &#8211; The target is too slow to respond. Increase <code>scrape_timeout<\/code> in the job config<\/li>\n<li><strong>&#8220;no route to host&#8221;<\/strong> &#8211; Firewall is blocking the port. Verify with <code>sudo ufw status<\/code><\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Old console flags cause startup errors<\/h3>\n\n\n\n<p>If you&#8217;re migrating from Prometheus 2.x and your systemd service includes <code>--web.console.templates<\/code> or <code>--web.console.libraries<\/code> flags, Prometheus 3 will fail to start. Remove these flags from your service file &#8211; they are no longer supported since the console templates were removed from the distribution.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">High memory usage on large installations<\/h3>\n\n\n\n<p>Prometheus stores recent data in memory before flushing to disk. If you have many targets or high-cardinality metrics, memory usage can grow quickly. Reduce cardinality by dropping unnecessary labels in your scrape configs, or reduce <code>scrape_interval<\/code> for less critical targets. You can monitor Prometheus&#8217;s own memory usage with:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>process_resident_memory_bytes{job=\"prometheus\"}<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">How to Check Prometheus Storage Usage<\/h2>\n\n\n\n<p>Prometheus stores time-series data on disk in the TSDB. Monitoring the storage consumption helps you plan capacity and adjust retention settings. Check the current disk usage:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>du -sh \/var\/lib\/prometheus<\/code><\/pre>\n\n\n\n<p>You can also monitor storage via PromQL. This query shows the total number of time series currently stored:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>prometheus_tsdb_head_series<\/code><\/pre>\n\n\n\n<p>And this shows the rate of samples ingested per second:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>rate(prometheus_tsdb_head_samples_appended_total[5m])<\/code><\/pre>\n\n\n\n<p>A rough estimate for storage: each time series consumes about 1-2 bytes per sample. With a 15-second scrape interval and 30-day retention, expect roughly 3-6 KB per time series per day. If you have 10,000 active series, that&#8217;s 30-60 MB per day or about 1-2 GB per month. Adjust <code>--storage.tsdb.retention.time<\/code> based on your available disk space and how far back you need to query.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p>You now have a production-ready Prometheus 3 installation with node_exporter collecting system metrics, alert rules watching for common issues, and Grafana dashboards providing visualization. The OTLP receiver is enabled for future OpenTelemetry integration. From here, add more exporters for your specific services &#8211; database exporters, web server exporters, or custom application metrics &#8211; and expand your alert rules to match your SLAs.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Prometheus 3 brings a completely redesigned UI, native OpenTelemetry support, and significant performance improvements over the 2.x series. This guide walks through a production-ready installation of Prometheus 3 with node_exporter on Ubuntu 24.04 and Debian 13, including alert rules, Grafana integration, and real-world troubleshooting tips. What&#8217;s New in Prometheus 3? Prometheus 3 is a major &#8230; <a title=\"Install Prometheus 3 on Ubuntu 24.04 \/ Debian 13\" class=\"read-more\" href=\"https:\/\/computingforgeeks.com\/install-prometheus-ubuntu-debian\/\" aria-label=\"Read more about Install Prometheus 3 on Ubuntu 24.04 \/ Debian 13\">Read more<\/a><\/p>\n","protected":false},"author":3,"featured_media":164042,"comment_status":"open","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[26,299,50,165,81],"tags":[],"class_list":["post-164041","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-debian","category-how-to","category-linux-tutorials","category-monitoring","category-ubuntu"],"_links":{"self":[{"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/posts\/164041","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/comments?post=164041"}],"version-history":[{"count":0,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/posts\/164041\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/media\/164042"}],"wp:attachment":[{"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/media?parent=164041"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/categories?post=164041"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/tags?post=164041"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}