GitHub

Dashboard

Open http://localhost:8080 in a browser running on the Kapkan host. When you are under attack, look first at the Live mode banner (is Kapkan actually announcing, or only watching?) and the Active attacks list (what is being hit, and how hard).

The web UI is built into the kapkan binary itself, so there is nothing extra to install or deploy — the same process serves the dashboard, the JSON API and Prometheus metrics.

iOne binary, one listener

The dashboard, the JSON API and /metrics are all served by the same process on the same address. There is no separate web service to deploy or keep in sync.

Where it lives

The dashboard is served at / on the same address as the REST API — the api.listen value from your config. With the default of 127.0.0.1:8080, you open it at http://localhost:8080.

Because the default binds 127.0.0.1, the dashboard is reachable only from the Kapkan host itself — opening localhost:8080 on your own laptop will show nothing. To view it from your workstation, forward the port over SSH rather than rebinding api.listen to a public address:

ssh -L 8080:127.0.0.1:8080 user@kapkan-host

Then open http://localhost:8080 on your workstation. (Rebinding the listener to a public address needs an API token first — see the Authentication caveat below.)

To serve only the JSON API and metrics without the UI, disable it:

api:
  listen: "127.0.0.1:8080"
  dashboard: false   # serve the JSON API and /metrics only

With api.dashboard: false, the /api/v1 endpoints and /metrics keep working — only the embedded UI shell stops being served.

What it shows

The dashboard polls the JSON API and renders everything Kapkan tracks in memory:

  • Live mode — whether the instance is running in dry-run or live, so you can see at a glance whether a detected attack would actually be announced.
  • Active and recent attacks — currently firing attacks plus the recently ended ones, each with its classification of the attack type (for example, NTP/DNS amplification or a SYN flood — see the Detection page for what each type means) and the dominant sources, ports and protocols captured from the flow samples.
  • Top talkers — the tracked-host snapshot with per-direction rates and learned baselines, so you can see who is loudest and how it compares to normal.
  • Hostgroups — your named prefix groups and their state.
  • Scrubbing nodes — shown only when you run managed scrubbing nodes: each node's liveness (it is alive because it keeps polling for rules), how many bans divert to it, and its own reported load, drops, version and dry-run flag — the reported columns are labelled as such, because a node's self-report is advisory, never the source of its liveness.
  • Ban table — every ban, active and historical (with the scrubbing node column when nodes are configured).
  • Traffic / Reports — live ingress/egress charts built from the in-memory rate buffers, plus a Historical reports section that reads the persisted ClickHouse tables when storage is enabled.
  • Controls — the same actions the API offers: manual ban / unban of an address and config reload (the equivalent of sending SIGHUP).

The Historical reports section on the Traffic / Reports view is the one part that needs storage: it is populated only when ClickHouse storage is enabled, and otherwise renders a labeled placeholder explaining how to turn it on.

No database required

The dashboard is built entirely from the engine's in-memory state. Historical flow storage is a separate, optional feature — it is not needed to see live attacks, top talkers or bans.

Attack detail

Click an attack in the Active and recent attacks list to open its detail drawer. Alongside the classification, the "why it fired" breakdown, the escalation ladder and the mitigation route, two sections attribute the traffic:

  • Captured sample — the dominant Top sources (relabeled Top destinations for an outgoing attack), Protocols and Top source / dest ports distilled from the flow sample, plus the total packets sampled. With GeoIP enabled it also shows a Top ASNs row (Top dest ASNs for outgoing attacks): the busiest autonomous systems by sampling-corrected packets, listed as AS<number> <organization>.
  • Raw flows — a table of individual captured flows (source, protocol, destination, flags, fragmentation, packets). With a country database loaded, each source carries a small country-code badge such as US or DE; hover it to see the source's network organization.

The Top ASNs row and the per-flow country badges appear only when GeoIP attribution is enabled. Point geoip.asn_database at a MaxMind GeoLite2/GeoIP2 ASN database for the ASNs and organization names, and geoip.country_database at a country database for the country badges — see the geoip block in Configuration. Without them the drawer still renders, just without the ASN row and country tags.

Authentication

By default the API and dashboard are unauthenticated, which is safe only because the default api.listen binds to 127.0.0.1. When you set an API token, the dashboard adapts: the static UI shell still loads, but the data behind it does not until you supply the token.

When auth is enabled, the dashboard prompts for the token and keeps it in the browser's sessionStorage, attaching it as a bearer header on every API request it makes. Each /api/v1 request is authorized with Authorization: Bearer <token>; /metrics and the static shell stay open, but the live data and the ban / reload controls do not.

!Set a token before exposing the listener

Before binding api.listen to anything beyond 127.0.0.1, configure an API token. See Authentication for how to set api.token_env and how requests are verified.

  • REST API — the endpoints the dashboard polls and the control actions it calls.
  • Authentication — how to protect the API and dashboard with a token.