Web Development

Hotlink Protection On Nginx

I recently created a WordPress plugin called Redirection Manager which will keep track of all 404s on your website and log the URL and the referrer of the link.

In doing so I noticed there were quite a few websites using some old CSS, Javascript and image files from my website on their own. You can easily do this by just linking to the asset using my absolute URL.

<link href="https://paulund.co.uk/stylesheet.css" rel="stylesheet">

The problem is this resource will come from my website and my server so now my server not only has to handle the traffic from my own site but also anyone who's using any of my assets. This is obviously a big unnecessary load on the server which needs to be fixed, so I needed nginx to handle this before it accessed my database.

Here's the solution I came up with.

location ~ .(css|js|swf|gif|png|jpe?g)$ 
     valid_referers none blocked ~.google. ~.bing. ~.yahoo. server_names ~($host);
     if ($invalid_referer) {
        return   403;

It checks on files types of

  • CSS
  • JS
  • SWF
  • GIF
  • PNG
  • JPEG
  • JPG

It will then block all requests for these files unless the referrer is from google, bing, yahoo or the server host name (which should be the current domain).

If a domain has come back as invalid then we throw a 403 Forbidden HTTP code so the content will not be shown on their website.

Testing Domain

When you've added this to your Nginx config file you'll need to restart nginx.

> sudo service nginx restart

Then you can make a curl request from the commandline and spoof the referrer.

To test a bad URL

> curl --referer http://www.arandomstealingurl.com <IMAGE_URL>

To test a successful URL you can use the following

> curl --referer http://www.google.com <IMAGE_URL>
Back to top

Learn how to code with Treehouse

  • Learn projects with access to 1000+ videos
  • Practice live with our Code Challenge Engine
  • Get help in our members-only forums

Start with a 7 day free trial

Leave a Reply

Your email address will not be published. Required fields are marked *