# Fail2Ban filter: WordPress probe / brute-force scanning in Apache's # vhost_combined access log. # # Install as: /etc/fail2ban/filter.d/apache-vhost-wp-probe.conf # # Expected log line (Apache "vhost_combined" LogFormat, which is what # other_vhosts_access.log uses): # # [13/Sep/2026:02:48:46 -0500] wolfstream.com:443 62.60.130.27 - - "GET /wp-admin/index.php HTTP/1.1" 403 3239 "https://wolfstream.com/wp-login.php" "Mozilla/5.0 ..." # |<------ stripped by datepattern ------>| |vhost:port| || |u||i| # # NOTE: fail2ban removes the timestamp it matched from the line *before* # applying failregex. Any failregex that starts with ^\[...\] therefore can # never match this log - that is the bug in the commonly-posted version of # this filter. [Definition] # Anchor and consume the whole bracketed timestamp, so the line handed to # failregex begins at the vhost field. datepattern = ^\[%%d/%%b/%%Y:%%H:%%M:%%S %%z\] # Only error responses (4xx/5xx) count as a failure. A real administrator # logging in gets 200/302 and is never banned; an unauthenticated visitor # hitting /wp-admin/ gets a 302 redirect and is never banned. Direct # requests for a .php file under wp-content/ or wp-includes/ are the # plugin/theme vulnerability scan pattern - legitimate assets there are # .css/.js/images, not .php. failregex = ^\s*\S+ \S+ \S+ "(?:GET|POST|HEAD) /+(?:wp-login\.php|wp-admin/|xmlrpc\.php|wp-config\.php|wp-(?:content|includes)/[^"]*\.php)[^"]*" (?:4\d\d|5\d\d) \d+ ignoreregex =