Skip to content
appsgit

Deploy guide

How to self-host Prometheus with Docker Compose

Prometheus Docker Compose setup with Node Exporter for host metrics: prometheus.yml, retention, localhost-only ports, Grafana dashboards, backups and upgrades.

  • Updated
  • Intermediate
  • About 20 minutes

You will need

  • 1 vCPU / 1 GB RAM (more with many targets)
  • Docker + Docker Compose v2
  • Local disk for the time-series database
  • Grafana (optional, for dashboards)

What is Prometheus?

Prometheus is an open source monitoring system and time-series database. It scrapes metrics over HTTP from targets such as servers, containers, databases and applications, stores them efficiently on disk, and lets you query them with PromQL and trigger alerts. It is a graduated Cloud Native Computing Foundation project under the Apache-2.0 license and the default metrics backend for Grafana dashboards.

This guide runs Prometheus together with Node Exporter, the official exporter for Linux host metrics such as CPU, memory, disk and network.

Requirements

  • A Linux server with Docker Engine and Docker Compose v2. A small setup needs about 1 vCPU and 1 GB of RAM; memory grows with the number of time series.
  • Local disk for the database. A single host with Node Exporter produces modest data, but plan a few GB for months of retention.

Step 1: Prepare the server

This guide assumes Ubuntu 24.04 with Docker installed from the official Docker Engine guide.

mkdir -p ~/monitoring && cd ~/monitoring

Create prometheus.yml, the scrape configuration:

global:
  scrape_interval: 15s

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

  - job_name: node
    static_configs:
      - targets: ["host.docker.internal:9100"]

Step 2: Create the Docker Compose file

Node Exporter needs the host's network and process namespaces to report real host metrics, exactly as its official docs describe. Prometheus reaches it through host.docker.internal. Save this as docker-compose.yml:

services:
  prometheus:
    image: prom/prometheus:v3.15.0
    container_name: prometheus
    restart: unless-stopped
    command:
      - "--config.file=/etc/prometheus/prometheus.yml"
      - "--storage.tsdb.path=/prometheus"
      - "--storage.tsdb.retention.time=90d"
    ports:
      - "127.0.0.1:9090:9090"
    extra_hosts:
      - "host.docker.internal:host-gateway"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
      - prometheus_data:/prometheus

  node-exporter:
    image: prom/node-exporter:v1.12.1
    container_name: node-exporter
    restart: unless-stopped
    command:
      - "--path.rootfs=/host"
    network_mode: host
    pid: host
    volumes:
      - "/:/host:ro,rslave"

volumes:
  prometheus_data:

Overriding command replaces the image defaults, so the config file and storage path are passed explicitly. The 90-day retention replaces the 15-day default.

Two notes on ports. Prometheus has no login, so 9090 is bound to 127.0.0.1; Docker-published ports bypass ufw, and "9090:9090" would put your metrics on the internet. Node Exporter uses host networking instead, so it listens on port 9100 like a normal host process, and here ufw does apply. Allow the Docker networks and keep it closed to everyone else:

sudo ufw allow from 172.16.0.0/12 to any port 9100 proto tcp

Step 3: Start and open the app

docker compose up -d
ssh -L 9090:127.0.0.1:9090 user@YOUR_SERVER_IP   # run this on your laptop

Open http://localhost:9090, go to Status, Target health, and check that both prometheus and node are UP. Try a query such as node_memory_MemAvailable_bytes on the Query page.

To get dashboards, add Grafana to this same Compose file (see our Grafana guide), create a Prometheus data source with the URL http://prometheus:9090, and import dashboard ID 1860 (Node Exporter Full).

Step 4: Put it behind HTTPS

Most people never expose Prometheus and only publish Grafana. If you do need remote access, put it behind Caddy with authentication:

prometheus.example.com {
    basic_auth {
        admin PASTE_HASH_FROM_caddy_hash-password
    }
    reverse_proxy 127.0.0.1:9090
}

Generate the hash with caddy hash-password and a strong password such as the output of openssl rand -hex 32.

Backups and upgrades

Prometheus data is usually treated as replaceable, but if you want history to survive a disk failure, take a snapshot. That requires starting Prometheus with --web.enable-admin-api, then:

curl -XPOST http://127.0.0.1:9090/api/v1/admin/tsdb/snapshot

The snapshot appears under /prometheus/snapshots in the volume; copy it off-site. Always back up prometheus.yml and docker-compose.yml. To upgrade, bump the tags after reading the release notes, then:

docker compose pull && docker compose up -d

Troubleshooting

  • Node target is DOWN with "connection refused" or a timeout: the firewall blocks 9100 from Docker networks, or the extra_hosts line is missing.
  • "permission denied" on /prometheus: the image runs as user nobody. Use a named volume, or chown 65534:65534 a bind-mounted folder.
  • Config changes ignored: Prometheus reads the file at startup. Run docker compose restart prometheus, or enable --web.enable-lifecycle and POST to /-/reload.
  • Disk keeps growing: lower the retention time or set --storage.tsdb.retention.size.

Next steps

Add cAdvisor for per-container metrics, write alert rules and route them through Alertmanager, scrape exporters for your databases and apps, and add more servers by installing Node Exporter on each.

Spotted something out of date? Tell us and we will update the guide.

FAQ

Prometheus questions

Still curious? Email info@appsgit.com.

What port does Prometheus use?

The Prometheus server and web UI listen on port 9090. Node Exporter serves host metrics on port 9100, and other exporters use their own ports.

Does Prometheus have a login or password?

No. Prometheus has no authentication by default, which is why this guide binds port 9090 to localhost. Add basic auth through a web config file or put it behind a reverse proxy with authentication before exposing it.

Is Prometheus free?

Yes. Prometheus is a free, open source Cloud Native Computing Foundation project under the Apache-2.0 license, with no paid edition.

Prometheus vs Grafana: what is the difference?

Prometheus collects and stores metrics and evaluates alert rules. Grafana draws dashboards from data sources, Prometheus being the most common. Most setups run both: Prometheus as the database, Grafana as the interface.

How long does Prometheus keep data?

Prometheus keeps 15 days of data by default. Change it with the --storage.tsdb.retention.time flag (for example 90d), or cap disk use with --storage.tsdb.retention.size.

Prometheus vs InfluxDB?

Prometheus pulls metrics from exporters on a schedule and has its own query language, PromQL, built for monitoring and alerting. InfluxDB is a general time-series database that applications push data into. For server and container monitoring, Prometheus has the larger exporter ecosystem.