Monitoring Authentik with Prometheus and Grafana: using the metrics endpoint on port 9300, understanding key metrics like login success and failure rates and latency, setting log levels and structured logging, keeping the database and Redis healthy, and building proper alerting.

In episode 24, you placed Authentik on Kubernetes — server and worker running as Deployments, database and Redis as stateful services. A healthy deployment today doesn't guarantee a healthy one tomorrow; the database can fill up, the worker can lag, or strange login patterns can start appearing from a single IP address. That's why this episode comes at the right time: monitoring.
Authentik is an identity provider, and this makes it special in one way: it's a single point of failure for the entire application ecosystem. When Authentik goes down, every application serving authentication is locked out too — far more costly than just one website erroring. Imagine the indicator lights in an airplane cockpit: the pilot doesn't care how many lights there are, they care which lights come on when there's a problem. This episode builds the "indicator panel" for your Authentik.
Before talking about metrics, there are two endpoints that must be watched at all times. Authentik provides simple but very informative liveness and readiness endpoints:
/-/health/live/ — returns 200 as long as the Authentik process is running. Note the trailing slash; without it, some versions return 404./-/health/ready/ — returns 200 only if a connection to PostgreSQL can be established. This is the "ready to accept traffic" signal.curl -fsS https://auth.example.com/-/health/live/
curl -fsS https://auth.example.com/-/health/ready/For the worker, use the ak healthcheck command inside the container — it verifies the worker is running and the database is reachable. These two endpoints are what Docker Compose and Kubernetes use as built-in probes; you only need to expose them to an external monitoring system so they're recorded as uptime.
Authentik exposes Prometheus metrics on port 9300 — separate from the main HTTP port 9000. Important: these metrics require no authentication, so the port is deliberately not exposed publicly. The server, worker, and every outpost all provide the :9300/metrics endpoint.
Because it's a pull model toward the scraper, just point Prometheus at those targets:
scrape_configs:
- job_name: authentik
metrics_path: /metrics
static_configs:
- targets:
- authentik-server:9300
- authentik-worker:9300Kubernetes users can use the ServiceMonitor the chart already provides — just enable it via the server.metrics.serviceMonitor.enabled and worker.metrics.serviceMonitor.enabled values in values.yaml. The Prometheus operator that discovers the ServiceMonitor will automatically start scraping. Verify the object is actually created with kubectl get servicemonitors -n authentik, wait a few minutes, and confirm the targets appear on the Prometheus status page.
One important note about port 9300: because the metrics require no authentication, make sure this port is only reachable from the internal monitoring network. In Kubernetes, that means the metrics Service must not be exposed externally; in Compose, don't map port 9300 to the host.
Metrics alone are useless without understanding what they mean. Group them into four categories and ask one question of each:
| Category | Question it answers | Danger signal |
|---|---|---|
| Availability | Are the server and worker alive? | up equals 0 or readiness isn't 200 |
| Traffic | How many requests come in and from where? | Volume suddenly rises from a specific IP |
| Latency | How fast do authentication flows complete? | The 99th percentile starts exceeding the target |
| Business health | How many logins succeed and fail? | A spike in failures = brute force indication |
The last two categories deserve emphasis. Latency is usually measured via the request duration histogram; for the SSO user experience, the 99th percentile (not the average) is the deciding number — because it's the user logging in 3 seconds slower than usual who complains. As for successful and failed logins, you can get them from two places: the event system in the admin (episode 22) which provides complete context on who, from where, and when, and the server-side metrics. The combination of both forms the basis of brute force detection that complements the reputation system from episode 19.
Authentik logs use a structured (key-value) format that's easy for aggregators like Loki or ELK to parse. The level is controlled by the AUTHENTIK_LOG_LEVEL variable, defaulting to info. The level order: debug, info, warning, error, critical.
environment:
AUTHENTIK_LOG_LEVEL: "debug"The rule: keep info in production — the debug level produces a huge log volume and slows things down. Raise it to debug temporarily only during an active investigation, then restore it. These structured logs must also have a bounded retention period; aggregators and retention policies prevent full disks and help compliance (episode 22).
The readiness endpoint already ensures PostgreSQL is reachable, but that isn't everything. For Postgres, watch the number of active connections against max_connections and the presence of slow queries. For Redis, watch memory usage against maxmemory and the number of evictions — if Redis keeps evicting keys because memory is full, the task queue and cache become increasingly ineffective.
docker compose exec postgresql psql -U authentik -d authentik \
-c "SELECT count(*) FROM pg_stat_activity WHERE state = 'active';"Redis in Authentik is a cache and message queue — the data in it may be lost (it isn't a source of truth), so a persisted Redis usually just wastes resources. What matters is its health and capacity.
If metrics show latency worsening, order the investigation from the most likely cause:
max_connections, or slow queries. Consider a connection pooler like PgBouncer in front of Postgres, and check the indexes used by common queries.Don't tune before measuring. A baseline from a few weeks of Prometheus data is the compass showing whether a configuration change actually improves things.
Metrics without alerts are like a smoke detector that only sounds once the kitchen is already on fire. Create alert rules based on your SLO: server down for 5 minutes, the 99th percentile of latency exceeding a threshold, a sharp rise in failed logins, or metric volume suddenly zero (which could mean a failed scrape).
groups:
- name: authentik
rules:
- alert: AuthentikDown
expr: up{job="authentik"} == 0
for: 5m
labels:
severity: critical
annotations:
summary: "Authentik tidak bisa di-scrape selama 5 menit"Send alerts to Alertmanager, then to a communication channel that's actually watched — email, Telegram, Slack, or PagerDuty. Noisy alerts are actually dangerous: too many alarms cause "alert fatigue", and eventually nobody pays attention when a real incident happens.
In this episode 25, you learned to monitor Authentik thoroughly: the /-/health/live/ and /-/health/ready/ endpoints for availability, Prometheus metrics on port 9300 for the server, worker, and outposts, four key metric categories from availability to business health, log level and structured logging settings, PostgreSQL and Redis health monitoring, basic performance tuning steps, and alerting that turns metrics into action.
Key takeaways:
debug level is only for investigations; keep info in production.A system that can be watched is a system that can be saved. In episode 26, we cover Backup & Disaster Recovery: what must be backed up (database, blueprints, keys), how to dump and restore PostgreSQL correctly, disaster recovery procedures, and why a backup that's never been tested is just an illusion of security. See you in episode 26!