Skip to content

# CrowdSec Manager & Security Configuration

This page covers the CrowdSec Manager web UI on the Pangolin server, protected behind Tinyauth authentication, along with tuning of CrowdSec security rules and enabling Cloudflare Turnstile captcha for the CrowdSec bouncer.

## Architecture

    graph LR
        User -->|HTTPS| Traefik
        Traefik -->|forwardAuth| Tinyauth
        Tinyauth -->|authenticated| Traefik
        Traefik -->|proxy| CrowdSec-Manager
        CrowdSec-Manager -->|API| CrowdSec
        Traefik -->|bouncer plugin| CrowdSec
        CrowdSec -->|captcha decision| Turnstile[Cloudflare Turnstile]

All services run on the same Docker Compose stack and share the `pangolin` network. Traefik reaches them through Gerbil's network namespace.

## Components Added

### CrowdSec Manager

Image: `hhftechnology/crowdsec-manager:1.1.0`

A web UI for managing CrowdSec operations — viewing alerts, decisions, managing bouncers, and configuring scenarios. It has read-only access to Traefik and CrowdSec configs and read-write access to its own data and backups.

Accessible at: `https://crowdsec.bnkserve.org`

### Tinyauth

Image: `ghcr.io/steveiliop56/tinyauth:v4`

A lightweight forward-auth middleware that protects the CrowdSec Manager dashboard with a login screen. Traefik's `forwardAuth` middleware checks every request to the manager against Tinyauth before allowing access.

Login page at: `https://auth.bnkserve.org`

User credentials are stored in a users file (`/data/users`) mounted from the host, using bcrypt-hashed passwords.

Special Characters in Passwords

Tinyauth v4 has a known issue where special characters (`@`, `!`, etc.) in passwords can cause login failures through the browser, even though the bcrypt hash verifies correctly via the CLI. Use alphanumeric passwords to avoid this.

## Traefik Routing

### Routers

Router | Domain | Middleware | Purpose
--- | --- | --- | ---
`crowdsec-manager-router` | `crowdsec.bnkserve.org` | `security-headers`, `tinyauth` | Dashboard (HTTPS)
`crowdsec-manager-redirect` | `crowdsec.bnkserve.org` | `redirect-to-https` | HTTP → HTTPS redirect
`tinyauth-router` | `auth.bnkserve.org` | `security-headers` | Auth login page (HTTPS)
`tinyauth-redirect` | `auth.bnkserve.org` | `redirect-to-https` | HTTP → HTTPS redirect

No tinyauth middleware on the tinyauth router

The `tinyauth-router` must not have the `tinyauth` forwardAuth middleware applied — this would create an infinite redirect loop.

### Middleware

The `tinyauth` forwardAuth middleware forwards every request to `http://tinyauth:3000/api/auth/traefik`. If the user has a valid session cookie (scoped to `.bnkserve.org`), the request passes through. Otherwise, the user is redirected to the Tinyauth login page.

    tinyauth:
      forwardAuth:
        address: http://tinyauth:3000/api/auth/traefik
        trustForwardHeader: true
        authResponseHeaders:
          - X-Forwarded-User

## CrowdSec Tuning

### Relaxed Crawl Detection

The `crowdsecurity/http-crawl-non_statics` scenario was triggering on legitimate Canadian users browsing the site. The local override at `/etc/crowdsec/scenarios/http-crawl-non_statics.yaml` (replacing the hub symlink) has relaxed thresholds:

Parameter | Before | After | Effect
--- | --- | --- | ---
`capacity` | 40 | 80 | Twice as many distinct pages before triggering
`leakspeed` | 0.5s | 0.25s | Bucket drains twice as fast

Combined effect: 4x more lenient — a user must hit 80+ distinct non-static pages faster than 1 every 0.25 seconds to trigger a captcha.

### Canadian ISP Whitelist

A whitelist expression in `/etc/crowdsec/parsers/s02-enrich/mywhitelists.yaml` exempts traffic from major Canadian ISPs from all CrowdSec scenarios:

    expression:
      - evt.Meta.ASNNumber in ['812', '852', '6327', '5645', '20365', '25668', '577']

AS Number | ISP
--- | ---
812 | Rogers Communications
852 | TELUS Communications
6327 | Shaw Communications
5645 | TekSavvy
20365 | Freedom Mobile
25668 | CipherKey
577 | Bell Canada

Field name

The GeoIP enricher populates `evt.Meta.ASNNumber` (not `ASNumber`). This can be verified by inspecting `/etc/crowdsec/parsers/s02-enrich/geoip-enrich.yaml`.

## Cloudflare Turnstile Captcha

Previously, CrowdSec captcha decisions resulted in a hard 403 block because no captcha provider was configured. Now, users with a captcha decision see a Cloudflare Turnstile challenge page and can proceed after solving it.

Configuration added to the CrowdSec bouncer plugin in `dynamic_config.yml`:

    captchaProvider: turnstile
    captchaSiteKey: <site-key>
    captchaSecretKey: <secret-key>
    captchaHTMLFilePath: /etc/traefik/captcha.html

Captcha HTML template path

The `captcha.html` template is copied from the plugin source to `/etc/traefik/captcha.html` (the mounted config volume). Do not reference the `/plugins-storage/` path directly — the hash in that path changes on every Traefik restart.

## DNS Records

Two A records pointing to `72.11.155.21`:

Record | Purpose
--- | ---
`crowdsec.bnkserve.org` | CrowdSec Manager dashboard
`auth.bnkserve.org` | Tinyauth login page

## Verification

    # Check containers are running and healthy
    docker ps --filter name=crowdsec-manager --filter name=tinyauth

    # Check both are on the pangolin network
    docker network inspect pangolin --format '{{range .Containers}}{{.Name}} {{end}}'

    # Verify no Canadian ISPs in active decisions
    docker exec crowdsec cscli decisions list | grep "CA"

    # Check CrowdSec whitelist is loaded
    docker exec crowdsec cscli parsers inspect mywhitelists

    # Check Traefik logs for captcha errors
    docker logs traefik 2>&1 | grep -i captcha