Intrusion blocking for Linux servers β fail2ban, a decade later.
EzyShield watches your server logs, detects attacking IPs, and bans them with escalating penalties: locally via nftables and at the edge via Cloudflare. A deterministic rule engine scores every event offline and always works; AI is consulted only for the ambiguous cases, so decisions stay cheap and the tool runs fully offline if you never configure a provider. It ships as a single static Go binary β no Python, no Java, no runtime to install.
Status: pre-alpha. The pipeline, rule engine, nftables + Cloudflare enforcement, AI providers, and notifiers work today. Run in dry-run (the default) and please report bugs via issues. Interfaces may still change before 1.0.
| fail2ban | EzyShield | |
|---|---|---|
| Bans | local firewall, per-jail bantime | strike-based escalation + local and edge (Cloudflare) |
| Detection | regex filters | rule engine + signatures, optional AI for ambiguous traffic |
| Lockout safety | manual ignoreip |
anti-lockout: your SSH session + admin CIDRs auto-allowlisted before every rule write |
| Default behavior | enforces immediately | dry-run by default β observe before you arm it |
| Runtime | Python | single static binary, no dependencies |
fail2ban is battle-tested and great at what it does β EzyShield aims one layer higher: escalation, edge enforcement, AI-assisted scoring, and guardrails that make it hard to ban yourself. You can even run EzyShield as the brain and keep fail2ban for enforcement.
logs (SSH, Nginx)
β
βΌ
[ Collector ] ββ tail file / journald
β
βΌ
[ Parser ] ββ structured event (IP, method, status, ...)
β
βΌ
[ Enricher ] ββ GeoIP / ASN / reputation
β
βΌ
[ Rule Engine ] ββ offline scoring (always runs)
β
βββ(ambiguous only)βββΆ [ AI Analyzer ] ββ Anthropic / OpenAI-compatible / Ollama
β
βΌ
[ Decision Engine ] ββ strikes + TTL escalation + policy
β
ββββΆ [ Enforcer ] ββ nftables (local) / Cloudflare (edge)
ββββΆ [ Notifier ] ββ Telegram / Email / Slack / Discord / webhook
The whole path from parser to decision is side-effect-free and tested against
fixture logs. Firewall changes only happen through a small privilege-separated
helper (ezyshield-enforcer) that holds CAP_NET_ADMIN and accepts a fixed,
minimal verb set β the main daemon can never run arbitrary firewall commands.
| Strike | Ban duration |
|---|---|
| 1 | 5 minutes |
| 2 | 1 hour |
| 3 | 24 hours |
| 4 | 7 days |
| 5 | permanent |
Strike history is kept forever in SQLite, so a repeat offender from last month still escalates today.
- Escalating bans β short first ban, permanent after repeated offences
- Local enforcement β nftables, via a privilege-separated enforcer helper
- Edge enforcement β push IP bans to a Cloudflare list
- SSH + Nginx parsers with fuzz-tested, panic-safe parsing of hostile input
- Deterministic rule engine β thresholds + scanner signatures; works with zero AI configured
- AI-assisted decisions (optional) β Anthropic, any OpenAI-compatible endpoint, or local Ollama, with provider failover, a token budget, and verdict caching
- Prompt-injection defense β log lines are treated as data, never instructions; AI output is schema-validated and clamped by policy (it can only suggest within limits)
- Anti-lockout β active SSH peer + admin CIDRs auto-allowlisted before any rule write; allowlist always wins
- Dry-run by default β nothing is enforced until you set
armed: true - Ban rate limit β
max_bans_per_minute(default 30) so a bad rule or poisoned feed can't ban the internet - Notifications β Telegram, Email (SMTP), Slack, Discord, generic webhook
- Service & port discovery β
ezyshield scaninventories what's actually listening on the host - Audit trail β every action recorded in SQLite; export to JSON/CSV
- Scriptable β
--jsonon commands; unix-socket control, no TCP port ever
curl -sfL https://get.ezyshield.com | sudo shThe installer fetches the latest signed binaries (ezyshield and
ezyshield-enforcer) and verifies checksums.
git clone https://github.com/evertramos/ezy-shield.git
cd ezy-shield
go build -o ezyshield ./cmd/ezyshield
go build -o ezyshield-enforcer ./cmd/ezyshield-enforcer
sudo mv ezyshield ezyshield-enforcer /usr/local/bin/Requires Go 1.24+ and Linux with nftables for local enforcement.
Then:
sudo ezyshield init # create config under /etc/ezyshield
sudo ezyshield doctor # validate config, permissions, and dependenciesNaming: the binary is
ezyshieldand behaves exactly asezy shieldwould in the widerezytool family βezyshield initβ‘ezy shield init.
# Run the pipeline (dry-run until you set armed: true in policy.yaml)
sudo ezyshield watch
# Inspect the running daemon
ezyshield status
# Manual ban / unban
sudo ezyshield ban 203.0.113.42
sudo ezyshield unban 203.0.113.42
# Permanently allow an IP or CIDR
sudo ezyshield allow 198.51.100.0/24
# See active bans / allowlist / recent events
ezyshield list
# Test a notification channel without waiting for a real event
sudo ezyshield test-notify telegram
# See what's listening on this host
sudo ezyshield scan| File | Purpose |
|---|---|
/etc/ezyshield/config.yaml |
Log sources, enforcement backends, AI providers, notifications |
/etc/ezyshield/policy.yaml |
Score thresholds, strike table, allowlists, rate limits |
/etc/ezyshield/rules.yaml |
Detection rules |
Secrets (API tokens, SMTP passwords) are never stored in YAML β reference
them as env:VARNAME or via systemd LoadCredential=. Inline secret values are
rejected when the config loads, and ezyshield doctor warns on bad file
permissions.
Minimal config.yaml:
data_dir: /var/lib/ezyshield
collectors:
- kind: journald
unit: sshd
- kind: file
path: /var/log/nginx/access.log
enforce:
nftables:
table: inet ezyshield
set: blocked
notify:
telegram:
bot_token: env:EZYSHIELD_TELEGRAM_BOT_TOKEN
chat_ids: ["-1001234567890"]Start in dry-run (armed: false in policy.yaml), watch what it would block,
then arm it. The full setup walkthrough β collectors, AI, notifications, custom
rules β is in docs/QUICKSTART.md.
Built today: SSH/Nginx detection, rule engine, nftables bans, Cloudflare edge (IP lists), Anthropic/OpenAI/Ollama providers, Telegram/Email/Slack/Discord/ webhook notifications, dry-run, anti-lockout, audit log.
Planned (not yet shipped β see issues):
- More edge backends: Bunny, AWS WAF; ASN- and country-level blocking
- More local backends: iptables, ufw, firewalld
- More log sources: Apache, Caddy, Traefik, container logs
- Localhost-only dashboard (SSH-tunneled, like
kubectl proxy) - Community module/plugin system
- Host sensor: reverse-shell and egress-anomaly detection
- Reputation feeds, more notifiers (ntfy, Pushover, WhatsApp/SMS)
EzyShield is a root-capable security daemon and is built accordingly: privilege separation for firewall writes, unix-socket control (no listening TCP port), a localhost-only dashboard plan, anti-lockout, action rate limiting, and secrets kept out of config and logs. Every change goes through a mandatory security review.
Found a vulnerability? Please follow SECURITY.md β do not open a public issue for security reports.
Contributions are welcome. Read CONTRIBUTING.md first; a CLA is required. Every PR ships code + tests + doc updates together, and CI (lint, tests, CodeQL, fuzz, security gates) must be green to merge.
EzyShield is free and open source, and always will be (AGPL-3.0). If it keeps your servers safer, consider sponsoring β it funds focused time to build this in the open, independently.
EzyShield is released under AGPL-3.0 β see LICENSE.