{# traefik/rows.html — HTMX fragment for the Traefik page: routers that need attention first (routes.router_state), the proxy's own counts, the healthy routers folded into one table, then certificates by soonest expiry. #} {% from "_macros.html" import stat_tile, status_badge %} {# ── Counts ───────────────────────────────────────────────────────────────── #}
{{ stat_tile("Needs attention", problems|length, state="crit" if problems else "inactive") }} {{ stat_tile("Healthy routers", healthy|length, state="up" if healthy else "inactive") }} {% if global_stat %} {% if global_stat.config_last_reload_success is not none %} {{ stat_tile("Config", "OK" if global_stat.config_last_reload_success == 1.0 else "Reload failed", state="up" if global_stat.config_last_reload_success == 1.0 else "crit", hint=(global_stat.config_reloads_total|int ~ " reloads") if global_stat.config_reloads_total is not none else none) }} {% endif %} {% if global_stat.open_conns_total is not none %}{{ stat_tile("Open connections", global_stat.open_conns_total|int) }}{% endif %} {% if global_stat.process_memory_bytes is not none %}{{ stat_tile("Memory", global_stat.process_memory_bytes|bytes) }}{% endif %} {% endif %}
{% macro router_card(r) %}
{{ status_badge(r.state, "Failing" if r.state == 'crit' else "Warning") }}

{{ r.name }}

{{ r.why }}

Req/s{{ "%.2f"|format(r.latest.request_rate) }}{{ r.sparkline_req|safe }}
Bandwidth{{ r.latest.response_bytes_rate|rate }}
p95{{ "%.0f"|format(r.latest.latency_p95_ms) }} ms{{ r.sparkline_p95|safe }}
p99{{ "%.0f"|format(r.latest.latency_p99_ms) }} ms
4xx{{ "%.1f"|format(r.latest.error_rate_4xx_pct) }}%
5xx{{ "%.1f"|format(r.latest.error_rate_5xx_pct) }}%{{ r.sparkline_5xx|safe }}
Last scraped {{ r.latest.scraped_at|ago }}
{% endmacro %} {% if problems or healthy or gone or certs or old_certs %} {# ── Routers that need attention ─────────────────────────────────────────── #} {% if problems %}
{% for r in problems %}{{ router_card(r) }}{% endfor %}
{% endif %} {# ── Healthy routers, folded ─────────────────────────────────────────────── #} {% if healthy %}
{{ healthy|length }} healthy router{{ 's' if healthy|length != 1 }}
{% for r in healthy %} {% endfor %}
RouterReq/sBandwidthp954xx5xx
{{ r.name }} {{ "%.2f"|format(r.latest.request_rate) }} {{ r.latest.response_bytes_rate|rate }} {{ "%.0f"|format(r.latest.latency_p95_ms) }} ms {{ "%.1f"|format(r.latest.error_rate_4xx_pct) }}% {{ "%.1f"|format(r.latest.error_rate_5xx_pct) }}%
{% endif %} {# ── Routers Traefik no longer reports: their last numbers are history, not a state, so they are listed by when they were last seen and nothing else. ── #} {% if gone %}
{{ gone|length }} router{{ 's' if gone|length != 1 }} no longer reported

Traefik stopped reporting these, usually because the service behind them was removed.

{% endif %} {% if healthy %} {% endif %} {# ── Certificates Traefik still serves, soonest expiry first; then the ones it no longer reports (renewed or retired), kept here but off the dashboard (#5254). #} {% if certs or old_certs %}
TLS certificates
{% if certs %} {% for cert in certs %} {% endfor %}
NameRoutersExpiresLeft
{{ cert.cn }}{% if cert.sans %}
also {{ cert.sans|join(", ") }}
{% endif %}
{% if cert.routers is none %}—{% elif cert.routers %}{{ cert.routers|join(", ") }}{% else %}not in use{% endif %} {{ cert.not_after.strftime("%Y-%m-%d") }} {{ cert_left(cert.days_remaining) }}
{% endif %} {% if old_certs %}
No longer served ({{ old_certs|length }}) — renewed or retired; Traefik stopped reporting them {% for cert in old_certs %} {% endfor %}
NameExpires
{{ cert.cn }} {{ cert.not_after.strftime("%Y-%m-%d") }}
{% endif %}
{% endif %} {% else %}

No Traefik metrics yet. Configure metrics_url in config.yaml under plugins.traefik.

{% endif %}