Hotlink protection before proxy when using proxy_pass?

Hi,

I have nginx 1.3.0 configured for a server that forwards to a proxy

server {
server_name dev.local.lan;
listen 192.168.1.100:80;
root /var/empty;
access_log /var/log/nginx/access.log
main;
rewrite_log on;
ssl off;
location / {
proxy_pass http://PROXY;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_connect_timeout 600s;
proxy_read_timeout 600s;
}
}

It works like it should.

192.168.1.100 is the IP of my workstation; the server is on this same
workstation while I develop.

I want to add hotlink protection at the nginx so attempted hotlinks from
unauthorized hosts never get passed to the proxy, but all OK image
requests do as usual.

Using

http://nginxlibrary.com/hotlink-protection/

I modify the server config

server {
server_name dev.local.lan;
listen 192.168.1.100:80;
root /var/empty;
access_log /var/log/nginx/access.log
main;
rewrite_log on;
ssl off;

  •           location ~* \.(png|gif|jpg|jpeg|swf|ico)(\?[0-9]+)?$ {
    
  •                   valid_referers none blocked dev.local.lan
    

*.dev.local.lan;

  •                   if ($invalid_referer) {
    
  •                           return   403;
    
  •                   }
    
  •           }
    

    location / {
    proxy_pass http://PROXY;
    proxy_redirect off;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For
    $proxy_add_x_forwarded_for;
    proxy_set_header X-Client-Verify SUCCESS;
    proxy_connect_timeout 600s;
    proxy_read_timeout 600s;
    }
    }

With this config, If I nav as usual to my site root

http://dev.local.lan

I get my site content displayed in the browser – minus ANY images.

And in the logs lots of these,

==> /var/log/nginx/error.log <==
2012/05/25 08:52:37 [error] 21132#0: *48 open()
“/var/empty/img/img1.png” failed (2: No such file or directory),
client: 192.168.1.100, server: dev.local.lan, request: “GET
/img/img1.png HTTP/1.1”, host: “dev.local.lan”, referrer:
http://dev.local.lan/
2012/05/25 08:52:37 [error] 21132#0: *49 open()
“/var/empty/img/img2.png” failed (2: No such file or directory),
client: 192.168.1.100, server: dev.local.lan, request: “GET
/img/img2.png HTTP/1.1”, host: “dev.local.lan”, referrer:
http://dev.local.lan/
2012/05/25 08:52:37 [error] 21132#0: *51 open()
“/var/empty/img/img3.png” failed (2: No such file or directory),
client: 192.168.1.100, server: dev.local.lan, request: “GET
/img/img3.png HTTP/1.1”, host: “dev.local.lan”, referrer:
http://dev.local.lan/
2012/05/25 08:52:37 [error] 21132#0: *50 open()
“/var/empty/img/img4.png” failed (2: No such file or directory),
client: 192.168.1.100, server: dev.local.lan, request: “GET
/img/img4.png HTTP/1.1”, host: “dev.local.lan”, referrer:
http://dev.local.lan/
2012/05/25 08:52:37 [error] 21132#0: *48 open()
“/var/empty/img/imgA.gif” failed (2: No such file or directory),
client: 192.168.1.100, server: dev.local.lan, request: “GET
/img/imgA.gif HTTP/1.1”, host: “dev.local.lan”, referrer:
http://dev.local.lan/css/css_i9LjMH-EfBMHZV516oBxThl0uqd7YYp4V7x4fuvUFVs.css
2012/05/25 08:52:37 [error] 21132#0: *50 open()
“/var/empty/img/img4.png” failed (2: No such file or directory),
client: 192.168.1.100, server: dev.local.lan, request: “GET
/img/img4.png HTTP/1.1”, host: “dev.local.lan”, referrer:
http://dev.local.lan/

The anti-hotlink stanza IS having an effect, just not the one I want.

What do I need to correct?

RandyK

The anti-hotlink stanza IS having an effect, just not the one I want.
What do I need to correct?

It is because the regular expression locations are matched first (
http://wiki.nginx.org/HttpCoreModule#location ).

As in:

location ~* .(png|gif|jpg|jpeg|swf|ico)(?[0-9]+)?$ {
is processed first and since nginx doesn’t merge/apply directives from
multiple (matching) location blocks the proxy_pass defined in
‘location /’ is not effective.

So you either have to duplicate the proxy_* block:

location ~* .(png|gif|jpg|jpeg|swf|ico)(?[0-9]+)?$ {
valid_referers none blocked dev.local.lan *.dev.local.lan;

if ($invalid_referer) {
         return   403;
}
proxy_pass            http://PROXY;
proxy_redirect         off;
.....

}

or use nested locations (I think it should work):

location / {
proxy_pass http://PROXY;
proxy_redirect off;

location ~* \.(png|gif|jpg|jpeg|swf|ico)(\?[0-9]+)?$ {
     valid_referers none blocked dev.local.lan *.dev.local.lan;
     if ($invalid_referer) {
         return   403;
    }

}

rr

or use nested locations (I think it should work):

That failed to work, still getting the same errors :-/

So you either have to duplicate the proxy_* block:

I switched to

location ~* .(png|gif|jpg|jpeg|swf|ico)(?[0-9]+)?$ {
valid_referers none blocked dev.local.lan
*.dev.local.lan;
if ($invalid_referer) {
return 403;
}
proxy_pass http://PROXY;
proxy_redirect off;

}

location / {
proxy_pass http://PROXY;
proxy_redirect off;

}

and for valid referrer (e.g., visiting the site from
mach2.dev.local.lan), the site renders correctly, and I can ‘grab’ all
image files for hotlinking.

BUT, I’m still able to hotlink to (for example)

http://dev.local.lan/favicon.ico

from a !whitelisted machine, e.g. visiting from other.other.lan.

RandyK