Personal websites, blog pages, etc. You can spend a lot of time, effort, and sometimes money setting them up and maintaining them. The pay-off is when you see lots of people visit your site, take an interest and even provide feedback. The annoyance comes when you notice in your logs that a select handful of images are being downloaded a helluva lot more than every other image on your server, and further scruitiny shows that it wasn’t even your own website requesting them – it was someone elses.
So you go and have a look at the referring site. Worse-case scenario was that they had blatantly plagerised your site – copied everything as their own. Not so bad is that someone has found an interesting pic on your site and linked directly to it on another site to tell people about it, but not necessarily atrributed your site to it.
Hot-linking files between sites is considered bad nettiqette if you have not got permission from the site owner. Image copyright issues aside, it is preferred that if you have an interest in an image that you download a copy and host it yourself, or that you link to the hosting website itself so that people can see proper attribution.
This has already happened to me a few times with the most notable being some Korean blogger’s site blatantly copying word for word one of my articles, but he decided to leave all the images in it hot-linking to my server. I couldn’t believe it, but I knew it wouldn’t be long before someone did that. I dropped a politely worded, but firm, message on his blog where everyone could see it, and he has since deleted the plagerised entry from his blog.
So, how do we go about preventing your Apache web server from serving up images to invalid referrers? Read on…
This HowTo was written with Ubuntu Server 8.04.2 Hardy Heron in mind since most server users would be likely still be using the LTS release for public-facing servers, however these instructions should apply to any version Ubuntu Server until Apache make any radical changes to how their http daemon configuration works. I will also assume that you already have a web site up and running. We are just going to add to its configuration here.
To prevent hot-linking is a simple matter of checking what file is being requested from your server. We can do this by checking for certain file extensions such as .jpg, .png etc. We then have a rule to ensure that such requests are coming from your website, eg: www.acmecorp.com instead of someone else’s site. If the rule matches your site, the requested image is served, otherwise an alternate image is served instead.
What’s the alternate image? Simply it’s a small-sized image that provides a small message to the hot-linker to tell them that you shouldn’t be hot-linking images to your site. The small size ensures that it is transferred quickly and doesn’t chew up much bandwidth on your connection.
Here is the one I use for serenux.com:
Can be anything you want, really. Just make it polite or funny. This one was created in The GIMP and saved out with extremely high compression to make it as small as possible without compromising image quality so much that the image is unreadable with compression artifacts. From memory, I think it was 40% quality instead of the usual 80-85% you’d save most photos with.
Create your own message in a picture and save it out to somewhere on your website with some arbitrary name. I use “noop.jpe” in reference to “no operation” and the file extension is deliberately mangled for reasons you’ll see later. I also save it in the root of my website so I don’t have a long convoluted URL to refer to it with. Eg: if your website resides in /var/www on your server, then save this image to /var/www/noop.jpe accordingly.
Now we need to tell Apache to use this image in place of serving other hot-linked images.
If you use SSH to manage your server:
- SSH into your web server as normal.
$ ssh acmecorp@www.acmecorp.com
- Change directory to the /etc/apache2/sites-available directory.
$ cd /etc/apache2/sites-available
- Bring up your website’s configuration file into your favourite text editor. In this case, the config file is called “www.acmecorp.com” and i’ll use the Nano editor to edit it.
$ sudo nano www.acmecorp.com
- Add the following lines to the end of the configuration file, but before the </Virtualhost> line:
# Prevent hotlinking of images from foreign sites and redirect to a new image.
RewriteEngine on
RewriteCond %{HTTP_REFERER} !^http://www\.acmecorp\.com/.*$ [NC]
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} ^http://.*$
RewriteRule .*\.(jpe?g|gif|bmp|png)$ http://www.acmecorp.com/noop.jpe [NC,R,L]
(Change www.acmecorp.com to what is relevant to your site, of course)
What the above does in order is turn on URL re-writing, then check to see if the referrer does NOT start with the string “www.acmecorp.com” (the NC means “not case-sensitive”, so it matches on things like WWW.ACMECORP.COM and www.AcmeCorp.com as well), the referrer is also checked to ensure that is is not blank, and that the referrer had a “http://” string at the start.
If all these rules match true, then one last rule is applied before re-writing the URL – if the URL string requested ends with .jpg, .jpeg (the e? part tests for whether the “e” exists or not so it matches on jpg or jpeg), .gif, .bmp or .png, then re-write the requested URL as “www.acmecorp.com/noop.jpe” with no case-sensitivity on the match (“NC”, the “R” parameter will tell your visitor’s browser that they were redirected (you don’t have to do this – you may want the visitor to think this is actually what they requested), and the “L” parameter will stop processing of anymore re-write rules here, ie: this is the “Last” re-write rule.
- Save your work and exit the editor by pressing CTRL + X and then “Y” to save.
- We’re almost there! Now that we have the rules written, we now need to enable the URL re-writing module of Apache called “mod_rewrite”. Without it, the changes we did to the configuration will cause Apache to error out on startup. Ubuntu has the re-write module pre-compiled in, so all we have to do is enable it. To do this, simply enter the command:
$ sudo a2enmod rewrite
- Now we are ready to rock and/or roll. Restart your Apache server with:
$ sudo /etc/init.d/apache2 restart
- Ensure that no errors were reported during startup and then test hot-linking to your site. NOTE: If you already tested hot-linking from another site and can still see your images, more than likely they have been served up from your web browser’s cache – clear your cache and try again.
- Pat yourself on the back. You’re done.
If you use WEBMIN to manage your server:
This HowTo section assumes you’re using Webmin version 1.430 or later.
- Open your web browser and get into your Webmin interface as normal.
- Click on “Servers” in the left pane. A list of server daemons will be listed underneath.
- Click on the “Apache Webserver” daemon. The right pane will then show you your available web sites.
- Click on the “Global Configuration” tab at the top-left of the Virtual Server list. The pane will change to show global Apache options.
- Click on the “Configure Apache Modules” icon. The pane will change to show the currently available and enabled Apache modules.
- Locate “rewrite” in the list and ensure a checkbox is enabled against it. Do not change anything else.
- Scroll to the bottom of the list and click on the “Enable selected modules” button. You will be returned to the Virtual Server list page.
- Now click on the icon relevant to your virtual server, eg: “www.acmecorp.com”. The window changes to show the options available for that virtual server.
- Click on the “Edit Directives” icon. You will be presented with a text editor showing the configuration file.
- At the end of the file, paste the following in:
# Prevent hotlinking of images from foreign sites and redirect to a new image.
RewriteEngine on
RewriteCond %{HTTP_REFERER} !^http://www\.acmecorp\.com/.*$ [NC]
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} ^http://.*$
RewriteRule .*\.(jpe?g|gif|bmp|png)$ http://www.acmecorp.com/noop.jpe [NC,R,L]
(Change www.acmecorp.com to what is relevant to your site, of course.)
See the description of what all this does in the SSH instructions.
- Click on the Save button.
- Click on “Apply changes” at the top-right of the Webmin window.
- Test hot-linking images on a foreign site to your own. NOTE: If you already tested hot-linking from another site and can still see your images, more than likely they have been served up from your web browser’s cache – clear your cache and try again.
- Pat yourself on the back. You’re done.
Notes:
Now, you’ll rember that I called the anti hot-linking image “noop.jpe” instead of “noop.jpg”. Want to know why? Well, it’s the only image on your entire server that you DON’T want to be matched on for anti hot-linking. Despite the URL being re-written to deliver that image to the visitor’s web browser, that very image is still subject to the re-write rules as well. If you were to tell your Apache server to re-write the URL for every .jpg image on your server, then the “noop.jpe” file served as “noop.jpg” instead would be re-written to “noop.jpg” again and again and again in an infinite loop, hanging your server and not actually serving it to the visitor! Thankfully Apache today is a little smarter and will detect and abort an infinite loop, but it still serves nothing to the visitor. This is why we called the file “noop.jpe” so that it does NOT match the “.jpg” or “.jpeg” rules. We could fix this by simply adding another rule that says “don’t re-write if noop.jpg is being requested” but I’m just lazy. You want the rule? OK, fine – add this before the “ReWriteRule” line:
RewriteCond %{HTTP_REFERER} !^http://www\.acmecorp\.com/noop\.jpg.*$ [NC]
Now what if you participate on other forums and want to allow hot-linking of images on your site from that site? What about Google and other search engines – can you omit them from being blocked? You sure can. Just add these rules in before the “ReWriteRule” line, and modify them to your requirements:
RewriteCond %{HTTP_REFERER} !^http://(www\.|forums\.)?overclockers\.com\.au/.*$ [NC]
RewriteCond %{HTTP_REFERER} !^http://(images\.)?google.*$ [NC]
The first condition says “don’t re-write if the referrer string starts with either “www.overclockers.com.au” or “forums.overclockers.com.au” and the second condition says “don’t re-write if the referrer string starts with either “images.google.<whatever>” or “google.<whatever>” (so that means it’ll allow things like images.google.com.au, google.com, google.co.uk, images.google.co.uk etc, but will NOT allow things like banana.google.com or freddo.google.co.uk”. You can adapt this easily enough to other search engines like Yahoo etc.
Finally, what if you simply want to be a bastard and present a broken link to the hot-linker instead of a friendly message? Hot-linkers be damned! An easy way to do that is to re-write the “ReWriteRule” line as follows:
RewriteRule .*\.(jpe?g|gif|bmp|png)$ - [F]
The dash and the “F” parameter essentially drops the request and serves nothing back. Not even an acknowledgement. As far as your hot-linker is concerned, the image file doesn’t exist.
Happy blocking!