Analytics cookies only (Google Analytics, PostHog). No ad networks, no cross-site tracking. See our privacy policy.
Self-host CrowdSec
updated Oct 2026deployed by usprices checked · Jul 2026Install verified on Ubuntu 26.04 · Oct 2026 · how we test
We earn commissions when you shop through the links below. Full disclosure →
An open-source intrusion-prevention engine that parses your server and application logs, detects brute force, scanning and other abusive behaviour with shared scenarios from its hub, and bans the offending IPs through separate 'bouncer' components for your firewall, reverse proxy or CDN. Every instance also pulls a community blocklist built from signals shared by other installs. The agent is MIT-licensed Go and runs as a single container with a SQLite database; it has no web UI of its own.
Runs on a VPS from $4/mo (Kamatera 1GB, 1 GB RAM) · prices checked Sep 2026
Our recommendation
Pick CrowdSec when you want the server behind your reverse proxy to notice brute force, scanning and other abuse in its own logs and ban the source, with the bonus of a community blocklist built from what other installs have seen. It is an MIT-licensed Go agent: parsers and scenarios come from its hub as collections, detections are stored in a local SQLite database behind a Local API, and the actual blocking is done by separate bouncers for your firewall, reverse proxy or CDN. Our snippet runs the one agent container with the sshd collection, reading the host's log directory read-only, and persists the config and data volumes the image requires. Upstream publishes no RAM minimum, so our 256 MB floor is an estimate; the agent is small. It is not a replacement for the catalog's Caddy, Traefik or Nginx Proxy Manager, it sits beside them: the proxy's access log is the next thing you feed it, and a bouncer on the proxy or the firewall is what turns a detection into a block.
What you need
Any VPS with at least 256 MB of RAM
A domain you control — most self-hosted setups need HTTPS in front of them
About an afternoon — budget time for troubleshooting
Paid link — we earn a commission if you shop through it.
Install
Run these commands on your server:
# CrowdSec — single-container agent + Local API, reading the host's auth log over a read-only mount — based on the image README on Docker Hub, pinned to v1.8.1mkdir -p acquis.dcat > acquis.d/ssh.yaml <<'EOF'filenames: - /logs/auth.log - /logs/sysloglabels: type: syslogEOFcat > docker-compose.yml <<'EOF'services: crowdsec: image: crowdsecurity/crowdsec:v1.8.1 restart: unless-stopped environment: COLLECTIONS: "crowdsecurity/sshd" ports: - 8080:8080 - 6060:6060 volumes: - crowdsec-config:/etc/crowdsec - ./acquis.d:/etc/crowdsec/acquis.d - crowdsec-data:/var/lib/crowdsec/data - /var/log:/logs:rovolumes: crowdsec-config: crowdsec-data:EOFdocker compose up -d# no web UI: wait for the Local API, then confirm the agent registered and the sshd collection is installedtimeout 180 bash -c 'until docker compose exec -T crowdsec cscli lapi status >/dev/null 2>&1; do sleep 5; done'docker compose exec -T crowdsec cscli collections list# bans only take effect once a bouncer (firewall, Caddy, Traefik, Nginx, Cloudflare…) is paired via: docker compose exec crowdsec cscli bouncers add my-bouncer
CrowdSec's Docker docs and example compose file set out what the agent does and does not do on its own:
non-negotiableThe agent only detects. Nothing is blocked until you install a bouncer (firewall, reverse proxy or CDN) and register it against the Local API with cscli bouncers add or a BOUNCER_KEY_<name> variable. There is also no web UI: cscli inside the container is the local view, and the hosted CrowdSec Console (enrolled with ENROLL_KEY) is the dashboard. Signal sharing with the central API is on unless you set DISABLE_ONLINE_API.
non-negotiableCurrent images refuse to start unless /var/lib/crowdsec/data is mounted, and upstream strongly suggests named volumes or bind mounts for both it and /etc/crowdsec, which holds the Local API credentials and the bouncer keys; lose that volume and every bouncer has to be re-registered. Our snippet persists both.
non-negotiablePin the {version} tag, which upstream calls the release recommended for production. slim drops the notifier plugins and the GeoIP database; the -debian flavour is the one that can read journald, which matters on a host that logs only to the journal. Collections are installed from the COLLECTIONS variable at start, so a new log source means editing the compose file and acquis.d, not just dropping a file in.
non-negotiableThe Local API is plain HTTP on port 8080. Upstream's example compose binds it to 127.0.0.1 and says exposing it to other hosts is at your own risk; our snippet publishes it on all interfaces so a reader can check /health, so change the port mapping to 127.0.0.1:8080:8080 unless remote bouncers need it, or turn on USE_TLS with the LAPI_CERT_FILE/LAPI_KEY_FILE variables. Port 6060 serves Prometheus metrics with no auth.