Skip to main content
9090

Port 9090Prometheus

TCP

Port 9090 is the Prometheus time-series metrics server port. Prometheus scrapes metrics from targets and exposes a query API and web UI on port 9090. Like many monitoring tools, Prometheus has no authentication by default. Publicly exposed Prometheus instances leak infrastructure topology, service names, resource utilization, and potentially secrets in metric labels.

Port Number

9090

Protocol

TCP

Service

Prometheus Metrics Server

Range

IANA Registered (1024–49151)

Description

Prometheus serves its PromQL query API, federation endpoint, and built-in UI on port 9090. Scrape targets expose metrics on /metrics (often port 9100 for node_exporter, 8080 for app metrics). Prometheus doesn't natively support authentication or TLS – the recommended approach is nginx reverse proxy with basic auth + TLS in front of port 9090. Thanos and Cortex add authentication for multi-tenant deployments.

Security risks

  • 1CVE-2021-29622: Open redirect in Prometheus web UI allowed phishing via crafted URLs (fixed 2.26.1/2.27.1)
  • 2No authentication by default – any network-adjacent attacker can query all metrics, discover service topology, read label values that may contain secrets
  • 3Federation endpoint (/federate) exposes all metric data to unauthorized scrapers if reachable
  • 4TSDB admin API (--web.enable-admin-api) allows deleting metric data and creating snapshots without auth
  • 5Remote Write receiver (--web.enable-remote-write-receiver) accepts arbitrary metrics injection, enabling metric poisoning for alerting bypass

Firewall guidance

Never expose port 9090 to the internet. Bind Prometheus to localhost or a private interface (--web.listen-address=127.0.0.1:9090). Place nginx with basic auth + TLS in front. In Kubernetes, use ClusterIP service. For multi-tenant, deploy Thanos or Mimir which add native auth. The /metrics endpoint on Prometheus itself should also be protected.

Diagnosis commands

Count how many scrape targets are UP

shell
curl -s http://localhost:9090/api/v1/query?query=up | jq '.data.result | length'

Show all DOWN scrape targets with last error

shell
curl -s http://localhost:9090/api/v1/targets | jq '.data.activeTargets[] | select(.health=="down")'

Dump current Prometheus config (check if admin API is enabled)

shell
curl -s http://localhost:9090/api/v1/status/config | jq .data.yaml | head -50

Validate Prometheus configuration file syntax

shell
promtool check config /etc/prometheus/prometheus.yml

Usage examples

Port 9090 – Prometheus
shell
curl http://localhost:9090/api/v1/query?query=up
curl http://localhost:9090/metrics
promtool query instant http://localhost:9090 'rate(http_requests_total[5m])'

Common services on this port

PrometheusVictoriaMetricsThanos QuerierCortexMimir

Related ports

History

Prometheus was created at SoundCloud in 2012 by Matt Proud and Julius Volz, inspired by Google's Borgmon. Open-sourced in 2015, it became the second CNCF project (after Kubernetes) in 2016 and graduated in 2018. Port 9090 was chosen as a common development port. PromQL became the de facto metrics query language. Prometheus 2.0 (2017) introduced the TSDB rewrite with dramatically better performance.

FAQ

How do I add authentication to Prometheus?

Since Prometheus 2.24, native basic auth and TLS are supported via web.yml (--web.config.file). Create web.yml with basic_auth_users and tls_server_config sections. For OAuth2/OIDC, use a reverse proxy (nginx, oauth2-proxy, or Pomerium). Thanos and Mimir add multi-tenant auth natively.

Prometheus vs VictoriaMetrics?

Both use port 9090 and support PromQL. VictoriaMetrics offers better compression (10x), native long-term storage, native clustering, and higher ingestion throughput. Prometheus is simpler operationally (single binary) and has the larger ecosystem. VictoriaMetrics is the common choice when Prometheus hits storage or cardinality limits.

Why are my Prometheus metrics showing gaps?

Gaps usually mean: (1) scrape target was down during that interval, (2) Prometheus itself restarted (check --storage.tsdb.retention.time), (3) target's /metrics took longer than scrape_timeout (default 10s), or (4) head compaction dropped samples from a crash. Check up{} metric for the target during the gap period.