Deploying without observability is flying without instruments. This episode enables structured JSON logs, the Prometheus metrics endpoint, Grafana dashboards, alerting for authentication failures and 5xx errors, up to centralized log aggregation with Loki.

Episode 25 deployed Authelia to Kubernetes with HPA, probes, and network policies. The infrastructure is running, but there's one question still unanswered: how do you know Authelia is actually healthy? A flight doesn't rely on the pilot's feelings — it relies on instruments. Episode 26 builds those instruments: structured logs, metrics, dashboards, and alerting.
Why is observability for Authelia so important? Because Authelia is the gate. A small problem at the gate — server down, broken session storage, a brute force surge — impacts every application behind it. The earlier it's detected, the smaller the blast radius. Monitoring here isn't an add-on; it's the safety net for the entire architecture built since episode 13.
Authelia writes logs to stdout (standard for containers) in two formats: text and json. For production, use JSON — a structured format that can be parsed by machines, filtered, and aggregated without ambiguity. Enable it via the log block in the configuration:
log:
level: info
format: json
file_path: ''file_path is left empty so logs keep flowing to stdout and are handled by the runtime (Docker logging driver, kubelet, etc.). Don't write logs to a file inside the container — that file disappears when the container is replaced, and it isn't rotated automatically.
An example JSON log line produced when a request is processed:
{"time":"2026-08-03T10:00:00Z","level":"info","msg":"Request processed","method":"GET","path":"/api/verify","status_code":200,"latency_ms":12}With a format like this, you can make queries like "all requests to /api/verify that returned 5xx in the last 5 minutes" — something almost impossible to do with plain text logs.
Authelia log levels: trace, debug, info, warn, error. A rule of thumb:
info — balanced between information and volume.debug — reveals authorization decisions and session flows.trace — extremely noisy and may include sensitive data.You can change the level without restarting via hot reload, but remember: permanent debug and trace in production is a performance leak and a privacy risk — a topic you already learned in episode 23.
Authelia ships with a built-in Prometheus exporter. Enable it via the telemetry block — the endpoint stands on a separate port (default :9959) so it isn't mixed with authentication traffic:
telemetry:
metrics:
enabled: true
address: 'tcp://:9959/metrics'Important
Important note: the address above already includes the /metrics path. Without that path, the endpoint responds 404 — the most common complaint in the Authelia forums. Check directly with curl -fsS http://127.0.0.1:9959/metrics to make sure metrics are served.
Never expose port 9959 to the public. Metrics don't contain credentials, but they provide a complete map of authentication patterns — valuable enough for an attacker during reconnaissance.
Authelia exposes counters and histograms prefixed with authelia_. The most important metrics to monitor:
| Metric | Vector | Meaning |
|---|---|---|
authelia_request_total | code, method | All HTTP requests; the basis for measuring 5xx |
authelia_authz_total | code | Authorization requests (verify endpoint) |
authelia_authn_total | success, banned | 1FA authentication — the source of brute force detection |
authelia_authn_second_factor_total | success, banned, type | 2FA authentication per type (totp, webauthn, duo) |
authelia_authn_passkey_total | success | Passkey authentication |
authelia_authn_duration | success | Authentication time histogram |
From these you can compute the authentication success-failure ratio, detect banned=true spikes (a sign of brute force held back by regulation), and measure authentication latency. Note that metric names can change between versions — when moving versions, compare the /metrics output before updating dashboards.
Add a scraping job in prometheus.yml. If Authelia runs in Docker Compose, just target the service name; in Kubernetes, use a ServiceMonitor:
scrape_configs:
- job_name: authelia
metrics_path: /metrics
scheme: http
static_configs:
- targets: ['authelia:9959']With this job, Prometheus pulls metrics every 15 seconds and stores them in a time series — the raw material for dashboards and alerts.
Authelia provides a community dashboard that can be imported directly into Grafana as a starting point. That dashboard shows request summaries, authentication failure rates, and latency — complete with panels using the metrics above.
Don't stop at the built-in dashboard. Build custom panels that answer your own operational questions:
authelia_authn_duration histogram)authelia_authn_total with banned="true")A good dashboard turns numbers into decisions, not just a collection of pretty panels.
A dashboard is only useful while you're watching it. Alerting works 24 hours. Define rules in Prometheus — here's an example for the three most important scenarios:
groups:
- name: authelia
rules:
- alert: AutheliaDown
expr: up{job="authelia"} == 0
for: 5m
labels:
severity: critical
annotations:
summary: "Authelia tidak merespons scraping"
- alert: AuthenticationFailuresSpike
expr: rate(authelia_authn_total{success="false"}[5m]) > 10
for: 2m
labels:
severity: warning
annotations:
summary: "Lonjakan kegagalan autentikasi 1FA"
- alert: HighServerErrors
expr: sum(rate(authelia_request_total{code=~"5.."}[5m])) > 0.05
for: 5m
labels:
severity: warning
annotations:
summary: "Terlalu banyak respons 5xx dari Authelia"Forward the alerts to a channel the team actually watches: Telegram, Discord, Slack, or email — via Alertmanager. The two alarms that most often save production are the spike in failed authentications (a sign of attack or broken config) and AutheliaDown (a sign the whole gate is closed).
Metrics tell you whether there's a problem; logs tell you why. During an incident, you need to read logs from all instances at once, not open terminals one by one. Loki — Prometheus's natural pair from Grafana — accepts Authelia's JSON logs and indexes them by label:
discovery.relabel "authelia" {
targets = discovery.docker.targets("docker", {}).output
rule {
source_labels = ["__meta_docker_container_name"]
regex = "authelia-.*"
action = "keep"
}
rule {
source_labels = ["__meta_docker_container_name"]
target_label = "container"
}
}With the container="authelia" label, a Loki query like {container=~"authelia.*"} |= "level\":\"error" immediately shows all errors from all instances in one place. Promtail for file-based setups or kube-prometheus-stack for Kubernetes are common alternatives.
Episode 26 completes the observability layer: enabling structured JSON logs at the right level, turning on the Prometheus metrics endpoint on port 9959, scraping it with a job, displaying it in Grafana dashboards, enforcing alerting for critical scenarios, and aggregating logs centrally with Loki.
Key points:
log.format: json and let logs flow to stdout.telemetry.metrics.address with the /metrics path — without the path, the endpoint 404s.authelia_authn_total and authelia_authn_second_factor_total for attack patterns.AutheliaDown, authentication failure spikes, and 5xx.All the data is collected — now the question: what happens if everything is lost? In episode 27 we dissect Backup & Disaster Recovery: what must be backed up, strategies, restore procedures, and disaster scenarios. See you in episode 27!