Environment
This guide installs Prometheus and Node Exporter on one Ubuntu server, then adds an optional Windows host. It retains the original article’s versions as reproducible examples, not as a claim that they are the latest releases.
| Component | Example |
|---|---|
| Prometheus host | Ubuntu 24.04 LTS, x86_64, 192.168.1.50 |
| Prometheus | 3.5.0 |
| Node Exporter | 1.9.1 |
| Windows host | Windows Server 2019, x64, 192.168.1.60 |
| Windows Exporter | 0.31.3 |
Replace the IP addresses with your own. Review the projects’ current releases before a new deployment. The Linux downloads below are for amd64; use the matching architecture on other systems.
Ubuntu 24.04 LTS
Create the Service Account and Directories
These commands assume a fresh installation. If the account or configuration already exists, inspect it and back up the configuration before proceeding.
sudo apt update
sudo apt install -y ca-certificates curl
sudo useradd --system --user-group --no-create-home --shell /usr/sbin/nologin prometheus
sudo install -d -o root -g prometheus -m 0750 /etc/prometheus
sudo install -d -o prometheus -g prometheus -m 0750 /var/lib/prometheus
The service needs write access to /var/lib/prometheus. Keep its executable files owned by root.
Download and Install Prometheus
Run this block in Bash. Stop if a download or checksum check fails.
(
set -eu
workdir=$(mktemp -d)
cd "$workdir"
version=3.5.0
archive="prometheus-${version}.linux-amd64.tar.gz"
release="https://github.com/prometheus/prometheus/releases/download/v${version}"
curl -fLO "$release/$archive"
curl -fLO "$release/sha256sums.txt"
grep -F " $archive" sha256sums.txt | sha256sum --check --strict -
tar -xzf "$archive"
sudo install -o root -g root -m 0755 "prometheus-${version}.linux-amd64/prometheus" /usr/local/bin/prometheus
sudo install -o root -g root -m 0755 "prometheus-${version}.linux-amd64/promtool" /usr/local/bin/promtool
)
prometheus --version
promtool --version
Official binaries include both the server and promtool. See Prometheus installation.
Configure Prometheus
Start with a self-scrape target. Exporter jobs are added after their services are installed.
sudo tee /etc/prometheus/prometheus.yml > /dev/null <<'EOF'
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
- job_name: prometheus
static_configs:
- targets: ['127.0.0.1:9090']
EOF
sudo chown root:prometheus /etc/prometheus/prometheus.yml
sudo chmod 0640 /etc/prometheus/prometheus.yml
sudo -u prometheus /usr/local/bin/promtool check config /etc/prometheus/prometheus.yml
scrape_interval controls metric collection; evaluation_interval controls rule evaluation. See the configuration reference.
Create the systemd Service
sudo tee /etc/systemd/system/prometheus.service > /dev/null <<'EOF'
[Unit]
Description=Prometheus Monitoring Server
Wants=network-online.target
After=network-online.target
[Service]
Type=simple
User=prometheus
Group=prometheus
ExecStart=/usr/local/bin/prometheus --config.file=/etc/prometheus/prometheus.yml --storage.tsdb.path=/var/lib/prometheus --storage.tsdb.retention.time=15d --web.listen-address=127.0.0.1:9090
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
sudo systemd-analyze verify /etc/systemd/system/prometheus.service
sudo systemctl daemon-reload
sudo systemctl enable --now prometheus
sudo systemctl status prometheus --no-pager
curl --fail http://127.0.0.1:9090/-/ready
The explicit retention period is 15 days; it is not a disk-space quota. See the server flags.
Open the Web Interface
The service listens on loopback. From a remote workstation, open an SSH tunnel:
ssh -N -L 9090:127.0.0.1:9090 username@192.168.1.50
Visit http://localhost:9090 while the tunnel is open. Local port 9090 must be free.
Install Node Exporter
Run these commands on the same Ubuntu server:
sudo useradd --system --user-group --no-create-home --shell /usr/sbin/nologin node_exporter
(
set -eu
workdir=$(mktemp -d)
cd "$workdir"
version=1.9.1
archive="node_exporter-${version}.linux-amd64.tar.gz"
release="https://github.com/prometheus/node_exporter/releases/download/v${version}"
curl -fLO "$release/$archive"
curl -fLO "$release/sha256sums.txt"
grep -F " $archive" sha256sums.txt | sha256sum --check --strict -
tar -xzf "$archive"
sudo install -o root -g root -m 0755 "node_exporter-${version}.linux-amd64/node_exporter" /usr/local/bin/node_exporter
)
node_exporter --version
Create the service:
sudo tee /etc/systemd/system/node_exporter.service > /dev/null <<'EOF'
[Unit]
Description=Prometheus Node Exporter
After=network.target
[Service]
Type=simple
User=node_exporter
Group=node_exporter
ExecStart=/usr/local/bin/node_exporter --web.listen-address=127.0.0.1:9100
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
sudo systemd-analyze verify /etc/systemd/system/node_exporter.service
sudo systemctl daemon-reload
sudo systemctl enable --now node_exporter
sudo systemctl status node_exporter --no-pager
curl --fail --silent --show-error http://127.0.0.1:9100/metrics
Node Exporter exposes Linux host metrics on /metrics. See the official monitoring guide.
Install Windows Exporter
Run PowerShell as administrator on the Windows host. Download windows_exporter-0.31.3-amd64.msi from the release linked above, verify it against the release checksum, and save it in C:\Installers.
Create the Configuration
New-Item -ItemType Directory -Path 'C:\ProgramData\windows_exporter' -Force
@'
collectors:
enabled: cpu,logical_disk,memory,net,os,service,system
log:
level: info
scrape:
timeout-margin: 0.5
telemetry:
path: /metrics
'@ | Set-Content -LiteralPath 'C:\ProgramData\windows_exporter\config.yml' -Encoding Ascii
This follows the versioned configuration example. The correct YAML key is telemetry:, not telemetry:iis. Enable role-specific collectors such as ad, dhcp, or iis only on appropriate servers. The obsolete cs and logon entries from the original notes are omitted.
Install the Service
$installer = 'C:\Installers\windows_exporter-0.31.3-amd64.msi'
if (-not (Test-Path -LiteralPath $installer)) { throw "Installer not found: $installer" }
$msiArguments = '/i "{0}" /qn /norestart CONFIG_FILE="C:\ProgramData\windows_exporter\config.yml" LISTEN_PORT=9115 ADDLOCAL=FirewallException REMOTE_ADDR="192.168.1.50" /L*v "C:\Installers\windows_exporter-install.log"' -f $installer
$installation = Start-Process -FilePath 'msiexec.exe' -ArgumentList $msiArguments -Wait -PassThru -WindowStyle Hidden
if ($installation.ExitCode -notin 0, 3010) {
throw "MSI failed with exit code $($installation.ExitCode). Check the installation log."
}
if ($installation.ExitCode -eq 3010) { Write-Warning 'Restart Windows to complete installation.' }
Get-Service windows_exporter
(Invoke-WebRequest -UseBasicParsing 'http://localhost:9115/metrics').StatusCode
Replace REMOTE_ADDR with the Prometheus server’s IP. The configuration file must exist before installation. This guide retains the custom port 9115; Windows Exporter’s default is 9182. Set the port through MSI so its firewall rule uses the same port. MSI properties override matching YAML settings; collectors are configured in YAML. See the v0.31.3 installer reference.
After configuration changes:
Restart-Service windows_exporter
Add the Exporter Targets
On the Ubuntu Prometheus server, first check Windows connectivity if using that host:
curl --fail --silent --show-error http://192.168.1.60:9115/metrics
sudo nano /etc/prometheus/prometheus.yml
Use this complete configuration. Omit the windows job if no Windows exporter is installed:
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
- job_name: prometheus
static_configs:
- targets: ['127.0.0.1:9090']
- job_name: node
static_configs:
- targets: ['127.0.0.1:9100']
- job_name: windows
static_configs:
- targets: ['192.168.1.60:9115']
Validate before reloading:
sudo -u prometheus /usr/local/bin/promtool check config /etc/prometheus/prometheus.yml && sudo systemctl reload prometheus
sudo journalctl -u prometheus -n 50 --no-pager
The service’s ExecReload sends SIGHUP, which reloads Prometheus configuration without enabling the HTTP lifecycle API. See configuration reloads.
Open http://localhost:9090/targets through the SSH tunnel and confirm the configured targets are UP. Query:
up
Each successful scrape produces 1; a failed scrape produces 0. Allow at least one scrape interval after adding a target. up = 1 confirms a successful scrape, not that every optional collector succeeded.
Optional: Remote Linux Hosts and LAN Access
For a Node Exporter on another Linux host, bind its service to that host’s LAN IP or 0.0.0.0:9100, reload systemd, restart it, and add the host’s address to the node target list. If UFW is active on that host, permit only Prometheus:
sudo ufw allow from 192.168.1.50 to any port 9100 proto tcp
To allow a remote Grafana server to reach Prometheus, change its service flag to --web.listen-address=0.0.0.0:9090 or a specific LAN IP, then apply the unit change:
sudo systemctl daemon-reload
sudo systemctl restart prometheus
sudo ufw allow from 192.168.1.70 to any port 9090 proto tcp
Use the actual Grafana server IP instead of 192.168.1.70. These examples provide unauthenticated HTTP access on a trusted network; use TLS and authentication before exposing endpoints beyond it.
Connect Grafana
In Grafana, add a Prometheus data source and set its server URL:
- Same Ubuntu host, native services:
http://127.0.0.1:9090. - Separate Grafana server with LAN access configured:
http://192.168.1.50:9090.
Set the scrape interval to 15s and select Save & test. If Grafana runs in a container, 127.0.0.1 refers to that container; use an address reachable from its network. See Grafana’s Prometheus configuration guide.
Troubleshooting
sudo systemctl status prometheus node_exporter --no-pager
sudo journalctl -u prometheus -n 100 --no-pager
sudo journalctl -u node_exporter -n 100 --no-pager
sudo ss -ltnp
- Prometheus cannot open its database: Verify ownership of
/var/lib/prometheusand available disk space. - Configuration reload fails: Run
promtool check config, then inspect the service journal. - Target is DOWN: Test its
/metricsURL from the Prometheus server; check the port, listening address, and firewall. - Windows service fails: Inspect the MSI log, Windows Application event log, and YAML configuration.
- Windows role metrics are missing: Check that the corresponding server role and collector are enabled.
- Grafana cannot connect: Use the Prometheus address reachable from Grafana’s host or container.