Skip to content
DevOps devops monitoring 6 min read

Installing Prometheus on Ubuntu

Prometheus is a monitoring tool that collects numbers (called metrics) from your servers and applications, stores them over time, and lets you query and alert on them. It works by “scraping” — meaning it regularly visits a web address on each target and reads the metrics it exposes. In this guide you will install Prometheus from the official binary on Ubuntu, run it as a proper background service, point it at a real scrape target, and confirm in the web UI that it is collecting data. This matters because once Prometheus is running and scraping itself, you have a foundation you can extend to monitor your whole fleet.

When to install Prometheus this way

There are a few ways to run Prometheus. Picking the right one keeps your setup simple and easy to maintain.

MethodWhen to use itWhen NOT to use it
Official binary + systemd (this guide)A real Ubuntu server you control and want long-term. Full control over version and config.You want zero-maintenance hands-off hosting.
apt install prometheusQuick test on a throwaway box.Production — the Ubuntu package often lags well behind the latest release.
Docker containerYou already run everything in containers.A single plain server where Docker adds overhead you don’t need.
Hosted (Grafana Cloud, AWS AMP)You don’t want to manage the server at all.You need data to stay fully on your own machine.

We use the official binary with systemd (the standard Ubuntu service manager that starts, stops, and restarts background programs) because it gives you the current version and behaves like any other well-run Linux service.

Step 1 — Create a dedicated user

Running Prometheus as a normal login user (or worse, as root, the all-powerful admin account) is a security risk. If the process is ever compromised, the attacker gets whatever that account can do. The fix is a system user — a locked-down account with no login shell and no home directory, used only to run this one service.

sudo useradd --no-create-home --shell /usr/sbin/nologin prometheus

This creates a user named prometheus that nobody can log in as. --shell /usr/sbin/nologin blocks interactive logins, and --no-create-home skips making a home folder it doesn’t need.

Step 2 — Download and install the binary

Go to the official releases page, copy the latest Linux AMD64 download link, and fetch it. At the time of writing the current line is the 3.x series.

cd /tmp
wget https://github.com/prometheus/prometheus/releases/download/v3.4.1/prometheus-3.4.1.linux-amd64.tar.gz
tar -xvf prometheus-3.4.1.linux-amd64.tar.gz
cd prometheus-3.4.1.linux-amd64

Output:

prometheus-3.4.1.linux-amd64/
prometheus-3.4.1.linux-amd64/prometheus
prometheus-3.4.1.linux-amd64/promtool
prometheus-3.4.1.linux-amd64/LICENSE
prometheus-3.4.1.linux-amd64/NOTICE

Now move the two programs into a system path and create the folders Prometheus uses. /usr/local/bin is where you put binaries you installed by hand. /etc/prometheus holds config, and /var/lib/prometheus holds the stored metrics (this is the time-series database, or TSDB — the on-disk store of all those numbers over time).

sudo cp prometheus promtool /usr/local/bin/
sudo mkdir -p /etc/prometheus /var/lib/prometheus
sudo cp -r consoles console_libraries /etc/prometheus/

Give the prometheus user ownership of its directories so the service can read its config and write its data.

sudo chown -R prometheus:prometheus /etc/prometheus /var/lib/prometheus
sudo chown prometheus:prometheus /usr/local/bin/prometheus /usr/local/bin/promtool

Confirm it installed correctly:

prometheus --version

Output:

prometheus, version 3.4.1 (branch: HEAD, revision: ...)
  build user:       root@...
  go version:       go1.24.3

Step 3 — Write the configuration file

Prometheus reads a single YAML file, prometheus.yml. YAML is a plain-text format where indentation (spaces, never tabs) defines structure. Two settings matter most here:

  • scrape_interval — how often Prometheus pulls metrics from each target.
  • scrape_configs — the list of things to scrape. Each entry is a job (a named group of targets) with one or more targets (host:port addresses).

Create the file:

sudo nano /etc/prometheus/prometheus.yml

Paste this in. It tells Prometheus to scrape itself, which every install can do because Prometheus exposes its own metrics on port 9090 at the path /metrics.

global:
  scrape_interval: 15s      # how often to scrape every target by default
  evaluation_interval: 15s  # how often to evaluate alerting rules

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

Before you start the service, validate the file with promtool, the checking tool that shipped alongside Prometheus. Catching a typo now is far easier than debugging a service that won’t start.

promtool check config /etc/prometheus/prometheus.yml

Output:

Checking /etc/prometheus/prometheus.yml
 SUCCESS: 1 rule files found
 SUCCESS: /etc/prometheus/prometheus.yml is valid prometheus config file syntax

Step 4 — Create the systemd service

A systemd unit file describes how to run a program as a managed background service. Create one so Prometheus starts on boot and restarts if it crashes.

sudo nano /etc/systemd/system/prometheus.service
[Unit]
Description=Prometheus Monitoring
Wants=network-online.target
After=network-online.target

[Service]
User=prometheus
Group=prometheus
Type=simple
Restart=on-failure
ExecStart=/usr/local/bin/prometheus \
  --config.file=/etc/prometheus/prometheus.yml \
  --storage.tsdb.path=/var/lib/prometheus/ \
  --web.console.templates=/etc/prometheus/consoles \
  --web.console.libraries=/etc/prometheus/console_libraries \
  --web.listen-address=0.0.0.0:9090

[Install]
WantedBy=multi-user.target

Restart=on-failure means systemd brings the service back if it dies. User=prometheus runs it as the locked-down account from Step 1.

Reload systemd so it sees the new file, then enable (start on boot) and start the service:

sudo systemctl daemon-reload
sudo systemctl enable --now prometheus
sudo systemctl status prometheus

Output:

● prometheus.service - Prometheus Monitoring
     Loaded: loaded (/etc/systemd/system/prometheus.service; enabled)
     Active: active (running) since Mon 2026-06-15 10:12:04 UTC; 3s ago
   Main PID: 4821 (prometheus)

active (running) means it is up. If it shows failed, run sudo journalctl -u prometheus -e to read the error log.

Step 5 — Open the firewall (only if needed)

If you want to reach the web UI from another machine and you use UFW (Uncomplicated Firewall, Ubuntu’s simple firewall front-end), allow port 9090. Restrict it to a trusted address rather than opening it to the world.

sudo ufw allow from 203.0.113.10 to any port 9090 proto tcp

Security gotcha: the Prometheus web UI has no built-in login. Anyone who can reach port 9090 can read all your metrics and shut Prometheus down via its API. Never expose it to the public internet directly — keep it behind a firewall, a VPN, or a reverse proxy that handles authentication.

Step 6 — View targets and confirm self-scraping

Open http://your-server-ip:9090 in a browser. Then go to Status → Targets in the top menu. You should see one target, the prometheus job, with a green UP state. That green status is your proof that scraping works end to end.

You can also verify from the command line. Query the built-in up metric, which is 1 for every healthy target:

curl -s 'http://localhost:9090/api/v1/query?query=up'

Output:

{"status":"success","data":{"resultType":"vector","result":[{"metric":{"__name__":"up","instance":"localhost:9090","job":"prometheus"},"value":[1718446324,"1"]}]}}

The trailing "1" confirms Prometheus is successfully scraping itself.

Best Practices

  • Always run promtool check config before reloading or restarting — it catches YAML mistakes that would otherwise crash the service.
  • Reload config without downtime using sudo systemctl reload prometheus (or kill -HUP) instead of a full restart after editing prometheus.yml.
  • Never expose port 9090 to the public internet; put it behind a firewall, VPN, or authenticating reverse proxy.
  • Pin a specific version in your download URL so rebuilds are reproducible, and review release notes before upgrading.
  • Set a sensible retention with --storage.tsdb.retention.time=30d so the database doesn’t fill your disk over time.
  • Keep scrape_interval at 15s to start; only lower it if you genuinely need finer resolution, since it increases storage and load.
Last updated June 15, 2026
Was this helpful?