{"id":91,"date":"2009-04-05T11:36:00","date_gmt":"2009-04-05T01:36:00","guid":{"rendered":"https:\/\/www.serenux.com\/?p=91"},"modified":"2021-01-14T11:41:38","modified_gmt":"2021-01-14T01:41:38","slug":"howto-prevent-other-sites-hot-linking-to-images-on-your-own-apache-website-on-your-ubuntu-server","status":"publish","type":"post","link":"https:\/\/www.serenux.com\/index.php\/2009\/04\/05\/howto-prevent-other-sites-hot-linking-to-images-on-your-own-apache-website-on-your-ubuntu-server\/","title":{"rendered":"HowTo: Prevent other sites hot-linking to images on your own Apache website on your Ubuntu Server."},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">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\u2019t even your own website requesting them \u2013&nbsp;<em>it was someone elses<\/em>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">So you go and have a look at the referring site. Worse-case scenario was that they had blatantly plagerised your site \u2013 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.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Hot-linking files between sites is considered bad&nbsp;<a href=\"https:\/\/web.archive.org\/web\/20160311192245\/http:\/\/www.google.com.au\/url?q=http:\/\/en.wikipedia.org\/wiki\/Netiquette&amp;ei=VeLXSeCuNYiIkAWy7ZHPBA&amp;sa=X&amp;oi=spellmeleon_result&amp;resnum=1&amp;ct=result&amp;cd=1&amp;usg=AFQjCNFr-L6n5EH-Loy4L0QsA9r4tEpYFg\" target=\"_blank\" rel=\"noreferrer noopener\">nettiqette<\/a>&nbsp;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.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This has already happened to me a few times with the most notable being some Korean blogger\u2019s 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\u2019t believe it, but I knew it wouldn\u2019t 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.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">So, how do we go about preventing your Apache web server from serving up images to invalid referrers? Read on\u2026<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">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.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">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\u2019s site. If the rule matches your site, the requested image is served, otherwise an alternate image is served instead.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">What\u2019s the alternate image? Simply it\u2019s a small-sized image that provides a small message to the hot-linker to tell them that you shouldn\u2019t be hot-linking images to your site. The small size ensures that&nbsp; it is transferred quickly and doesn\u2019t chew up much bandwidth on your connection.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Here is the one I use for serenux.com:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img decoding=\"async\" src=\"https:\/\/web.archive.org\/web\/20160311192245im_\/http:\/\/www.serenux.com\/noop.jpe\" alt=\"Anti hot-linking message\" title=\"Anti hot-linking message\"\/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">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\u2019d save most photos with.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Create your own message in a picture and save it out to somewhere on your website with some arbitrary name. I use \u201cnoop.jpe\u201d in reference to \u201cno operation\u201d and the file extension is deliberately mangled for reasons you\u2019ll see later. I also save it in the root of my website so I don\u2019t have a long convoluted URL to refer to it with. Eg: if your website resides in&nbsp;<em>\/var\/www<\/em>&nbsp;on your server, then save this image to&nbsp;<em>\/var\/www\/noop.jpe<\/em>&nbsp;accordingly.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Now we need to tell Apache to use this image in place of serving other hot-linked images.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>If you use SSH to manage your server:<\/strong><\/p>\n\n\n\n<ol class=\"wp-block-list\"><li>SSH into your web server as normal.<br><br><code>$ ssh acmecorp@www.acmecorp.com<\/code><br><\/li><li>Change directory to the \/etc\/apache2\/sites-available directory.<br><br><code>$ cd \/etc\/apache2\/sites-available<\/code><br><\/li><li>Bring up your website\u2019s configuration file into your favourite text editor. In this case, the config file is called \u201cwww.acmecorp.com\u201d and i\u2019ll use the Nano editor to edit it.<br><br><code>$ sudo nano www.acmecorp.com<\/code><br><\/li><li>Add the following lines to the end of the configuration file, but before the &lt;\/Virtualhost> line:<br><br><code># Prevent hotlinking of images from foreign sites and redirect to a new image.<br>RewriteEngine on<br>RewriteCond %{HTTP_REFERER} !^http:\/\/www\\.acmecorp\\.com\/.*$ [NC]<br>RewriteCond %{HTTP_REFERER} !^$<br>RewriteCond %{HTTP_REFERER} ^http:\/\/.*$<br>RewriteRule .*\\.(jpe?g|gif|bmp|png)$ http:\/\/www.acmecorp.com\/noop.jpe [NC,R,L]<\/code><br><br>(Change www.acmecorp.com to what is relevant to your site, of course)<br><br>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 \u201cwww.acmecorp.com\u201d (the NC means \u201cnot case-sensitive\u201d, 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 \u201chttp:\/\/\u201d string at the start.<br><br>If all these rules match true, then one last rule is applied before re-writing the URL \u2013 if the URL string requested ends with .jpg, .jpeg (the e? part tests for whether the \u201ce\u201d exists or not so it matches on jpg or jpeg), .gif, .bmp or .png, then re-write the requested URL as \u201cwww.acmecorp.com\/noop.jpe\u201d with no case-sensitivity on the match (\u201cNC\u201d<img decoding=\"async\" src=\"https:\/\/web.archive.org\/web\/20160311192245im_\/http:\/\/www.serenux.com\/wp-content\/themes\/grey-opaque\/images\/smilies\/icon_wink.gif\" alt=\"Smilie: ;)\">, the \u201cR\u201d parameter will tell your visitor\u2019s browser that they were redirected (you don\u2019t have to do this \u2013 you may want the visitor to think this is actually what they requested), and the \u201cL\u201d parameter will stop processing of anymore re-write rules here, ie: this is the \u201cLast\u201d re-write rule.<br><\/li><li>Save your work and exit the editor by pressing CTRL + X and then \u201cY\u201d to save.<br><\/li><li>We\u2019re almost there! Now that we have the rules written, we now need to enable the URL re-writing module of Apache called \u201cmod_rewrite\u201d. 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:<br><br><code>$ sudo a2enmod rewrite<\/code><br><\/li><li>Now we are ready to rock and\/or roll. Restart your Apache server with:<br><br><code>$ sudo \/etc\/init.d\/apache2 restart<\/code><br><\/li><li>Ensure that no errors were reported during startup and then test hot-linking to your site.\u00a0<em>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\u2019s cache \u2013 clear your cache and try again.<br><\/em><\/li><li>Pat yourself on the back. You\u2019re done.<\/li><\/ol>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>If you use WEBMIN to manage your server:<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This HowTo section assumes you\u2019re using Webmin version 1.430 or later.<\/p>\n\n\n\n<ol class=\"wp-block-list\"><li>Open your web browser and get into your Webmin interface as normal.<br><\/li><li>Click on \u201cServers\u201d in the left pane. A list of server daemons will be listed underneath.<br><\/li><li>Click on the \u201cApache Webserver\u201d daemon. The right pane will then show you your available web sites.<br><\/li><li>Click on the \u201cGlobal Configuration\u201d tab at the top-left of the Virtual Server list. The pane will change to show global Apache options.<br><\/li><li>Click on the \u201cConfigure Apache Modules\u201d icon. The pane will change to show the currently available and enabled Apache modules.<br><\/li><li>Locate \u201crewrite\u201d in the list and ensure a checkbox is enabled against it. Do not change anything else.<br><\/li><li>Scroll to the bottom of the list and click on the \u201cEnable selected modules\u201d button. You will be returned to the Virtual Server list page.<br><\/li><li>Now click on the icon relevant to your virtual server, eg: \u201cwww.acmecorp.com\u201d. The window changes to show the options available for that virtual server.<br><\/li><li>Click on the \u201cEdit Directives\u201d icon. You will be presented with a text editor showing the configuration file.<br><\/li><li>At the end of the file, paste the following in:<br><br><code># Prevent hotlinking of images from foreign sites and redirect to a new image.<br>RewriteEngine on<br>RewriteCond %{HTTP_REFERER} !^http:\/\/www\\.acmecorp\\.com\/.*$ [NC]<br>RewriteCond %{HTTP_REFERER} !^$<br>RewriteCond %{HTTP_REFERER} ^http:\/\/.*$<br>RewriteRule .*\\.(jpe?g|gif|bmp|png)$ http:\/\/www.acmecorp.com\/noop.jpe [NC,R,L]<\/code><br><br>(Change www.acmecorp.com to what is relevant to your site, of course.) <br><br>See the description of what all this does in the SSH instructions.<br><\/li><li>Click on the Save button.<br><\/li><li>Click on \u201cApply changes\u201d at the top-right of the Webmin window.<br><\/li><li>Test hot-linking images on a foreign site to your own.\u00a0\u00a0<em>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\u2019s cache \u2013 clear your cache and try again.<br><\/em><\/li><li>Pat yourself on the back. You\u2019re done.<\/li><\/ol>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Notes:<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Now, you\u2019ll rember that I called the anti hot-linking image \u201cnoop.jpe\u201d instead of \u201cnoop.jpg\u201d. Want to know why? Well, it\u2019s the only image on your entire server that you DON\u2019T want to be matched on for anti hot-linking. Despite the URL being re-written to deliver that image to the visitor\u2019s 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 \u201cnoop.jpe\u201d file served as \u201cnoop.jpg\u201d instead would be re-written to \u201cnoop.jpg\u201d 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 \u201cnoop.jpe\u201d so that it does NOT match the \u201c.jpg\u201d or \u201c.jpeg\u201d rules. We could fix this by simply adding another rule that says \u201cdon\u2019t re-write if noop.jpg is being requested\u201d but I\u2019m just lazy.&nbsp;<img decoding=\"async\" src=\"https:\/\/web.archive.org\/web\/20160311192245im_\/http:\/\/www.serenux.com\/wp-content\/themes\/grey-opaque\/images\/smilies\/icon_wink.gif\" alt=\"Smilie: ;)\">&nbsp;You want the rule? OK, fine \u2013 add this before the \u201cReWriteRule\u201d line:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">RewriteCond %{HTTP_REFERER} !^http:\/\/www\\.acmecorp\\.com\/noop\\.jpg.*$ [NC]<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Now what if you participate on other forums and want to&nbsp;allow&nbsp;hot-linking of images on your site from that site? What about Google and other search engines \u2013 can you omit them from being blocked? You sure can. Just add these rules in before the \u201cReWriteRule\u201d line, and modify them to your requirements:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">RewriteCond %{HTTP_REFERER} !^http:\/\/(www\\.|forums\\.)?overclockers\\.com\\.au\/.*$ [NC]\nRewriteCond %{HTTP_REFERER} !^http:\/\/(images\\.)?google.*$ [NC]<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The first condition says \u201cdon\u2019t re-write if the referrer string starts with either \u201cwww.overclockers.com.au\u201d or \u201cforums.overclockers.com.au\u201d and the second condition says \u201cdon\u2019t re-write if the referrer string starts with either \u201cimages.google.&lt;whatever&gt;\u201d or \u201cgoogle.&lt;whatever&gt;\u201d (so that means it\u2019ll 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\u201d<img decoding=\"async\" src=\"https:\/\/web.archive.org\/web\/20160311192245im_\/http:\/\/www.serenux.com\/wp-content\/themes\/grey-opaque\/images\/smilies\/icon_wink.gif\" alt=\"Smilie: ;)\">. You can adapt this easily enough to other search engines like Yahoo etc.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">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 \u201cReWriteRule\u201d line as follows:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">RewriteRule .*\\.(jpe?g|gif|bmp|png)$ - [F]<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The dash and the \u201cF\u201d 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\u2019t exist.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Happy blocking!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>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 [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-91","post","type-post","status-publish","format-standard","hentry","category-tutorials"],"_links":{"self":[{"href":"https:\/\/www.serenux.com\/index.php\/wp-json\/wp\/v2\/posts\/91","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.serenux.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.serenux.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.serenux.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.serenux.com\/index.php\/wp-json\/wp\/v2\/comments?post=91"}],"version-history":[{"count":1,"href":"https:\/\/www.serenux.com\/index.php\/wp-json\/wp\/v2\/posts\/91\/revisions"}],"predecessor-version":[{"id":92,"href":"https:\/\/www.serenux.com\/index.php\/wp-json\/wp\/v2\/posts\/91\/revisions\/92"}],"wp:attachment":[{"href":"https:\/\/www.serenux.com\/index.php\/wp-json\/wp\/v2\/media?parent=91"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.serenux.com\/index.php\/wp-json\/wp\/v2\/categories?post=91"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.serenux.com\/index.php\/wp-json\/wp\/v2\/tags?post=91"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}