# Access\_log to track failed logins

**URL:** <https://www.ruby-forum.com/t/access-log-to-track-failed-logins/225158>\
**Category:** NGINX\
**Created:** [December 18, 2012, 8:33pm UTC](https://www.ruby-forum.com/t/access-log-to-track-failed-logins/225158 "2012-12-18T20:33:56Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![aris](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/258eb7/32.png) [@aris](https://www.ruby-forum.com/u/aris)\
**Post date:** [December 18, 2012, 8:33pm UTC](https://www.ruby-forum.com/t/access-log-to-track-failed-logins/225158/1 "2012-12-18T20:33:56Z")

</div>

I have a login page that redirects (actually appends the parameter  
“?error=true” to the URL and lets the user try again).

I was trying to re-define “access\_log” with a full path and (for now)  
“combined” to a separate file in that location in hopes of tracking  
failed logins in a separate log. Originally, I had a regex nested  
location for the error redirect, then I took it out and put it in its  
own location. Nothing seems to work.

This doesn’t seem to work at all. An empty log gets created at startup,  
but nothing ever gets written there. Is it because the access logging  
is already done by the time the location is determined?

How can I somehow log when someone accesses the “login” page with the  
“error=true” parameter on the URL?

Thanks,  
AJ

---

<div class="post-metadata">

**Author:** ![AJ\_Weber](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/8c91f0/32.png) [@AJ\_Weber](https://www.ruby-forum.com/u/AJ_Weber)\
**Post date:** [December 18, 2012, 11:34pm UTC](https://www.ruby-forum.com/t/access-log-to-track-failed-logins/225158/2 "2012-12-18T23:34:27Z")

</div>

On Tue, Dec 18, 2012 at 02:33:06PM -0500, AJ Weber wrote:

Hi there,

> I have a login page that redirects (actually appends the parameter  
> “?error=true” to the URL and lets the user try again).
> 
> I was trying to re-define “access\_log” with a full path and (for now)  
> “combined” to a separate file in that location

nginx chooses configuration based (primarily) on the “location”, which  
is the local part of the request, excluding query string.

So whatever location matches /my/login/page will also match  
/my/login/page?error=true.

Does that explain why your initial attempts did not do what you  
expected?

> This doesn’t seem to work at all. An empty log gets created at startup,  
> but nothing ever gets written there. Is it because the access logging  
> is already done by the time the location is determined?

No, the access logging is done in the context of whichever location the  
request finishes in. It doesn’t appear in your error=true log, because  
a request like /my/login/page%3Ferror=true was not made.

(As a test, make a request like that, and you should see it in the  
new file.)

> How can I somehow log when someone accesses the “login” page with the  
> “error=true” parameter on the URL?

Easiest? Log as normal, and post-process the access log. Something like

tail -F logs/access.log | grep error=true \>\> logs/error=true.log

may be close enough for a first pass.

Or let the application do this logging.

Otherwise, read [Module ngx\_http\_log\_module](http://nginx.org/r/access_log) to see if that offers  
anything.

Possibly logging to “logs/access.log-$arg\_error”, or to something that  
includes a variable set in a map based on $arg\_error, would do what you  
want? But be aware of the constraints.

Good luck,

## f

Francis D. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)

---

<div class="post-metadata">

**Author:** ![AJ\_Weber](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/8c91f0/32.png) [@AJ\_Weber](https://www.ruby-forum.com/u/AJ_Weber)\
**Post date:** [December 19, 2012, 3:05am UTC](https://www.ruby-forum.com/t/access-log-to-track-failed-logins/225158/3 "2012-12-19T03:05:56Z")

</div>

> Does that explain why your initial attempts did not do what you expected?  
> No, unfortunately it doesn’t. I copied the “GET” from the “usual”  
> access log exactly. Thus, I know the call is being made, because it’s  
> being logged in the normal log, and I’m pretty sure I have the right  
> location string, because I copied it right out of the log.

Do I need to escape anything? I’ve tried = and ^~ matching and neither  
seems to catch it.

> > This doesn’t seem to work at all. An empty log gets created at startup,  
> > but nothing ever gets written there. Is it because the access logging  
> > is already done by the time the location is determined?  
> > No, the access logging is done in the context of whichever location the  
> > request finishes in. It doesn’t appear in your error=true log, because  
> > a request like /my/login/page%3Ferror=true was not made.
> 
> (As a test, make a request like that, and you should see it in the  
> new file.)  
> Yes, as I mentioned above, my requests DO get logged (always). They  
> just don’t go to the log I want them to.

---

<div class="post-metadata">

**Author:** ![AJ\_Weber](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/8c91f0/32.png) [@AJ\_Weber](https://www.ruby-forum.com/u/AJ_Weber)\
**Post date:** [December 19, 2012, 10:12am UTC](https://www.ruby-forum.com/t/access-log-to-track-failed-logins/225158/4 "2012-12-19T10:12:23Z")

</div>

> but nothing ever gets written there. Is it because the access logging  
> is already done by the time the location is determined?
> 
> How can I somehow log when someone accesses the “login” page with the  
> “error=true” parameter on the URL?

Try at the http level:

map $arg\_error $log\_error {  
default 0;  
true 1;  
}

and at the server level:

error\_page 418 @log-error;

if ($log\_error) {  
return 418;  
}

location @log-error {  
access\_log my\_special.log;  
}

–appa

---

<div class="post-metadata">

**Author:** ![AJ\_Weber](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/8c91f0/32.png) [@AJ\_Weber](https://www.ruby-forum.com/u/AJ_Weber)\
**Post date:** [December 19, 2012, 10:12am UTC](https://www.ruby-forum.com/t/access-log-to-track-failed-logins/225158/5 "2012-12-19T10:12:58Z")

</div>

On Tue, Dec 18, 2012 at 09:05:30PM -0500, AJ Weber wrote:

Hi there,

> > So whatever location matches /my/login/page will also match  
> > /my/login/page?error=true.
> > 
> > Does that explain why your initial attempts did not do what you expected?

> No, unfortunately it doesn’t. I copied the “GET” from the “usual”  
> access log exactly. Thus, I know the call is being made, because it’s  
> being logged in the normal log, and I’m pretty sure I have the right  
> location string, because I copied it right out of the log.

For nginx location{} matching,

/my/login/page

and

/my/login/page?error=true

are exactly the same. It is not possible to have one matched by one  
location, and the other matched by another.

(So you need something other than location{} matching to distinguish  
them.)

## f

Francis D. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)

---

<div class="post-metadata">

**Author:** ![AJ\_Weber](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/8c91f0/32.png) [@AJ\_Weber](https://www.ruby-forum.com/u/AJ_Weber)\
**Post date:** [December 20, 2012, 3:02pm UTC](https://www.ruby-forum.com/t/access-log-to-track-failed-logins/225158/6 "2012-12-20T15:02:48Z")

</div>

This solution worked. Many thanks to you AND Francis for your replies  
to help.

I always cringe when using the if-statement because of the “bad press”  
it’s gotten in the past. I understand the push to use “location”  
wherever possible, but sometimes a well-placed, simple if-statement is  
exactly what’s needed!

Now the logging is working, and I wrote a (really just modified an  
existing) fail2ban “jail” to watch for IP’s trying to hack the site.  
Nothing’s foolproof, but every little bit helps!

Thanks to all again,  
AJ
