v2.2.5 Source Available Go Linux/FreeBSD Daemon/Docker/K8s

From a single VPS
to a distributed fleet —
one binary, zero overhead

Distributed security event processing engine for any HTTP server — and far beyond

A smart, universal, distributed security engine: behavioural detection instead of static rules, any log source in, any destination out, any language for your own plugins. Scale from a single VPS to a distributed fleet — collect events on one machine, score them on another, ban on a third — over a built-in encrypted node mesh. Bare-metal, Docker Compose, or Kubernetes DaemonSet.

What "smart, universal, scalable, distributed" means

Smart

Eight behavioural detectors score patterns — probing, rate anomalies, bruteforce ratios, sequential crawling — instead of matching static signatures. Legitimate crawlers are verified via rDNS/fDNS and never scored.

Universal

Any log source in (file, stdin, syslog, HTTP push/pull across 9 vendor formats), any destination out (Fail2Ban, Cloudflare WAF, MikroTik/OpenWrt/OPNsense firewalls, Loki/Splunk/Datadog), any language for your own plugin via exec+JSON.

Scalable

One process handles N independent log streams, each with its own pipeline of sources, detectors, and sinks — from a single nginx vhost to a fleet of edge nodes, without spinning up separate processes per site.

Distributed

Collect on one machine, score on another, ban on a third — over a built-in encrypted QUIC/TLS 1.3 node mesh with Ed25519 identity and TOFU pinning. No message broker, no log shipper, no VPN required.

↓ Install View on GitHub

Every request. Every threat. Any output.

nginx / Apache / Traefik / Caddy / HAProxy / LiteSpeed access.log
Profile (log format · field mapping · server type)
TailReader × N streams (inotify · logrotate-aware)
Parser (ngx_http_realip · CF-Connecting-IP · XFF chain)
Whitelist (IP · CIDR · UA · bot DNS verify)
WAF (rule-engine · pass / drop / tag)
Tracker (per-IP state · ring buffer · rate counters)
Scorer (8 detectors · linear decay)
threats.log / Named Channel Switch
Executor → Fail2Ban · Cloudflare WAF · MikroTik · OpenWrt · OPNsense · nginx blocklist · exec+JSON
8
Behavioural detectors
3
Topologies · bare-metal · Docker · K8s
11
Verified bot families
7
Native outputs · Fail2Ban · CF WAF · MikroTik · OpenWrt · OPNsense · nginx · exec+JSON
5
Architectures · amd64 · arm64 · arm · riscv64 · 386
~16 MB
Single binary · arm64 ready

Any server. Any proxy. Real attacker IP.

Six servers supported natively — nginx works without any config. Every other server enables with a single profile line. Works behind any proxy or Cloudflare — always scores the real attacker, never the CDN or load balancer.

6
Server profiles
1
Line of config
0
Regex to write
Zero config
nginx
default parser

nginx combined log format works out of the box — no profile needed.

One line
Apache
profile: "apache"

Standard CLF — no server-side changes required.

One line
Traefik
profile: "traefik"

Default access log (CLF) — no configuration needed.

One line
LiteSpeed / OpenLiteSpeed
profile: "litespeed"

Apache CLF by default — no server-side changes required.

Plugin
Caddy
profile: "caddy"

Requires xcaddy + transform-encoder plugin for CLF output.

rsyslog
HAProxy
profile: "haproxy-http"

Requires option httplog in haproxy.cfg + rsyslog to write to file.

Behind a proxy? Real IP always reaches the detector.
Cloudflare
Traefik · Caddy · HAProxy · nginx
your server
ArxSentinel
XFF chain unwrapped CF-Connecting-IP ngx_http_realip trusted proxy CIDR real attacker · always

Block known attacks before they reach your detectors

pass — explicit allowlist

Rules evaluated first. A matching pass rule short-circuits the entire pipeline — health checks, internal IPs and known-good bots bypass all further processing with zero overhead.

drop — hard block

SQLi, path traversal, scanner signatures — matched requests are gated out at line rate and never reach the scorer. No state allocated, no detector CPU spent on known-bad traffic.

tag — score and continue

Suspicious but ambiguous traffic gets a label and a score delta, then flows into the regular detection pipeline. Combine WAF signals with behavioural detectors for correlated ban decisions.

Custom fields

Extend the rule namespace with your own http.* fields — two Go changes, no recompilation of core logic. Add TLS version, request body length, or any field your log source exposes.

8 detectors, one score

Each detector adds points to an IP's score. Score decays linearly over the observation window — no false bans from old traffic.

Probe

Requests to sensitive paths: /.env, /.git/config, /.aws/credentials, /wp-config.php, /phpinfo.php, admin panels, backup archives and 30+ others. Active reconnaissance attempts trigger immediately on the first request.

+25 per request

Rate anomaly

More than 100 requests per 60 seconds from a single IP. Catches DDoS probes, aggressive vulnerability scanners, credential stuffing bursts and scraping tools trying to stay under static limits.

+25

Suspicious User-Agent

Case-insensitive substring match against built-in lists: scanners (Nuclei, sqlmap...), grabbers (Scrapy, HTTrack...) and automation clients (python-requests, curl...). Extend via config easily.

+15 to +40

Bruteforce

More than 60% of responses are 404 with at least 10 requests. Typical signature of path-enumeration tools (dirbuster, gobuster, ffuf) blindly traversing wordlists. min_requests prevents false positives.

+30

Sequential crawler

Five or more sequentially numbered URLs in a row — /page/1, /page/2, /article/100... Characteristic of automated content scrapers dumping entire site sections at machine speed.

+20

No-asset bot

Loads pages but requests CSS, JS or images on fewer than 10% of hits — with at least 3 page views. Real browsers fetch resources; markup-only scrapers skip static assets entirely.

+20

URL overflow / WAF bypass

URLs longer than 2048 characters, or containing known WAF evasion keywords: bypass, shell, cmd, eval, exec... Targets buffer overflows and code injections.

+30

Bad Bot Blocklist

Matches User-Agent (and optionally Referer) against a community-maintained blocklist of ~685 known bad bots — scrapers, SEO crawlers, spam bots, vulnerability probes. Updated daily. Powered by nginx-ultimate-bad-bot-blocker by Mitchell Krog.

+60

Legitimate traffic is never banned

Automatic verification

Googlebot, Bingbot, Yandex, DuckDuckBot, GPTBot and 6 others are verified via reverse + forward DNS. Legitimate crawlers are never scored. Fakes get a penalty instead. Trusted crawlers can be matched by User-Agent only (`ua_only`, no DNS) and given per-bot detector exemptions (`exempt_detectors`) so legitimate automation is never penalised.

Custom exclusions

Add your office IPs, VPN subnets (CIDR), monitoring services, SEO tools by User-Agent substring, or URL paths. Changes apply instantly on SIGHUP.

Live reload

All config changes — whitelist, detector scores, thresholds — apply instantly on SIGHUP. No restart. IP state and DNS cache are preserved.

Ban at the layer that fits your stack

Fail2Ban

Write threat events to a log file in the classic Fail2Ban format. No new infrastructure — the default output, and still the fastest path to a working ban on any Linux box.

Cloudflare WAF

Add threat IPs to a Cloudflare IP List and ban them at the network edge — no iptables, no host firewall. Batch operations, async polling, automatic TTL expiry and cross-instance dedup.

nginx

Write banned IPs to a plain blocklist file with TTL auto-expiry and atomic writes. arxsentinel only writes the file; you include it into nginx however suits you. Optional reload command.

MikroTik RouterOS v7

Manage a RouterOS firewall address-list over the REST API. TTL-based auto-unban, safe removal of only arxsentinel-owned entries, works on CHR and ARM-based routers.

OpenWrt ubus firewall

Ban IPs on an OpenWrt router via ubus (uhttpd-mod-ubus) — no SSH, no exec. Batched UCI edit + a single firewall reload per cycle; TTL is owned by the plugin, not left to nftables timeouts.

OPNsense REST API

Ban IPs on an OPNsense firewall via its native REST API (alias_util) — no batching needed, changes apply immediately to the underlying pfctl table. Independent point add/delete per event, active TTL sweep.

Ship straight into the SIEM you already run

Grafana Loki

Push raw and scored events straight into Grafana Loki over the Push API. Stream-label any field (job, severity, stream), batch with gzip, optional mTLS — JSON envelope is recommended for log-platform readability.

Splunk HEC

Forward to a Splunk HTTP Event Collector endpoint with token auth. JSON mode, multi-index, gzip batching, optional mTLS. Events get indexed the moment a verdict crosses the threshold — no separate log shipper required.

Datadog Logs API

Send to Datadog's Logs API v2 over HTTPS — pick the regional intake URL (US, EU, AP1, AP2, UK1, US3, US5, US2 Gov) and tag with arbitrary ddtags. Gzip batching, optional mTLS, works alongside your existing Datadog log pipelines.

Five interfaces. Write yours in any language.

Five typed plugin roles

Source / Sink / Detector / Processor / Executor — each a small Go interface in pkg/plugin/. Plugins register themselves in init(): no central factory list, the framework discovers them by name. Compose the pipeline from roles, not from internal hooks.

Any language, no Go required

The exec+JSON protocol: a subprocess that reads a JSON object per event from stdin and writes a JSON response to stdout. Extend detection, add a sink, write an executor in Python, Bash, or anything that can speak a byte stream — ArxSentinel owns the subprocess lifecycle (spawn, stdin/stdout wiring, shutdown).

Proven, not theoretical

Five shipped executor plugins — Cloudflare, MikroTik, OpenWrt, OPNsense, nginx — and the three observability sinks just added (Loki, Splunk, Datadog) all use the same public plugin interfaces you would. No internal fast path, no privileged access: if it works for the bundled plugins, it works for yours.

One process. Many streams. Independent detection per source.

Multi-stream isolation

One process watches N independent log sources via streams: — each gets its own tracker, scorer, whitelist state, and threat log. A crash or slow scan on one stream never touches another. Backward compatible: a classic single-file config (general.log_file) is silently wrapped into one unnamed stream (stream="" on metrics), no migration needed.

Independent pipelines within a stream

A single stream can define multiple pipelines, each with its own inputs, rule-engine / WAF processors, detectors, and sinks — e.g. one pipeline watching /api/* with a strict WAF gate, another watching /admin/* with different detector thresholds, both inside the same stream config. Prometheus gains a pipeline label on every vector.

Correlate pipelines with tracker_group

Pipelines that share a tracker_group value share one IP-state tracker: an attacker probing your API and your admin panel accumulates one combined score instead of two separate ones, crossing the ban threshold sooner than either pipeline would catch alone. Omit tracker_group (or leave it empty) for full isolation instead.

Fits how you already deploy.

Custom log format

Not using a built-in profile? Define your own regex with named capture groups, or switch to JSON log parsing — both work without recompilation. Any format that captures IP, timestamp, method, path, status and bytes maps to the full detection pipeline.

Server profiles

Ship-ready profiles for popular servers. Override field positions, date formats and delimiter rules per log source without touching core logic.

Docker Compose sidecar

Deploy alongside any containerised HTTP server via a shared log volume — no changes to your app container. Ready-to-use docker-compose.yml and config in deploy/examples/docker/. Prometheus metrics exposed on :9117 for scraping.

Kubernetes DaemonSet

One pod per node reads host access logs via hostPath. Helm chart included with values reference and Prometheus Operator integration. Sidecar topology also supported for managed clusters without host log access.

Offline config validation

Run `arxsentinel validate` to check your whole config before deploy. A topology-aware validator models the real data flow and catches broken wiring using static plugin manifests — no live traffic needed.

Pluggable queue backends

Buffer executor events through an in-memory, file-based (bbolt), Redis — or transport queue that spans machines over the encrypted node mesh. Pick per executor to fit bare-metal, single-host, Kubernetes, or multi-node setups.

Named Channel Switch

Route events between independent pipelines by name — one pipeline detects while another enforces, fully decoupled. And the same named queue can now terminate on a different machine: Distributed NCS.

Collect anywhere. Detect centrally. Ban at the edge.

The same binary becomes a collector, a detector, or a responder — by config alone, connected over a built-in encrypted event mesh. The only tool in its class with node-to-node security event transport inside the engine itself: no message broker, no log shipper, no agent-server hierarchy, no VPN.

Collectors — Pi · VPS · NAS · branch office (12 MB each, parse only)
QUIC / TLS 1.3 · Ed25519 node identity · TOFU pinning (like SSH)
Detector node — 8 detectors · WAF · whitelist · one shared IP score across all sources
Scored verdicts routed onward — per pipeline, to different nodes
Responders → MikroTik router · OpenWrt firewall · OPNsense firewall · nginx blocklist · Cloudflare WAF · Grafana Loki · Splunk HEC · Datadog Logs API (raw + scored JSON)

Encrypted mesh built in

QUIC over one UDP port, TLS 1.3 always on, Ed25519 node keys generated on first start, TOFU fingerprint pinning like SSH. Mutual authentication before a single event flows — a stranger on your port gets nothing.

Cross-service correlation

Every collector forwards into one shared per-IP score. An attacker probing your web tier, API and auth service accumulates one combined score on the detector — and crosses the ban threshold sooner than any single service would catch alone.

Raw or scored — you route both

Forward raw parsed entries inward for central detection, scored verdicts outward for enforcement — or both into your SIEM. Pre-filter at the edge and let threats, not traffic volume, drive your ingest bill.

Proven by CI, not promised

Every documented topology — edge fleet aggregation, mixed routing to nginx + MikroTik/OpenWrt/OPNsense responders — runs as a real multi-container test on every merge. The diagrams in the docs are executable.

Distributed Processing Guide Ready topologies

Works with your stack

Read from any log source. Write threats to any destination. Fail2Ban remains the default — now one option among many.

Inputs

nginx Apache Traefik Caddy HAProxy LiteSpeed any log file stdin pipe syslog receiver HTTP (push/pull)

Outputs

Fail2Ban Cloudflare WAF MikroTik RouterOS OpenWrt ubus OPNsense REST nginx blocklist exec+JSON stdout JSON Grafana Loki Splunk HEC Datadog Telegram (soon)

Example input configs

type: file  ·  path: /var/log/nginx/access.log type: syslog  ·  addr: udp://0.0.0.0:5514  ·  no shared volume type: http  ·  protocol: plain|cloudflare|firehose|pubsub|loki|otlp|azure|splunk|ndjson

protocol: loki and protocol: splunk here mean receiving logs already shaped like Loki's push API or Splunk HEC — unrelated to the Grafana Loki / Splunk HEC outputs listed above, which send events out to those platforms instead.

40+ recipes. Copy. Fill in. Run.

Copy, fill in, run

40+ ready-to-use recipes across 14 categories: every supported server (nginx, Apache, Caddy, Traefik, HAProxy, LiteSpeed), every executor (Cloudflare, MikroTik, OpenWrt, OPNsense), every observability sink (Loki, Splunk, Datadog), CMS-specific probe paths (WordPress, Laravel, Drupal), and more. Browse the index in cookbook/CookBook.md — every row links straight to a working *.yaml.

Docker & Kubernetes included

5 recipe categories ship a full Docker Compose stack — Cloudflare, nginx executor, syslog, MikroTik, Fail2Ban — plus a full Kubernetes directory. Not just the ArxSentinel config, the whole reference deployment.

Distributed topologies, not just single-node

3 full working multi-node Distributed NCS examples in cookbook/distributed-ncs/ — base, edge aggregation, and mixed routing. The same topologies documented in the guide above, proven by real multi-container CI runs on every merge.

~16 MB. Runs anywhere.

~16 MB
Binary size · arm64
~25 MB
RAM · Pi 3B config
>20k
Log lines/sec · Pi 3B
0
Runtime dependencies
Enterprise threats.
Even on Raspberry Pi hardware.
Pure Go binary — no JVM, no Python runtime, no memory bloat. Runs natively on Raspberry Pi 3B (ARM Cortex-A53): ~25 MB RAM, 22k+ log lines/sec — 20× faster than any real Pi workload.

No black box. Deterministic scoring — every ban has a reason you can read in structured JSON logs.
YAML config SIGHUP reload JSON logs Prometheus metrics arm64 native Raspberry Pi 3B ready systemd unit

Install in 3 steps

The package handles everything: binary, systemd unit, Fail2Ban config, and system user.

# Works on Debian, Ubuntu, Fedora, RHEL, AlmaLinux, Rocky Linux, Arch Linux
# Auto-detects your distro and architecture (amd64 / arm64)
curl -fsSL https://raw.githubusercontent.com/mr-addams/arxsentinel/main/scripts/get.sh | sudo bash

The script downloads the correct package from GitHub Releases, installs it with your package manager, checks for fail2ban, auto-detects your access.log path, and starts the service.

# Requires Go 1.26+
git clone https://github.com/mr-addams/arxsentinel
cd arxsentinel
sudo ./scripts/install.sh
sudo systemctl enable --now arxsentinel
# Docker — distroless image (~12 MB), runs as uid 65532, amd64 + arm64
docker run -d \
  -v /var/log/nginx/access.log:/var/log/nginx/access.log:ro \
  -v /var/log/arxsentinel:/var/log/arxsentinel \
  -p 127.0.0.1:9117:9117 \
  ghcr.io/mr-addams/arxsentinel:latest

Prometheus metrics available at :9117/metrics immediately after start. For Docker Compose and Kubernetes (Helm DaemonSet) setup — see the full guides: README.docker.md · Kubernetes (Helm) README

# Native binary — 386 / amd64 / arm / arm64. Dedicated installer + rc.d service.
fetch https://github.com/mr-addams/arxsentinel/releases/latest/download/arxsentinel_<version>_freebsd_<arch>.tar.gz
tar xzf arxsentinel_<version>_freebsd_<arch>.tar.gz
cd arxsentinel_<version>_freebsd_<arch>
sudo sh install.sh
sysrc arxsentinel_enable=YES
service arxsentinel start

Creates the arxsentinel system user, installs the rc.d service, and seeds a config from the bundled example (never overwrites an existing config on re-run). Running your web server under podman on FreeBSD? See the full guide — storage driver, firewall setup, and container networking gotchas: FreeBSD Deployment Cookbook

After installation: open /etc/arxsentinel/config.yaml and set your log path. nginx works without any profile. For Apache, Traefik, Caddy, HAProxy or LiteSpeed — set parser.profile to the server name. Config reloads on SIGHUP — no restart needed.

What's coming in v2.x

NEXT

AWS WAF executor

Push threat IPs directly into AWS WAF IP set rules. Integrates with existing WAF rule groups — no Lambda or custom infrastructure required.

PLANNED

SSH source + detectors

Parse sshd auth logs (syslog/journald) and score brute-force / credential-stuffing patterns with dedicated detectors — the same scoring and executor pipeline you already use for HTTP.

PLANNED

Alert sinks

Push threats to Telegram, Slack and PagerDuty — with built-in deduplication and rate-limiting so a burst never floods your channel.