21

In order to prevent referrer spam, my nginx.conf contains a section like this:

if ($http_referer ~* spamdomain1\.com) {
    return 444;
}
if ($http_referer ~* spamdomain2\.com) {
    return 444;
}
if ($http_referer ~* spamdomain3\.com) {
    return 444;
}

These rules tell nginx just to close the connection if the user has one of these referrers set. Is there a more elegant way to do this? Can I define a list of these domains and then say something like, “If the referrer is in this list then return 444”?

  • create one big file quite like the one from sample and use it as include file where needed. – Hrvoje Špoljar Nov 22 '14 at 17:49
29

I would try a map:

map $http_referer $bad_referer {
    default                  0;
    "~spamdomain1.com"       1;
    "~spamdomain2.com"       1;
    "~spamdomain3.com"       1;
}

Then use it like so:

if ($bad_referer) {
    return 444;
}
  • 1
    Since map uses a hash tables this approach will perform better than a series of individual checks. Read the docs for options that could be used, like hostnames and possiblely include of a separate file where they are listed could make it easier to maintain. – Brian Nov 22 '14 at 22:57
  • Reading the docs related to map I was interested to see if one could use regex to match certain referrers since OP is doing regex matching using ~* operator, and indeed simply specifying map rule like "~*spamdomain4.com" 1; will do the trick. Neat! – Hrvoje Špoljar Nov 22 '14 at 23:01
  • You're right, and this needs to use it anyway. – Michael Hampton Nov 22 '14 at 23:07
  • Using the hostnames option it would be simply .spamdomain4.com 1; – Brian Nov 23 '14 at 0:04
  • 4
    @Brian The referer field is a complete URL, not simply a hostname. So that doesn't work. – Michael Hampton Nov 23 '14 at 0:20
13

You could use logical OR to craft one multi match statement e.g.

if ($http_referer ~ "spamdomain1\.com|spamdomain2\.com|spamdomain3\.com")  { 
  return 444;
}

EDIT per comment; removing break; from the block

  • 2
    The break directive will never be reached as return stops the processing of the current request. – Xavier Lucas Nov 22 '14 at 19:50
3

ngx_http_referer_module is another way to do it. Example from Referer Spam Blocking:

location / {
  valid_referers none blocked *.badreferer1.com badreferer2.com *.badreferer3.com badreferer4.net;

  if ($invalid_referer) {
    return   403;
  }
}

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.