Blog
prometheuspushgatewayalertmanagersystemdlinuxinstallation

Installing Prometheus — running Prometheus, Pushgateway, and Alertmanager on Linux with systemd

How to install Prometheus, Pushgateway, and Alertmanager from binaries on Linux and register them as systemd services. We cover the dedicated user and directory layout, the unit files for all three components, and the key runtime options — especially --web.listen-address, which sets the bind IP.

Data DynamicsJune 12, 20267 min read

The Prometheus ecosystem ships as single static binaries, so installation is simple. Without a package manager you just download a tarball and extract it, and you leave operation to systemd. This post is a hands-on guide to putting Prometheus, Pushgateway, and Alertmanager on Linux, registering them as systemd services, and the runtime options you must know — especially the bind IP address.

What this post covers:

  • The install method, standard directory layout, and dedicated user
  • Installing Prometheus / Pushgateway / Alertmanager
  • Writing systemd unit files for all three
  • Key runtime options and --web.listen-address (the bind IP)
  • Connecting the three, verifying, and systemd hardening

1. Install method and directory layout

Distro packages exist, but the official binary (tarball) install is the most recommended — it makes version control easy. Deciding a standard layout up front keeps the unit files clean.

PurposePath
Executables/usr/local/bin/
Config files/etc/prometheus/, /etc/alertmanager/
Data (TSDB/state)/var/lib/prometheus/, /var/lib/alertmanager/, /var/lib/pushgateway/
Run accountdedicated system user prometheus (no login)

Default ports are Prometheus 9090 · Pushgateway 9091 · Alertmanager 9093 (cluster 9094).

2. Common prep — dedicated user and directories

To avoid running the daemons as root, create a non-login system account and prepare the directories.

# dedicated system user (no home, no shell)
sudo useradd --system --no-create-home --shell /usr/sbin/nologin prometheus
 
# config/data directories
sudo mkdir -p /etc/prometheus /var/lib/prometheus
sudo mkdir -p /etc/alertmanager /var/lib/alertmanager
sudo mkdir -p /var/lib/pushgateway
 
sudo chown -R prometheus:prometheus /var/lib/prometheus /var/lib/alertmanager /var/lib/pushgateway

3. Installing Prometheus

Check the latest version at prometheus.io/download (replace VERSION below), then download and place the binaries and default config.

VERSION=3.2.1     # replace with the latest stable version
cd /tmp
curl -LO https://github.com/prometheus/prometheus/releases/download/v${VERSION}/prometheus-${VERSION}.linux-amd64.tar.gz
tar xzf prometheus-${VERSION}.linux-amd64.tar.gz
cd prometheus-${VERSION}.linux-amd64
 
# binaries
sudo cp prometheus promtool /usr/local/bin/
 
# default config (only if absent)
sudo cp prometheus.yml /etc/prometheus/prometheus.yml
sudo chown -R prometheus:prometheus /etc/prometheus

promtool is the config/rule validation tool, so install it too.

4. Installing the Pushgateway

VERSION=1.11.0    # replace with the latest version
cd /tmp
curl -LO https://github.com/prometheus/pushgateway/releases/download/v${VERSION}/pushgateway-${VERSION}.linux-amd64.tar.gz
tar xzf pushgateway-${VERSION}.linux-amd64.tar.gz
sudo cp pushgateway-${VERSION}.linux-amd64/pushgateway /usr/local/bin/

5. Installing Alertmanager

VERSION=0.28.0    # replace with the latest version
cd /tmp
curl -LO https://github.com/prometheus/alertmanager/releases/download/v${VERSION}/alertmanager-${VERSION}.linux-amd64.tar.gz
tar xzf alertmanager-${VERSION}.linux-amd64.tar.gz
cd alertmanager-${VERSION}.linux-amd64
 
sudo cp alertmanager amtool /usr/local/bin/
sudo cp alertmanager.yml /etc/alertmanager/alertmanager.yml
sudo chown -R prometheus:prometheus /etc/alertmanager

Each component has a different version number (Prometheus, Pushgateway, and Alertmanager release independently). Check each one's latest version when downloading.

6. Registering systemd services

Create three unit files. The meaning of the ExecStart options is explained in the next section.

/etc/systemd/system/prometheus.service:

[Unit]
Description=Prometheus
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 \
  --storage.tsdb.retention.time=30d \
  --web.listen-address=0.0.0.0:9090 \
  --web.enable-lifecycle
ExecReload=/bin/kill -HUP $MAINPID
 
[Install]
WantedBy=multi-user.target

/etc/systemd/system/pushgateway.service:

[Unit]
Description=Prometheus Pushgateway
Wants=network-online.target
After=network-online.target
 
[Service]
User=prometheus
Group=prometheus
Type=simple
Restart=on-failure
ExecStart=/usr/local/bin/pushgateway \
  --web.listen-address=0.0.0.0:9091 \
  --persistence.file=/var/lib/pushgateway/metrics \
  --persistence.interval=5m
 
[Install]
WantedBy=multi-user.target

/etc/systemd/system/alertmanager.service:

[Unit]
Description=Prometheus Alertmanager
Wants=network-online.target
After=network-online.target
 
[Service]
User=prometheus
Group=prometheus
Type=simple
Restart=on-failure
ExecStart=/usr/local/bin/alertmanager \
  --config.file=/etc/alertmanager/alertmanager.yml \
  --storage.path=/var/lib/alertmanager \
  --web.listen-address=0.0.0.0:9093 \
  --cluster.listen-address=
ExecReload=/bin/kill -HUP $MAINPID
 
[Install]
WantedBy=multi-user.target

Register and start:

sudo systemctl daemon-reload
sudo systemctl enable --now prometheus pushgateway alertmanager
sudo systemctl status prometheus
journalctl -u prometheus -f      # follow logs

7. Key options — especially the bind IP

Bind IP: --web.listen-address

For all three components, the HTTP server's --web.listen-address decides which IP and port to bind to. The format is host:port, and the host part is the interface to bind to.

--web.listen-address=0.0.0.0:9090     # all interfaces (default-like) — reachable from anywhere
--web.listen-address=127.0.0.1:9090   # localhost only — reachable only from the same host
--web.listen-address=10.0.0.5:9090    # bind to a specific NIC/IP — expose only the internal IP
--web.listen-address=:9090            # omitting host = all interfaces (same as 0.0.0.0)
--web.listen-address=[::1]:9090       # IPv6 localhost

How to choose:

  • 0.0.0.0 (all interfaces) — the most open. On a server with a public IP, leaving it as-is exposes it directly to the internet. Since Prometheus/Pushgateway/Alertmanager have no authentication by default, this is dangerous.
  • 127.0.0.1 (localhost) — suitable when placing them behind a reverse proxy (Nginx, etc.) on the same host that handles TLS/auth.
  • A specific internal IP (10.0.0.5) — when you want to expose only the management/private NIC and keep the public NIC closed.

Security advice: in production, default to binding to an internal IP or 127.0.0.1 + a firewall, and put a reverse proxy (TLS/auth) in front when external access is needed. The Prometheus family also supports native TLS/basic auth via --web.config.file.

Alertmanager's second bind: --cluster.listen-address

Besides --web.listen-address for the HTTP UI/API, Alertmanager has a separate --cluster.listen-address (default 0.0.0.0:9094) for gossip between HA cluster members.

  • For a single node, clustering isn't needed, so disable it with an empty value: --cluster.listen-address=
  • For multiple nodes (HA), bind to each node's IP and point at the others with --cluster.peer=<other-node:9094>.

Other key options

ComponentOptionMeaning
Prometheus--config.fileconfig file path
Prometheus--storage.tsdb.pathTSDB data directory
Prometheus--storage.tsdb.retention.timeretention period (default 15d). e.g. 30d
Prometheus--storage.tsdb.retention.sizeretention size cap. e.g. 50GB
Prometheus--web.enable-lifecycleallow /-/reload·/-/quit over HTTP
Prometheus--web.external-urlexternal URL behind a reverse proxy
Pushgateway--persistence.filepersist metrics across restarts (file path)
Pushgateway--persistence.intervalpersistence interval (default 5m)
Alertmanager--storage.pathpath for alert state (silences, etc.)
Alertmanager--data.retentionstate retention period (default 120h)

Enabling --web.enable-lifecycle lets you reload after config changes without a restart.

curl -X POST http://localhost:9090/-/reload

8. Connecting the three components

Configure prometheus.yml so Prometheus scrapes the Pushgateway, sends alerts to Alertmanager, and reads rule files.

global:
  scrape_interval: 15s
  evaluation_interval: 15s
 
rule_files:
  - "/etc/prometheus/rules/*.yml"
 
alerting:
  alertmanagers:
    - static_configs:
        - targets: ["127.0.0.1:9093"]
 
scrape_configs:
  - job_name: "prometheus"
    static_configs:
      - targets: ["127.0.0.1:9090"]
 
  - job_name: "pushgateway"
    honor_labels: true             # preserve pushed job/instance labels (required)
    static_configs:
      - targets: ["127.0.0.1:9091"]

After configuring, validate and reload:

promtool check config /etc/prometheus/prometheus.yml
curl -X POST http://localhost:9090/-/reload

9. Verifying

Each component exposes health/ready endpoints.

curl -s http://localhost:9090/-/healthy     # Prometheus
curl -s http://localhost:9090/-/ready
curl -s http://localhost:9091/-/healthy     # Pushgateway
curl -s http://localhost:9093/-/healthy     # Alertmanager
 
# check which ports are listening
sudo ss -ltnp | grep -E '9090|9091|9093'

Open http://<server-ip>:9090 (Prometheus), :9091 (Pushgateway), and :9093 (Alertmanager) in a browser to check the UIs. If every target is UP on Prometheus's Status → Targets, you're good.

10. (Bonus) systemd hardening

Beyond the dedicated user, narrowing the daemon's filesystem access with systemd security options is wise. Add to the [Service] section.

NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
PrivateTmp=true
ReadWritePaths=/var/lib/prometheus      # allow writes only to the data directory

ProtectSystem=strict makes the whole system read-only, so the key is to carve out the data directory via ReadWritePaths. (Do the same for the Pushgateway/Alertmanager with their respective data paths.)

Wrapping up

Installing the Prometheus stack is ultimately a repetition of place the binary → dedicated user/directories → systemd unit → tune options. The first thing to check in production is the bind IP. Since these components have no authentication by default, narrowing --web.listen-address to 127.0.0.1 or an internal IP, and fronting them with a firewall and a reverse proxy (TLS/auth), is a safe starting point.

As a next step, add exporters like node_exporter on top, and connect the alert rules and Alertmanager routing covered in earlier posts to complete the "collect → alert → notify" pipeline.