2026-05-17 15:38:10 +00:00
2026-05-17 15:38:10 +00:00
2026-05-17 15:38:10 +00:00
2026-05-17 04:54:34 +00:00
2026-05-17 08:28:16 +00:00
2026-05-17 08:28:16 +00:00
2026-05-17 04:54:34 +00:00
2026-05-17 15:38:10 +00:00
2026-05-17 08:28:16 +00:00
2026-05-17 08:28:16 +00:00
2026-05-17 08:28:16 +00:00
2026-05-17 08:28:16 +00:00
2026-05-17 08:28:16 +00:00
2026-05-17 04:54:34 +00:00
2026-05-17 08:28:16 +00:00

CrowdSec UI

A lightweight, dependency-free web dashboard for monitoring and managing CrowdSec.

Stack: Go 1.26 · html/template · Tailwind CSS (CDN) · Zero external Go packages


Features

Feature Transport Requires
Decisions (list, add, delete) LAPI REST Machine credentials
Alerts (list, delete) LAPI REST Machine credentials
Live dashboard stats LAPI REST (polled) Machine credentials
Bouncers (list, add, delete) cscli exec cscli binary
Machines (list, validate, delete) cscli exec cscli binary
Hub (collections/parsers/scenarios) cscli exec cscli binary
Metrics cscli exec cscli binary

All cscli-backed features degrade gracefully with a banner if the binary is unavailable.


Quick Start

1. Register the UI as a CrowdSec machine

# On the host running CrowdSec:
sudo cscli machines add crowdsec-dashy --password your-password -a -f /etc/crowdsec/dashy_credentials.yaml

# Or if CrowdSec is in Docker:
docker exec crowdsec cscli machines add crowdsec-dashy --password your-password -a -f /etc/crowdsec/dashy_credentials.yaml

2. Configure environment variables

Copy or edit docker-compose.yml and set:

CROWDSEC_API_LOGIN: "crowdsec-dashy"
CROWDSEC_API_PASSWORD: "your-password"     # must match step 1
UI_USERNAME: "admin"
UI_PASSWORD: "your-ui-password"            # Basic Auth for the web UI
UI_SESSION_SECRET: "32-char-random-string"

3. Set up cscli bind-mount (for CLI features)

# If CrowdSec is in Docker, extract cscli:
docker cp crowdsec:/usr/local/bin/cscli /usr/local/bin/cscli
chmod +x /usr/local/bin/cscli

# The docker-compose.yml already bind-mounts it:
# - /usr/local/bin/cscli:/usr/local/bin/cscli:ro

4. Launch

docker compose up -d

Open http://localhost:8080 — browser will prompt for Basic Auth.


Running Directly (no Docker)

# Build
go build -o crowdsec-dashy ./cmd/server

# Set env vars
export CROWDSEC_API_URL="http://localhost:8080"
export CROWDSEC_API_LOGIN="crowdsec-dashy"
export CROWDSEC_API_PASSWORD="your-password"
export UI_USERNAME="admin"
export UI_PASSWORD="your-ui-password"
export UI_SESSION_SECRET="32-char-random-string"

# Run
./crowdsec-dashy

Environment Variables

Variable Default Description
PORT :8080 Listen address
CROWDSEC_API_URL http://localhost:8080 CrowdSec LAPI base URL
CROWDSEC_API_LOGIN (required) Machine login (cscli machines add)
CROWDSEC_API_PASSWORD (required) Machine password
CSCLI_PATH /usr/local/bin/cscli Path to cscli binary
UI_USERNAME admin Basic Auth username
UI_PASSWORD changeme Basic Auth password — change this
UI_SESSION_SECRET (required, ≥32 chars) HMAC signing key
POLL_INTERVAL_SEC 15 Dashboard live-poll interval

Project Structure

crowdsec-dashy/
├── cmd/server/main.go              entrypoint
├── internal/
│   ├── config/config.go            env-var loading
│   ├── crowdsec/
│   │   ├── types.go                all shared structs
│   │   ├── lapi.go                 REST client (decisions, alerts)
│   │   └── cli.go                  cscli exec wrapper
│   ├── handlers/
│   │   ├── renderer.go             template engine + PageData
│   │   ├── dashboard.go
│   │   ├── decisions.go
│   │   ├── alerts.go
│   │   ├── bouncers.go
│   │   ├── machines.go
│   │   ├── hub.go
│   │   ├── metrics.go
│   │   └── api.go                  JSON API for dashboard polling
│   ├── middleware/middleware.go     BasicAuth, Logger, SecureHeaders, Recovery
│   └── router/router.go            route wiring
└── web/
    ├── templates/layouts/base.html sidebar shell
    ├── templates/pages/            one file per page
    └── static/css/app.css          all component styles
        static/js/app.js            global JS
        static/js/dashboard.js      stats polling

Adding a New Page

  1. Create internal/handlers/mypage.go with a handler struct
  2. Create web/templates/pages/mypage.html starting with {{template "base" .}}
  3. Add to SidebarNav in renderer.go
  4. Add mux.Handle("/mypage", handlers.NewMyPageHandler(deps)) in router.go

Security Notes

  • All routes protected by HTTP Basic Auth — put behind TLS (nginx/Caddy) in production
  • cscli args passed as a slice (never through a shell); strict allow-list of subcommands
  • LAPI JWT stored in memory only, never logged
  • Generated bouncer API keys shown exactly once, never stored by the UI
  • Security headers on every response: CSP, X-Frame-Options, X-Content-Type-Options
  • Server has explicit Read/Write/Idle timeouts

Dependencies

Go: zero external packages — stdlib only. Frontend: Tailwind CSS via CDN (CSS only, no JS framework), Google Fonts via CDN.

S
Description
No description provided
Readme AGPL-3.0 30 MiB
Languages
Go 56.6%
HTML 29.4%
CSS 9.8%
JavaScript 3.6%
Dockerfile 0.6%