Prometheus Metrics for OSS Password Pusher

Prometheus Metrics for OSS Password Pusher

TL;DR: Starting with v2.16.0, OSS Password Pusher has native Prometheus support. Set one environment variable, and you get push lifecycle counters, authentication event tracking, file upload metrics, plus the standard Rails/Puma/ActiveRecord instrumentation — all served from a standalone exporter that keeps sensitive data out of your metrics pipeline entirely.

Why This Matters

If you run Password Pusher on your own infrastructure, you already know the value of having visibility into what’s happening inside your services. How many pushes are being created? Are there spikes in failed passphrase attempts? Is something hammering the login endpoint?

Until now, answering those questions meant parsing application logs. That works, but it doesn’t give you the real-time dashboards, threshold alerts, and historical trend data that a proper metrics pipeline provides.

This release changes that.

How It Works

The Prometheus integration runs as a separate process inside the container, listening on port 9394. Puma web workers and the Solid Queue background worker send metrics to it asynchronously. Prometheus scrapes the /metrics endpoint on whatever interval you configure.

The architecture is deliberately simple:

  • Off by default. Nothing changes unless you set PWP__PROMETHEUS__ENABLED=true.
  • Fail-open. If the exporter process is unavailable, pushes, logins, and retrievals keep working normally. The metric is dropped, not the request.
  • No authentication data in metrics. Labels are bounded to safe values like push type (text, file, url, qr) and event category. No email addresses, user IDs, IP addresses, push tokens, or payload data ever appear in metric labels.

That last point is worth emphasizing. Password Pusher handles sensitive information by design. The metrics integration was built from the start to ensure none of that sensitivity leaks into your monitoring stack.

What You Get

Beyond the standard Rails metrics — HTTP request rates and durations, ActiveRecord connection pool stats, Puma thread utilization, Ruby process and GC metrics — Password Pusher adds five application-specific counters:

Metric Labels What It Tracks
pwpush_pushes_created_total kind, authenticated Push creation by type and whether a signed-in user created it
pwpush_retrievals_total kind, event Views, failed views, failed passphrase attempts, expirations, admin/owner views
pwpush_authentication_events_total event, mfa Login successes and failures, logouts, signups, MFA failures and rate limits
pwpush_uploaded_files_total — File attachment count
pwpush_uploaded_file_bytes_total — Total bytes uploaded

Some practical queries to get you started:

# Pushes created per hour, by type
sum by (kind) (increase(pwpush_pushes_created_total[1h]))

# Failed passphrase attempts in the last 15 minutes
sum(increase(pwpush_retrievals_total{event="failed_passphrase"}[15m]))

# Failed logins per minute (brute-force signal)
sum(rate(pwpush_authentication_events_total{event="login_failure"}[5m])) * 60

That third one — failed login rate — is the kind of signal that turns a metrics pipeline into a security tool.

Getting Started

For Docker Compose, add two environment variables and expose the metrics port on the loopback interface:

services:
  pwpush:
    image: pglombardo/pwpush:latest
    environment:
      PWP__PROMETHEUS__ENABLED: "true"
      PWP__PROMETHEUS__BIND: "0.0.0.0"
    ports:
      - "443:443"
      - "127.0.0.1:9394:9394"

For Kubernetes, the bundled Helm chart (v0.5.2+) has a metrics block that handles everything — environment variables, a dedicated ClusterIP service, and standard scrape annotations:

metrics:
  enabled: true
  scrapeAnnotations: true

The metrics port is never added to the public application service. If you use the Prometheus Operator, set scrapeAnnotations: false and point a ServiceMonitor at the metrics service instead.

One thing to keep in mind: the /metrics endpoint has no authentication. Keep port 9394 on a private network or cluster-internal service. Do not expose it to the internet.

Full configuration details, including how to use an external exporter and how to handle the separate worker image, are in the Prometheus Metrics documentation.

Credit Where It’s Due

This feature originated from a community contribution by @cgrard, who proposed the initial Prometheus exporter integration in PR #3957 back in December 2025. The final implementation refined the architecture and deployment wiring, but the idea and the initial work came from the community.

Thank you, @cgrard.


Peter Giacomo Lombardo Founder & Principal, Apnotic · Creators of Password Pusher