The following is the default configuration file of uban v1.0, uban.conf. UBAN (Universal Ban Daemon, Github) is a lightweight, open-source Linux security tool inspired by Fail2ban. It monitors application logs for suspicious activity, automatically blocks offending IP addresses through the system firewall, and increases ban durations for repeat offenders.

# ======================================================================
#         uban ("Universal Ban") - Security Engine Configuration
# ======================================================================
# For technical details, architecture, edge cases, and stress tests:
# https://amzdealshq.com/blog/category/uban/
#
# NOTE ON VERSION SUPPORT:
# uban v1.0 currently supports IPv4 ONLY. All log parsing, positional
# token extraction, and firewall ban tables operate on IPv4 addresses.
#
# GLOBAL PARSING & SYNTAX RULES:
#
# 1. Target strings in 'match_string' MUST be double-quoted (" ").
#    Multiple match strings within the same jail operate as an **OR**
#    relationship and can be separated by commas or spaces.
#    Matching is CASE-INSENSITIVE, but spaces between words matter!
#    Phrases must match exact spacing to keep enforcement lightweight.
#
# 2. Application blocks ([app_name]) feature an 'enabled = true/false'
#    master switch. BOTH the application block AND the individual jail
#    MUST have 'enabled = true' for the jail to evaluate logs.
#
# 3. Jail naming convention MUST follow [app_name-jail_name] (e.g.,
#    [nginx-444] under [nginx] or [sshd-retry] under [sshd]).
#
# 4. Tokenization & Positional Token Extraction Rules:
#    - Tokens are space-delimited. However, any content enclosed within
#      matching delimiters (" ", ( ), [ ], { }, < >) is treated as a
#      SINGLE token, regardless of how many internal spaces it contains.
#    - Token positions (ip_pos / match_pos) are 1-indexed:
#        * Positive values count from the left (e.g., 2 = #2 from left).
#        * Negative values count from the right (e.g., -3 = #3 from right).
#
# 5. Short tokens (<= 5 chars) enforce strict positional checks (#match_pos).
#    Long tokens/phrases (>= 6 chars) still require a 'match_pos' line in
#    the config, but positional enforcement is bypassed to scan flexibly
#    across the entire raw log line.
#
# 6. Ignore IP Evaluation Rules:
#    - 'ignoreip' accepts IPv4 addresses and IPv4 CIDR subnets (space-separated).
#    - Global 'ignoreip' and Jail-level 'ignoreip' operate in an **OR** relationship.
#    - If an incoming IP matches EITHER the [global] ignoreip list OR the jail's
#      local ignoreip list, it is instantly bypassed and never banned.
#
# 7. Escalation & Cap Directives:
#    - banfactor: Multiplier applied to ban_time on repeated offenses (e.g.,
#      Offense 1: base, Offense 2: base * factor, etc.). Set to 1 to enforce
#      a fixed ban duration on every offense.
#    - max_bantime: Maximum cap on calculated ban duration (e.g., 28d, 1y).
#      Set to 0 or any value over 10 years (e.g., 15y, 3660d) to enable
#      permanent bans when the calculated ban_time exceeds 10 years.
#
# COMPILE-TIME SYSTEM LIMITS & CAPACITY:
#
# The limits below are compiled directly into the binary from include/uban.h.
# If your configuration exceeds any of these constraints, simply update the
# corresponding #define in include/uban.h and recompile (make).
#
#   * App / Jail Section Names : 63 chars max  (MAX_NAME_LEN = 64)
#   * Match Pattern Strings    : 127 chars max (MAX_MATCH_LEN = 128)
#   * Ignore IP / Whitelist    : 255 chars max (MAX_IGNOREIP_LEN = 256)
#   * Max Jails Supported      : 32 configured (MAX_JAILS = 32)
#   * Max Apps Tracked         : 16 configured (MAX_APPS = 16)
#   * Max Patterns Per Jail    : 16 keywords   (MAX_MATCH_PATTERNS = 16)
#   * Max Tracked IP State     : 50,000 IPs    (MAX_TRACKED_IPS = 50000)
# ======================================================================

[global]
# Master log file for uban status warnings and operational alerts
log_file = "/var/log/uban/uban.log"

# Default state persistence directory for banfactor calculations
db_dir = "/var/lib/uban"

# Polling interval in ms (10ms = ~1ms-15ms latency, avg ~5ms)
poll_interval_ms = 10

# Global Whitelist: Evaluated across ALL application jails (IPv4 only)
ignoreip = 127.0.0.1/8 100.74.125.235


# ======================================================================
#        PRIMARY: [nginx] - HARDENED LOG SCHEMA (SECURE & NATIVE)       
# ======================================================================
# WHY THIS IS SECURE:
# Moving $status to position #2 places it BEFORE any user-controlled input
# ($request / $http_user_agent). Spammers can inject arbitrary spaces or
# quotes downstream, but because position #2 precedes user payload headers,
# the token index remains structurally resistant to token displacement and
# parsing bypasses.
#
# Recommended Nginx log configuration (/etc/nginx/nginx.conf):
#    log_format uban_format '$remote_addr $status - $remote_user '
#                           '[$time_local] "$request" $body_bytes_sent '
#                           '"$http_referer" "$http_user_agent"';
#    access_log /var/log/nginx/access.log uban_format;
#
# APACHE COMPATIBILITY:
# Apache access logs can follow the exact same hardened positional format:
#    LogFormat "%a %s - %u %t \"%r\" %>s %b \"%{Referer}i\" " \
#              "\"%{User-Agent}i\"" uban_format
#    CustomLog /var/log/apache2/access.log uban_format
#
# IMPORTANT:
# After updating your log_format in Nginx or Apache, you MUST test and reload
# the web server for the new schema to take effect:
#   Nginx:  sudo nginx -t && sudo systemctl reload nginx
#   Apache: sudo apachectl configtest && sudo systemctl reload apache2
# ======================================================================

[nginx]
enabled = true

# Jail 1: Immediate drop for forced connection resets (Direct IP accesses)
[nginx-444]
enabled = true
log_path = "/var/log/nginx/access.log"
# Jail-level ignoreip (Example: Single internal monitoring IP)
ignoreip = 100.75.75.75
ip_pos = 1
match_pos = 2
match_string = "444"
max_retry = 1
find_time = 30s
ban_time = 1d
banfactor = 3
max_bantime = 28d

# Jail 2: Malformed protocol requests, raw TLS probes, or bad client payloads
[nginx-400]
enabled = true
log_path = "/var/log/nginx/access.log"
# Jail-level ignoreip (Example: Commented out for quick sysadmin toggling)
# ignoreip = 192.168.1.0/24 10.0.0.50
ip_pos = 1
match_pos = 2
match_string = "400"
max_retry = 2
find_time = 1m
ban_time = 4h
banfactor = 2
max_bantime = 7d

# Jail 3: Excessive unauthorized / non-existent resource probes
[nginx-403_404]
enabled = true
log_path = "/var/log/nginx/access.log"
# Jail-level ignoreip (Example: Subnet overlapping global list + private range)
ignoreip = 100.74.125.0/24 172.16.0.0/12
ip_pos = 1
match_pos = 2
match_string = "403", "404"
max_retry = 10
find_time = 5m
ban_time = 1h
banfactor = 2
max_bantime = 2d

# Jail 4: For non-wordpress sites. Set to false for wordpress sites
# Probing wordpress dir on a non-wordpress site = spam bots
[nginx-wordpress]
enabled = true
log_path = "/var/log/nginx/access.log"
# Jail-level ignoreip (Example: Local private network subnet)
ignoreip = 10.0.0.0/8
ip_pos = 1
match_pos = 6
match_string = "wp-admin", "wp-content", "wp-includes", "wordpress"
max_retry = 1
find_time = 5
ban_time = 1h
banfactor = 2
max_bantime = 28d

# Jail 5: Safety test sandbox for local verification (Do NOT enable in prod)
# max_bantime does not matter here because of banfactor = 1
[nginx-200_502]
enabled = false
log_path = "/var/log/nginx/access.log"
# Jail-level ignoreip (Example: Whitelisting developer workstation)
ignoreip = 192.168.1.100
ip_pos = 1
match_pos = 2
match_string = "200", "502"
max_retry = 1
find_time = 10
ban_time = 1
banfactor = 1
max_bantime = 28d


# ======================================================================
# WARNING: [nginxDefault] - UNMODIFIED LOG SCHEMA (INSECURE / DO NOT USE)
# ======================================================================
# DO NOT USE THIS IN PRODUCTION.
# Standard logs place $status at position #6, AFTER $request.
# Spammers can inject extra quotes or spaces into their User-Agent or
# Request URI to shift token positions (token injection attack), causing
# the parser to miss position #6 and bypass the firewall completely.
# Always reorder log format to place status at position #2.
# ======================================================================

[nginxDefault]
enabled = false

[nginxDefault-404]
enabled = false
log_path = "/var/log/nginx/access.log"
ip_pos = 1
match_pos = 6
match_string = "404"
max_retry = 1
find_time = 10s
ban_time = 3s
banfactor = 2
max_bantime = 1y


# ======================================================================
#      SECONDARY: [sshd] - HUMAN-READABLE PHRASE MATCHING               
# ======================================================================
# Demonstrates flexible full-line scanning for human-readable keywords
# (phrases >= 6 chars). uban scans the log line for target strings like
# "Failed password" or "Invalid user" while extracting the IP address
# from position -4 (4th token from the right).
# Note: 'match_pos = 6' is present to satisfy syntax requirements, but
# full-line scanning is used automatically due to phrase length.
# ======================================================================

[sshd]
enabled = true

[sshd-retry]
enabled = true
log_path = "/var/log/auth.log"
# Jail-level ignoreip (Example: Whitelisting bastion host and VPN subnet)
ignoreip = 10.8.0.0/24 192.168.1.250
ip_pos = -4
match_pos = 6
match_string = "Failed password", "Invalid user"
max_retry = 3
find_time = 10m
ban_time = 1h
banfactor = 4
max_bantime = 1y