I have protected a web folder with Nginx's Auth_Basic module. The problem is, we can try several passwords until it works (brute force attacks). Is there a way to limit the number of failed re-tries?
Testing with a non-existent user, you will see something like belows in the error log:
2012/08/25 10:07:01 [error] 5866#0: *1 no user/password was provided for basic authentication, client: 127.0.0.1, server: localhost, request: "GET /pma HTTP/1.1", host: "localhost:81"
2012/08/25 10:07:04 [error] 5866#0: *1 user "ajfkla" was not found in "/etc/nginx/htpasswd", client: 127.0.0.1, server: localhost, request: "GET /pma HTTP/1.1", host: "localhost:81"
Then create necessary filter:
[Definition] failregex = no user/password was provided for basic authentication.*client: <HOST> user .* was not found in.*client: <HOST> user .* password mismatch.*client: <HOST> ignoreregex = </host></host></host>
[nginx-auth] enabled = true filter = nginx-auth action = iptables[name=NoAuthFailures, port=80, protocol=tcp] logpath = /var/log/nginx*/*error*.log bantime = 3600 # 1 hour maxretry = 3
Testing Fail2Ban rules:
fail2ban-regex /var/log/nginx/localhost.error_log /etc/fail2ban/filter.d/nginx-auth.conf
Failregex |- Regular expressions: |  no user/password was provided for basic authentication.*client: <HOST> |  user .* was not found in.*client: <HOST> |  user .* password mismatch.*client: <HOST> | `- Number of matches:  1 match(es)  2 match(es)  0 match(es) Ignoreregex |- Regular expressions: | `- Number of matches: Summary ======= Addresses found:  127.0.0.1 (Sat Aug 25 10:07:01 2012)  127.0.0.1 (Sat Aug 25 10:07:04 2012) 127.0.0.1 (Sat Aug 25 10:07:07 2012) 
PS: Since Fail2ban fetches log files to ban, make sure
logpath matches with your configuration.
I'm amazed no on else has given this solution/workaround.
Nginx basic-auth and
htpasswd support bcrypt password encryption with an optional cost variable. Bcrypt is designed to be slow, thus providing a hard limit on how fast you can attempt different passwords.
When creating your basic auth username/password use
htpasswd -B -C 12 path/to/users.db <username>
With a cost of 12 your server will likely not be able to try passwords more than a few times a second, increase that to say 14 and you'll probably be looking at around 1s per password attempt.
With that configured any reasonable password will be immune to brute force attack even if the attacker tried passwords continuously for years.
E.g. at 10 password attempts per second brute force attack on an 8 character alphanumeric password would take 692,351 years:
62**8 / (10*3600*24*365).
This is much easier to configure and more fool-proof than setting up "intelligent" request limitting.
I don't believe nginx has any internal facility to do this. The documentation page doesn't suggest it's possible.
You can use Fail2Ban to block IP addresses that have repeated failed login attempts.
The Fail2Ban wiki has some nginx-specific patterns.
Fail2Ban should be available as a package on most of the big distros.