Skip to content

Proxy Configuration

The proxy runs outside the firewall alongside Prometheus. It accepts scrape requests from Prometheus on HTTP and communicates with agents via gRPC.

HTTP Service

Configure the HTTP service that Prometheus scrapes:

proxy {
  http {
    port = 8080                       // Listen port for Prometheus scrapes
    host = "0.0.0.0"                  // Listen address for Prometheus scrapes
    idleTimeoutSecs = 45              // HTTP idle timeout
    requestLoggingEnabled = true      // Log every proxy metrics request
  }
}

gRPC Service

Configure the gRPC service that agents connect to:

proxy {
  agent.port = 50051                  // gRPC listen port for agent connections

  grpc {
    keepAliveTimeSecs = 7200          // Interval between PING frames
    keepAliveTimeoutSecs = 20         // Timeout for PING acknowledgment
    permitKeepAliveWithoutCalls = false
    maxConnectionIdleSecs = -1        // -1 = unlimited
    maxConnectionAgeSecs = -1         // -1 = unlimited
  }
}

Agent Authentication

The agent gRPC port is unauthenticated by default. Set a pre-shared token so the proxy rejects agents that do not present a matching value (UNAUTHENTICATED). Resolved from --agent_token → AGENT_TOKEN → proxy.agentToken; empty (the default) disables the check and logs a startup warning unless mutual TLS is configured. The token is never logged.

proxy {
  agentToken = "shared-secret"   // Agents must present the same value
}

Per-Agent Identities

Scope agents to specific paths with proxy.auth: a list of named identities, each with its own token and allowed path glob patterns. The proxy resolves an agent's token to an identity and rejects any registerPath for a path that does not match the identity's patterns. An empty paths list allows all paths. A legacy proxy.agentToken (above) is honored alongside auth as an allow-all identity, easing migration. See Per-Agent Identities and Path Authorization for details and a migration walkthrough.

proxy {
  auth = [
    { name = team-a, token = "team-a-token", paths = ["team_a_*"] }
    { name = team-b, token = "team-b-token", paths = ["team_b_*"] }
  ]
}

Because auth is a list of objects, it is config-file-only — there is no CLI/env equivalent, and the -D override cannot express a list. Identity names must be unique and tokens non-empty.

Service Discovery

Enable Prometheus HTTP service discovery:

proxy {
  service.discovery {
    enabled = true
    path = "discovery"
    targetPrefix = "proxy-host.example.com:8080"
  }
}

See Service Discovery for complete details.

Admin Endpoints

Enable admin endpoints for health checks and debugging:

proxy {
  admin {
    enabled = true
    port = 8092
    pingPath = "ping"
    versionPath = "version"
    healthCheckPath = "healthcheck"
    threadDumpPath = "threaddump"
    debugEnabled = false
  }
}

When enabled, the following endpoints are available:

Endpoint Description
GET /ping Returns "pong" (liveness check)
GET /healthcheck Returns health status JSON
GET /version Returns version information
GET /threaddump Returns JVM thread dump
GET /debug Proxy debug info (requires debugEnabled = true)

Dashboard

A read-only operational dashboard on its own port. Off by default.

proxy {
  dashboard {
    enabled = false                 // Enable the operational dashboard
    port = 8094                     // Its own port, NOT the admin port
    path = "dashboard"              // Served at http://<proxy>:8094/dashboard
    host = "0.0.0.0"                // Listen address; "127.0.0.1" keeps it on the proxy host
    refreshIntervalSecs = 2         // Re-push interval for drifting counters
    recentScrapesQueueSize = 200    // Scrape records retained for the dashboard
    maxSessions = 50                // Concurrent WebSocket sessions; more are closed
    allowedOrigins = []             // Browser origins allowed besides the dashboard's own host
    allowedHosts = []               // Host names the dashboard answers to; empty turns the check off
  }
}

Also settable as --dashboard / --dashboard_port / --dashboard_path / --dashboard_host, or DASHBOARD_ENABLED / DASHBOARD_PORT / DASHBOARD_PATH / DASHBOARD_HOST.

The proxy logs a warning at startup when the dashboard is enabled on all interfaces. A WebSocket from a browser origin other than the dashboard's own host is refused; behind a reverse proxy that rewrites the Host header, list the public origin (for example "https://dash.example.com") in allowedOrigins. Being a list, allowedOrigins must be set in a config file rather than with -D.

allowedHosts (for example ["dash.internal"]) lists the names you reach the dashboard by, which stops DNS rebinding. It is off while empty, the default, and like allowedOrigins must be set in a config file. See Exposure for what both lists guard against.

It runs on its own port rather than the admin port, partly because the admin port is a servlet container that cannot host WebSockets, and partly so the dashboard can be firewalled without also cutting off the /ping and /healthcheck endpoints Kubernetes probes target.

Like the admin and metrics endpoints, it has no authentication and no TLS — treat the port as internal. See Dashboard for what it shows.

Metrics

Enable internal metrics collection:

proxy {
  metrics {
    enabled = true
    port = 8082
    path = "metrics"
  }

  admin {
    enabled = true
    port = 8092
  }
}

See Monitoring for the complete metrics reference.

Internal Settings

Configure agent cleanup and scrape request management:

proxy.internal {
  staleAgentCheckEnabled = true
  maxAgentInactivitySecs = 60         // Evict after 60s of inactivity
  staleAgentCheckPauseSecs = 10       // Check every 10s

  scrapeRequestTimeoutSecs = 90       // Timeout for scrape requests
}
Setting Default Description
staleAgentCheckEnabled true Enable periodic stale agent cleanup
maxAgentInactivitySecs 60 Seconds of inactivity before agent is evicted
staleAgentCheckPauseSecs 10 Interval between cleanup checks
scrapeRequestTimeoutSecs 90 Timeout for individual scrape requests
scrapeRequestBacklogUnhealthySize 25 Backlog that marks the proxy unhealthy; each agent's queue is capped at twice this
maxInFlightScrapeRequests 1000 Max scrapes in flight across all agents; more get a 503
scrapeRequestMapUnhealthySize 0 Scrapes in flight that mark the proxy unhealthy (0 = 80% of maxInFlightScrapeRequests)
chunkContextMapUnhealthySize 0 Chunked transfers in progress that mark the proxy unhealthy (0 = 80% of the same)
maxPathsPerAgent 20000 Max paths one agent connection may register; more are refused (0 = unlimited)
maxPathLength 512 Max characters in a registered path (0 = unlimited)
maxLabelsSizeBytes 8192 Max size of a path's labels JSON, in bytes (0 = unlimited)
maxAgentFieldLength 256 Max characters of an agent's name, host, launch ID, or endpoint (0 = unlimited)
maxAgentProxyEndpoints 16 Max entries of an agent's proxy endpoint list (0 = unlimited)

The three path limits are safety nets against a runaway or misbehaving agent, set well above normal use. A path over a limit is refused at registration, before it is checked against the agent's identity patterns, and the agent logs the rejection once without retrying it. The proxy warns when an agent reaches 80% of maxPathsPerAgent.

The two agent limits bound what an agent reports about itself when it registers. The proxy only displays these values, in its logs, service discovery labels, dashboard, and /debug page, but it repeats them for every path the agent serves. A longer value is cut to its first maxAgentFieldLength characters, and a longer endpoint list to its first maxAgentProxyEndpoints entries. The agent stays registered, and the proxy logs one warning naming what it cut.

Content Size Limits

proxy.internal {
  maxZippedContentSizeMBytes = 5      // Max zipped content size
  maxUnzippedContentSizeMBytes = 10   // Max unzipped content size
}

Transport Filter

The transport filter detects agent disconnections immediately. Disable it when using a reverse proxy like Nginx:

proxy.transportFilterDisabled = true

Warning

With transportFilterDisabled, agent disconnections are not immediately detected. Agent contexts on the proxy are removed after the inactivity timeout (default: 60 seconds).

Give each agent its own identity

With the filter disabled, the proxy can't tie a call to a connection, so it binds each agent's calls to the auth identity the agent connected with. Agents that share an identity, including every agent on the legacy proxy.agentToken, can't be told apart, so give each agent its own proxy.auth token. See Isolation Between Agents.

gRPC Reflection

gRPC Reflection is disabled by default, because it lets anyone who reaches the agent port list and describe the proxy's API. Enable it for debugging and tooling:

proxy.reflectionDisabled = false

When agent authentication is configured (proxy.agentToken or proxy.auth), reflection calls need a valid agent token, like every other call on the agent port.

Log Level

# Set log level in config file:
proxy.logLevel = "debug"
agent.logLevel = "debug"

# Or via CLI:
# java -jar prometheus-proxy.jar --log_level debug
# java -jar prometheus-agent.jar --log_level debug

# Or via environment variable:
# PROXY_LOG_LEVEL=debug
# AGENT_LOG_LEVEL=debug

# Available levels: trace, debug, info, warn, error, off

Full Reference

See the complete configuration schema: config/config.conf