Prometheus Docker Compose: A Complete Setup Guide
Disclosure: This post contains one or more links to providers we have a real, registered affiliate/referral relationship with. We may earn a commission at no extra cost to you if you sign up through them.
Running Prometheus via Docker Compose is one of the fastest ways to get real, working metrics collection on a server without wrestling with systemd units or manual binary installs. This guide walks through a full prometheus docker compose setup – from a minimal config to scraping targets, adding Grafana, persisting data, and avoiding the mistakes that trip up most first-time setups.
Whether you’re monitoring a single VPS or a small fleet of containers, a docker-compose.yml-driven Prometheus stack gives you a reproducible, version-controllable monitoring layer that you can tear down and rebuild in seconds. That reproducibility is the real reason most teams choose a prometheus docker compose approach over a manually configured install: the whole stack lives in one file, checked into git, instead of scattered across server state nobody remembers.
Why Use Docker Compose for Prometheus
Prometheus itself is a single static binary with a YAML config file, so in theory you don’t need Docker at all. In practice, Docker Compose solves several problems at once for a prometheus docker compose deployment:
docker compose down && docker compose up -d gives you a clean slate in seconds.docker-compose.yml and prometheus.yml work identically on a laptop, a staging VPS, or production.If you’re already running other services with Compose, adding Prometheus to the same host is a natural extension rather than a separate operational concern.
Prometheus vs. a Manual Install
A manual install (downloading the binary, writing a systemd unit, managing the config path by hand) still works fine and is arguably lighter-weight for a single always-on server. The tradeoff is that upgrades become manual binary swaps, and there’s no built-in isolation between Prometheus’s dependencies and the rest of the host. A prometheus docker compose setup trades a small amount of Docker overhead for consistency and easier rollback – you can revert to a previous image tag instantly if an upgrade misbehaves.
Prerequisites
Before setting up prometheus docker compose, you need:
docker compose version should return a version string, not an error).docker-compose.yml and prometheus.yml are plain YAML files.If you’re setting this up on a VPS for the first time, see the general guide to self-hosting n8n on a VPS for a comparable pattern of running a Docker Compose stack on a small server – the same host sizing and networking considerations apply.
Basic Prometheus Docker Compose Setup
The simplest possible prometheus docker compose file runs just the Prometheus server, mounts a config file, and exposes port 9090.
Start with a project directory containing two files: docker-compose.yml and prometheus.yml.
# docker-compose.yml
services:
prometheus:
image: prom/prometheus:latest
container_name: prometheus
restart: unless-stopped
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
- prometheus_data:/prometheus
ports:
- "9090:9090"
command:
- "--config.file=/etc/prometheus/prometheus.yml"
- "--storage.tsdb.retention.time=15d"
volumes:
prometheus_data:
And a minimal prometheus.yml that scrapes Prometheus’s own metrics endpoint:
# prometheus.yml
global:
scrape_interval: 15s
scrape_configs:
- job_name: "prometheus"
static_configs:
- targets: ["localhost:9090"]
Bring it up with:
docker compose up -d
Visit http://your-server-ip:9090 and you should see the Prometheus web UI. Under Status → Targets, the prometheus job should show as UP. This confirms the base prometheus docker compose stack is working before you add anything else.
Understanding the Volume Mounts
The prometheus.yml:ro mount is read-only by design – Prometheus never writes back to its own config file, so mounting it read-only prevents accidental modification from inside the container. The prometheus_data named volume is where Prometheus stores its time-series database (TSDB); without it, every docker compose down (without -v) would still preserve data, but a full volume removal would wipe your metric history. Keep this distinction in mind when scripting cleanup commands.
Setting Retention and Storage Flags
The --storage.tsdb.retention.time flag controls how long Prometheus keeps data before deleting old blocks. Fifteen days is a reasonable default for a small deployment, but you can also cap by size with --storage.tsdb.retention.size if disk space is a tighter constraint than time. Both flags can be combined – Prometheus deletes data once either threshold is hit, whichever comes first.
Adding Scrape Targets
A Prometheus server that only scrapes itself isn’t very useful. The real value of a prometheus docker compose setup comes from adding scrape targets for the services you actually want to monitor.
Scraping the Node Exporter
To collect host-level metrics (CPU, memory, disk, network), add the Node Exporter as a second service in the same Compose file:
services:
prometheus:
image: prom/prometheus:latest
# ... (as above)
node-exporter:
image: prom/node-exporter:latest
container_name: node-exporter
restart: unless-stopped
pid: host
volumes:
- /proc:/host/proc:ro
- /sys:/host/sys:ro
- /:/rootfs:ro
command:
- "--path.procfs=/host/proc"
- "--path.sysfs=/host/sys"
- "--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)"
ports:
- "9100:9100"
Then add a scrape job to prometheus.yml:
- job_name: "node"
static_configs:
- targets: ["node-exporter:9100"]
Note that inside the Compose network, Prometheus reaches the exporter by service name (node-exporter), not localhost – Docker Compose’s default bridge network resolves service names as DNS hostnames automatically.
Scraping Application Metrics
If your own application exposes a /metrics endpoint (most frameworks have a Prometheus client library for this), add it the same way – as another static_configs block pointing at the service name and port. For dynamic environments with containers that come and go, Prometheus also supports service discovery mechanisms (Docker Swarm, Kubernetes, file-based) instead of hardcoded static targets, though a static config is usually sufficient for a small, stable stack.
Adding Grafana for Visualization
Prometheus’s built-in web UI is functional for ad-hoc queries but not built for dashboards. Pairing your prometheus docker compose stack with Grafana is the standard next step.
grafana:
image: grafana/grafana:latest
container_name: grafana
restart: unless-stopped
ports:
- "3000:3000"
volumes:
- grafana_data:/var/lib/grafana
depends_on:
- prometheus
volumes:
grafana_data:
After docker compose up -d, log in to Grafana at http://your-server-ip:3000 (default credentials are admin/admin, and Grafana forces a password change on first login). Add Prometheus as a data source using the internal Docker network address http://prometheus:9090 – not localhost, since Grafana runs in its own container. From there, you can import a community dashboard for Node Exporter metrics or build your own panels against your application’s custom metrics.
Persisting Data and Handling Backups
Data persistence is easy to overlook until you lose it. In the Compose file above, both prometheus_data and grafana_data are named volumes, which Docker manages outside the container’s writable layer – they survive docker compose down and container recreation, but not docker compose down -v or a manual docker volume rm.
For anything you actually care about keeping:
tar job against the volume’s mount point, or a dedicated backup tool.If you’re also running a database alongside this stack, the same persistence principles apply – see the guide to Postgres with Docker Compose for a closely related pattern of volume-backed data durability.
Securing Your Prometheus Docker Compose Deployment
By default, the Compose file above exposes Prometheus and Grafana directly on the host’s public ports. For anything beyond local testing, that’s a real exposure risk – Prometheus’s UI has no built-in authentication.
127.0.0.1:9090:9090 instead and put a reverse proxy in front with authentication..env files.Troubleshooting Common Issues
A few problems come up repeatedly with prometheus docker compose setups:
Targets Showing as “Down”
If a target shows DOWN in the Targets page, the most common cause is using localhost instead of the Docker Compose service name in prometheus.yml. Containers on the same Compose network communicate via service name DNS, not localhost – each container has its own network namespace. Fix the targets: entry to use the service name and re-run docker compose restart prometheus, or check logs with the patterns covered in the Docker Compose logs debugging guide.
Config Changes Not Taking Effect
Editing prometheus.yml on the host doesn’t automatically reload the running container’s in-memory config. Either restart the container (docker compose restart prometheus) or, if you started Prometheus with the --web.enable-lifecycle flag, trigger a hot reload via curl -X POST http://localhost:9090/-/reload without a restart.
Rebuilding After a Compose File Change
If you change the docker-compose.yml itself (new service, new port mapping), a simple restart isn’t enough – you need to recreate the containers. Run docker compose up -d again, which detects the diff and recreates only the affected services, or see the Docker Compose rebuild guide for a fuller breakdown of when --build or --force-recreate is actually needed.
Choosing Where to Host Your Monitoring Stack
A prometheus docker compose stack is lightweight enough to run on a small VPS instance, but disk I/O and available memory both affect how many metrics you can retain and for how long. If you’re provisioning a new server specifically for monitoring, providers like DigitalOcean or Vultr offer small instances that are generally sufficient for a Prometheus + Grafana + a handful of exporters, provided you keep retention windows reasonable and monitor disk usage on the TSDB volume itself.
Recommended: Ready to put this into practice? DigitalOcean is a tool we use for exactly this, and we have a real, disclosed affiliate relationship with them.
FAQ
Does Prometheus in Docker Compose persist data across restarts?
Yes, as long as you use a named volume or bind mount for /prometheus (the TSDB storage path). A plain docker compose restart or down/up cycle preserves the volume; only an explicit docker compose down -v or manual volume deletion removes it.
Can I run Prometheus and Grafana in the same Compose file as my application?
Yes – this is a common pattern. Add Prometheus, Grafana, and any exporters as additional services in your application’s existing docker-compose.yml, and they’ll share the same default network, letting Prometheus reach your app’s metrics endpoint by service name.
How do I add more scrape targets later?
Edit the scrape_configs section of prometheus.yml and reload Prometheus – either a container restart or a hot reload via the /-/reload endpoint if --web.enable-lifecycle is set. No changes to docker-compose.yml are needed unless the new target is a service you’re also adding to the same Compose stack.
Is Docker Compose suitable for production Prometheus deployments, or only Kubernetes?
Docker Compose is a reasonable choice for a single-host production deployment monitoring a small to medium number of targets. Once you need multi-host scaling, high availability, or dynamic service discovery across a cluster, a Kubernetes-based setup (using the Prometheus Operator or similar) becomes more appropriate – see the Kubernetes vs Docker Compose comparison for a broader look at when that step makes sense.
Conclusion
A prometheus docker compose setup gives you a reproducible, version-controlled monitoring stack that’s straightforward to extend – start with a single Prometheus service scraping itself, add exporters and application targets, layer Grafana on top for dashboards, and lock down access before exposing anything publicly. The core pattern (one docker-compose.yml, one prometheus.yml, named volumes for persistence) scales from a single small VPS up to a moderately sized fleet of monitored services without needing a different toolset. For further reference, the official Prometheus documentation and Docker Compose documentation cover configuration options and flags in more depth than this guide’s basics.
Leave a Reply