I've created a rule so fail2ban catches incorrect WordPress login attempts, and subsequently bans the IP; /etc/fail2ban/filter.d/wp-auth.conf Code: # WordPress brute force auth filter: /etc/fail2ban/filter.d/wp-auth.conf: # # Block IPs trying to auth wp wordpress # # Matches e.g. # 94.75.208.136 - - [25/Nov/2014:17:41:07 +0000] "POST /wp-login.php HTTP/1.0" 302 381 "-" "-" # [Definition] failregex = ^<HOST> .* "POST /wp-login.php ignoreregex = /etc/fail2ban/jail.conf Code: [wp-auth] enabled = true filter = wp-auth action = iptables-multiport[name=NoAuthFailures, port="http,https"] logpath = /var/www/*/log/access.log bantime = 1800 maxretry = 8 As you can see, I've added a wildcard into the logpath, so it looks at all site access.log files. However, certain sites are missing an access.log (ie, phpMyAdmin), so fail2ban stops searching logs with; Code: 2014-11-26 11:21:06,094 fail2ban.filter : INFO Added logfile = /var/www/domain1/log/access.log 2014-11-26 11:21:06,095 fail2ban.filter : INFO Added logfile = /var/www/domain2/log/access.log 2014-11-26 11:21:06,101 fail2ban.filter : INFO Added logfile = /var/www/domain3/log/access.log 2014-11-26 11:21:06,102 fail2ban.comm : WARNING Invalid command: ['set', 'wp-auth', 'addlogpath', '/var/www/phpmyadminbdomain/log/access.log'] Is there any way of setting it so fail2ban skips missing logs, rather than halting the scan?
Thanks till, but still the same issue. It seems to be sites that aren't accessed very often, don't have an access.log; Code: drwxr-xr-x 2 web38 client9 4096 2013-12-20 00:30 . drwxr-xr-x 34 root root 4096 2014-11-18 23:01 .. lrwxrwxrwx 1 root root 19 2013-11-20 06:15 access.log -> 20131120-access.log -rw-r--r-- 1 root root 223862 2013-11-17 23:12 error.log -rw-r--r-- 1 root root 25719 2013-11-21 00:30 webalizer.conf
I didn't really solve it. I kept meaning to create a cron that would 'touch' the access.log files for each site, which would then create the actual symlinked file. Basically it just needs a script to loop through all the sites in '/var/log/ispconfig/httpd/'... Code: touch /var/log/ispconfig/httpd/site1.com/access.log touch /var/log/ispconfig/httpd/site2.com/access.log touch /var/log/ispconfig/httpd/site3.com/access.log
Will be interested to see what solution you come up with. @till is it possible to change the logrotate to create / touch the file on rotation?
There is no logrotate job running. The file gets createdy by the script that wites the log files, so if there is no access to the website, no new file gets created.
Ok, I haven't looked into it too much. What rotates the logs then? Is it Apache itself? Or an ISPConfig script?
logrotate ( http://linux.die.net/man/8/logrotate ) rotates and gzips the files. I am not sure what creates the symlink.
Something like this should do the job, and make sure the access.log symlink files are created; Code: for site in /var/log/ispconfig/httpd/*; do [ -d $f ] && touch "$site"/access.log && echo Touched $site/access.log done; The logs rotate at 00:30, so running the above at a minute or so after that should be good.
@olimortimer your touching solution is probably the easiest. till's wgetting all the sites would not work for me, because some webistes/clients have expired/misconfigured domains.
also what bothers me a little is that we are feeding all logs to fail2ban, but what we need is only the WP logs. solution would be creating parallel log structure symlinking only WP sites. itterate through websites and if it has wp-admin or something in the webroot, create a symlink to logs from somewhere.
@olimortimer I may have mislead you with logrotate. I think ISPconfig rotates the logs. see /usr/local/ispconfig/server/cron_daily.php
You can get a fail2ban plugin for WP, so it only logs what fail2ban needs to see. However, most of the WP installs on my server are client sites, so I don't want to require them to have a plugin installed etc. Grabbing all the logs allows me to keep a tight control on access attempts. Note if you're using Cloudflare, you will need to use mod_cloudflare to log the real visitor IP to access.log, then send the IP to the Cloudflare API to block / unblock the IP on your Cloudflare account. /etc/fail2ban/jail.local Code: [wp-auth] enabled = true filter = wp-auth action = iptables-multiport[name=wp-auth, port="http,https"] cloudflare-api logpath = /var/log/ispconfig/httpd/*/access.log maxretry = 3 /etc/fail2ban/filter.d/wp-auth.conf Code: [Definition] failregex = ^<HOST> .* "POST /wp-login.php ignoreregex = /etc/fail2ban/action.d/cloudflare-api.local Code: [Definition] actionban = curl https://www.cloudflare.com/api_json.html -d 'a=ban' -d 'tkn=YOURTOKEN' -d 'email=YOUREMAIL' -d 'key=<ip>' actionunban = curl https://www.cloudflare.com/api_json.html -d 'a=nul' -d 'tkn=YOURTOKEN' -d 'email=YOUREMAIL' -d 'key=<ip>'
@olimortimer thanks for that info. for now I will just use your solution with touching the access.log