# aiquila-hetzner — CrowdSec

← [Overview](README.md)

---

## Overview

All three Hetzner stacks run **CrowdSec** (`aiq-crowdsec`) as a network-level intrusion
prevention system. CrowdSec reads Traefik's access logs, detects attack patterns, and
communicates ban decisions to the Traefik bouncer plugin, which enforces them on every
incoming request.

---

## How it works

1. **Traefik writes** JSON access logs to `/logs/access.log` (shared Docker volume).
2. **CrowdSec reads** the log file continuously via the acquisition config.
3. The **`crowdsecurity/traefik` collection** parses each log line and applies detection
   scenarios: SQL injection, XSS, path traversal, scanner fingerprints, brute-force
   patterns, and more.
4. When a scenario matches, CrowdSec stores a **ban decision** (IP address + expiry)
   in its local database.
5. On every request, the **Traefik bouncer plugin** queries
   `http://crowdsec:8080/api/v1/decisions` with the source IP.
6. If the IP is banned, Traefik returns **403** before the request reaches the backend.

---

## Container

| Property | Value |
|----------|-------|
| Image | `crowdsecurity/crowdsec:latest` |
| Container name | `aiq-crowdsec` |
| Memory limit | 512 MiB |
| Memory reservation | 256 MiB |
| Restart policy | `unless-stopped` |

---

## Acquisition config

`crowdsec/acquis.yml` is mounted read-only at `/etc/crowdsec/acquis.d/` inside the
container:

```yaml
# CrowdSec acquisition — reads Traefik JSON access log
filenames:
  - /logs/access.log
labels:
  type: traefik
```

The `type: traefik` label tells CrowdSec which parser to use. The `/logs` path is a
shared Docker volume also written by Traefik.

---

## Collections

The `COLLECTIONS` environment variable controls which detection scenarios are installed
at container startup:

```yaml
environment:
  COLLECTIONS: crowdsecurity/traefik
```

`crowdsecurity/traefik` is a curated collection that includes parsers and scenarios
for Traefik access logs: HTTP scanner detection, common web attack patterns
(SQLi, XSS, path traversal), and Traefik-specific fingerprints.

---

## Bouncer key

`CROWDSEC_BOUNCER_KEY` is a 64-character hex string auto-generated by `aiquila-hetzner`
at provisioning time and stored in `/opt/aiquila/.env`.

The key is registered automatically at container startup via the
`BOUNCER_KEY_traefik` environment variable:

```yaml
environment:
  BOUNCER_KEY_traefik: ${CROWDSEC_BOUNCER_KEY}
```

The Traefik bouncer plugin uses this key to authenticate against the CrowdSec LAPI.

---

## Useful cscli commands

```bash
# List active decisions (bans)
docker compose exec aiq-crowdsec cscli decisions list

# Unban an IP
docker compose exec aiq-crowdsec cscli decisions delete --ip 1.2.3.4

# View alerts
docker compose exec aiq-crowdsec cscli alerts list

# List installed collections
docker compose exec aiq-crowdsec cscli collections list

# Check bouncer status
docker compose exec aiq-crowdsec cscli bouncers list
```

---

## Rotating the bouncer key

Changing `CROWDSEC_BOUNCER_KEY` requires re-registering the key in the CrowdSec local
API — editing `.env` alone is not enough.

See [advanced.md § Variables requiring extra care](advanced.md#variables-requiring-extra-care)
for the full procedure, which covers editing `.env`, running
`cscli bouncers add traefik-bouncer --key <new-key>`, and restarting the stack.

---

## Volumes

| Volume | Purpose |
|--------|---------|
| `crowdsec_db` | Persists decisions and alerts across container restarts; bind-mounted from `/opt/crowdsec` on the host |
| `logs` (shared) | Traefik access log read by CrowdSec; also written by Traefik |
