Infrastructure guide

Prometheus Docker Compose: Persistent Metrics and Reachable Targets

Configure Prometheus with persistent metrics, reachable Docker targets, bounded retention, private access, and a tested recovery path.

Published and reviewed by OpenAlt · October 4, 2026

An IT professional operates a computer in a server room, managing network systems and connected devices.
Photo by panumas nikhomkhai on Pexels

A useful Prometheus Docker deployment must retain samples, reach the services it scrapes and remain private enough to protect operational information. Start with one self-scrape target, durable storage and a clear retention limit. Add dashboards and exporters only after you can explain how data reaches the server.

Our rule is that an empty dashboard is not a monitoring system. A successful installation includes a known-good query, a controlled target failure and an alert path someone can actually receive. The Compose file is only the first part of that job.

Table of contents

What does this deployment provide?

This is a single-server starting point for collecting metrics from a small self-hosted stack. It does not supply redundant monitoring, an on-call service or automatically correct application alerts.

Prometheus periodically scrapes HTTP endpoints and stores time-series samples. The project's getting-started guide begins with the server monitoring itself. That is a useful first check because it removes unrelated application networking from the initial diagnosis.

Review the OpenAlt Prometheus profile if you are still choosing the monitoring component. Decide whether someone can own storage, configuration and alert delivery. If the answer is no, a maintained monitoring service may be the better operational choice even when running a container looks easy.

Set a narrow first objective: retain a useful history, detect a failed target and explain who responds. Avoid adding every exporter you can find. Unused metrics increase the amount of configuration and data the next operator must understand.

How do you create a persistent Compose stack?

Mount the configuration read-only and keep the time-series database in a persistent volume. The official installation guide uses port 9090; the container reads its configuration from /etc/prometheus/prometheus.yml.

Create a new directory with these two files. First, prometheus.yml:

global:
  scrape_interval: 30s
scrape_configs:
  - job_name: prometheus
    static_configs:
      - targets: ["localhost:9090"]

Then save compose.yaml:

services:
  prometheus:
    image: prom/prometheus:latest
    ports:
      - "127.0.0.1:9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
      - metrics:/prometheus
    command:
      - --config.file=/etc/prometheus/prometheus.yml
      - --storage.tsdb.path=/prometheus
      - --storage.tsdb.retention.time=15d
    restart: unless-stopped
volumes:
  metrics:

The 30s interval is a choice for this initial example, not a universal recommendation. The explicit retention setting makes the operating policy visible. Start with docker compose up -d, inspect logs and open the loopback address on the host or through an SSH tunnel.

Before routine use, pin the validated image version or digest. Preserve both configuration files in private version control. Never remove the volume as a casual troubleshooting step: it contains the history you intended to retain.

Which address should a scrape target use?

Use an address reachable from the Prometheus container, not merely from your laptop. Inside a container, localhost names that container's own network namespace.

The initial localhost:9090 target works because Prometheus is scraping itself. An application in another service on the same Compose network generally needs that service's DNS name and internal metrics port. A service running on the physical host needs a host address that is actually reachable from the container; the exact mechanism depends on the Docker platform.

The getting-started documentation shows how target configuration defines the endpoints to scrape. Write down three addresses for each application: the browser URL, the internal application address and the metrics endpoint. They may be different, especially when a reverse proxy sits in front.

Do not publish every metrics endpoint to the internet to make routing easier. Test reachability within the intended private network. If a target fails, distinguish DNS resolution, connection refusal, timeout, authentication and an incorrect HTTP path before changing configuration.

Close-up view of modern rack-mounted server units in a data center.
Photo by panumas nikhomkhai on Pexels
Abstract visualization of data analytics with graphs and charts showing dynamic growth.
Photo by Negative Space on Pexels

How do you verify collection and retention?

Check both current target health and historical samples. A successful scrape now does not prove that data survived yesterday's container replacement.

Open the target status view and query up. For the initial self-scrape job, expect a healthy target and recent samples. Query a known metric over a short time range, then restart the container and verify the earlier samples remain available.

Use a disposable target for a failure drill. Stop that target, observe the scrape failure and confirm recovery after restarting it. Keep production services out of this first experiment. Once alerting exists, repeat the drill to prove delivery rather than assuming a firing rule reaches a person.

The Prometheus storage documentation describes local time-series storage and retention. A named volume preserves that storage across ordinary container recreation. It does not create an independent copy, and removing the underlying Docker host can still remove the history.

When connecting Grafana, use the address visible from the Grafana server rather than your browser. Our Grafana Compose guide covers its own persistent state and provisioning responsibilities.

How much storage should you reserve?

Choose retention from the investigation history you need, then measure actual ingestion and disk growth. Do not infer capacity from the number of applications alone: label combinations and scrape frequency can change the amount of data dramatically.

Prometheus documents a default time retention of 15d when no retention limit is supplied. Its storage guidance also recommends leaving disk headroom when using a size limit, rather than assigning the entire filesystem to retained blocks. Local storage should use a supported local filesystem; NFS is not a safe substitute for the time-series database directory.

Make an operating worksheet containing the volume location, retention policy, current free space and observed daily growth. Set an alert before free space becomes critical. Review labels for unbounded values such as individual request IDs or arbitrary user input.

If the history is valuable for incident investigation, keep the capacity policy independent of unrelated downloads on the same host. A media import should not silently consume the disk space your monitoring system needs during an outage.

How do you protect the monitoring interface?

Treat access to the monitoring interface as access to operational information. Keep it on a private network or behind an intentional authentication layer; a convenient public URL is not the same as an appropriately protected service.

The Prometheus security model explains that users with access to the HTTP endpoint can inspect time-series data and operational details. Metric labels, target addresses and configuration context can reveal information that was never intended for public readers.

This example binds the host port to loopback. A reverse proxy in another container must reach Prometheus through a shared private network, not through that proxy's own loopback address. Test the allowed route and the denied route from separate clients.

Avoid enabling administrative or lifecycle features just because a copied example contains their flags. Add capabilities only when you understand who can call them. Record authentication ownership and certificate renewal alongside the service configuration.

What does recovery require?

Recover configuration and stored history as separate assets, and monitor the monitor from outside its own failure domain. A stopped Prometheus server cannot reliably tell you that it stopped.

The storage documentation describes snapshot and backup considerations. For a small installation, a planned stop followed by a consistent volume backup can provide a simple rehearsal path. Do not assume copying actively changing database files produces a valid recovery set.

Restore to an isolated instance, check a known historical query and confirm that intended targets can be reached before reconnecting alert delivery. Keep the previous image and matching data backup together for upgrades that may change storage behavior.

Use the infrastructure guides to plan dependencies such as the reverse proxy and database separately. Monitoring becomes dependable when its storage, network and human response path are understandable together.

FAQ

Why does localhost fail for another container?

It points back to Prometheus itself. Use the other service's reachable network name and metrics port.

Is Grafana required?

No. Prometheus has its own query interface. Add Grafana when shared dashboards improve the workflow.

Is a persistent volume a backup?

No. It preserves data across container replacement but can disappear with the host or underlying storage.

How do I detect a Prometheus outage?

Use an independent check outside that server's failure domain and verify that its notification reaches the responsible person.