No description
  • TypeScript 79.1%
  • HTML 20.9%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-09-12 00:26:19 +02:00
cli IPC socket path from config 2026-07-28 19:42:05 +02:00
core adapt matching rules to accept multiple options (array) and regexes 2026-09-10 22:47:07 +02:00
daemon collect metrics and display in dashboard 2026-07-29 23:44:58 +02:00
ipc collect metrics and display in dashboard 2026-07-29 23:44:58 +02:00
server make dashboard port and host configurable 2026-07-30 00:22:59 +02:00
tests fix test output 2026-09-12 00:26:19 +02:00
tools add a log generator for testing locally 2026-07-28 19:20:23 +02:00
.gitignore add a log generator for testing locally 2026-07-28 19:20:23 +02:00
banmachine-server.service add server service file 2026-07-30 00:13:10 +02:00
banmachine.service add server service file 2026-07-30 00:13:10 +02:00
config-example.json adapt matching rules to accept multiple options (array) and regexes 2026-09-10 22:47:07 +02:00
deno.json IPC socket path from config 2026-07-28 19:42:05 +02:00
deno.lock server with dashboard 2026-07-28 20:01:43 +02:00
plan.md add IPC and CLI 2026-06-14 11:59:50 +02:00
README.md adapt matching rules to accept multiple options (array) and regexes 2026-09-10 22:47:07 +02:00
session-ses_1430.md ignore list 2026-06-12 23:50:12 +02:00
specification.md adapt matching rules to accept multiple options (array) and regexes 2026-09-10 22:47:07 +02:00

BanMachine

A lightweight, modern security daemon designed to monitor structured JSON logs (like Caddy) and enforce bans via nftables.

Features

  • JSON-First: Native support for structured logs.
  • Sliding Window: Intelligent rate limiting.
  • Persistent: State saved in SQLite.
  • Non-Root: Designed to run with minimal capabilities (CAP_NET_ADMIN).
  • IPC Interface: Command-line tool to manage the daemon as a regular user.

Setup Instructions

1. Create System User

Create a dedicated user for BanMachine:

sudo useradd -r -s /usr/sbin/nologin banmachine

2. Prepare Directory

Move the project to a permanent location (e.g., /opt/banmachine) and set permissions:

sudo mkdir -p /opt/banmachine
sudo cp -r . /opt/banmachine
sudo chown -R banmachine:banmachine /opt/banmachine

3. Log & Socket Access

  1. Add the banmachine user to the group that has read access to your logs (usually adm or log):
    sudo usermod -aG adm banmachine
    
  2. To allow your current user to use the CLI, add yourself to the banmachine group:
    sudo usermod -aG banmachine $USER
    
    (Note: You may need to log out and back in for group changes to take effect.)

4. Configuration

Edit /opt/banmachine/config.json to match your log files and rules. Ensure the ipc.socketPath is in a directory writable by the banmachine user (e.g., /tmp/banmachine.sock).

5. Install Systemd Services

  1. Edit banmachine.service and banmachine-server.service and ensure the ExecStart path to deno is correct (which deno).
  2. Copy the service files:
    sudo cp banmachine.service banmachine-server.service /etc/systemd/system/
    sudo systemctl daemon-reload
    sudo systemctl enable banmachine
    sudo systemctl enable banmachine-server
    sudo systemctl start banmachine
    sudo systemctl start banmachine-server
    

6. Viewing Logs

Since BanMachine runs as systemd services, you can view the logs using journalctl:

# Follow daemon logs in real-time
sudo journalctl -u banmachine.service -f

# Follow dashboard logs in real-time
sudo journalctl -u banmachine-server.service -f

Usage

Rule Matching

Rules select log entries via the match object. Each key is a dot-notation path into the JSON log entry, each value is a condition:

"match": {
  "status": [400, 401, 403, 404],
  "request.method": ["GET", "POST", "HEAD"],
  "request.uri": { "$regex": "\\.(php|env|git)$" }
}
  • Plain value (404, "POST"): field equals the value. Types are coerced, so "404" in config matches 404 in the log.
  • Array: matches if the field equals any member (implicit OR). This replaces fail2ban-style alternations like (400|401|403|404).
  • {"$regex": "..."}: field's string value satisfies the pattern (compiled at config load; invalid patterns fail startup).
  • {"$not": <condition>}: negates the inner condition, e.g. {"$not": {"$regex": "^/api/"}}.

A fail2ban rule like ^<HOST> -.*(GET|POST|HEAD).*" (400|401|403|404).*$ translates to:

"match": {
  "status": [400, 401, 403, 404],
  "request.method": ["GET", "POST", "HEAD"]
}

with <HOST> handled by the rule's ipKey.

Command Line Interface

Manage the daemon using the CLI task. You can run this as a regular user if you are in the banmachine group.

# Check status
deno task cli status

# Manually ban an IP
deno task cli ban 1.2.3.4 3600

# Manually unban an IP
deno task cli unban 1.2.3.4

Web Dashboard

If the banmachine-server service is running, the dashboard is available at: http://localhost:8080 (or the port configured in the server).

nftables Verification

To see the rules being created by the daemon:

sudo nft list table inet banmachine

To see currently banned IPs:

sudo nft list set inet banmachine blacklist