5 Fun and Practical Htaccess Solutions

5 Fun and Practical Htaccess Solutions

Today we will go over some practical uses of htaccess files that you can use in your web applications.

Requirements

Htaccess files are plain-text configuration files used by the Apache HTTP web server. They allow users to set directory level options without requiring access to the httpd.conf file. As such it is required that your server uses Apache, and a web host that allows htaccess files (the most popular hosts do).

I assume a basic working knowledge of htaccess, but if you need to freshen up check out this article by Joseph Pecoraro

1. Prevent Hotlinking

Hotlinking, or inline linking, is when one web site links directly to an object on another site. This costs the hosting site bandwidth to provide the image on the page of the second site. On popular photo sites this can be a major problem, albeit humorous at times.

There are ways to fix this growing problem using htaccess. First here is the image we are trying to protect.

  RewriteEngine on
  RewriteCond %{HTTP_REFERER} !^$

  #domains that can link to images
  #add as many as you want
    RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?demo.collegeaintcheap.com [NC]
    # RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?noahhendrix.com [NC]

  #show no image when hotlinked
    RewriteRule \.(jpg|png|gif)$ - [NC,F,L]

We will step through this line-by-line.

  1. First we need to turn on the rewrite engine in Apache, this allows us to redirect the user’s request.
  2. Next we start setting our conditions using RewriteCond. This is a function that takes two arguments: TestString and CondPattern. TestString is the string we want to check our CondPattern against (using regular expressions). ${HTTP_REFERER} is a variable provided by Apache that holds the domain the request came from, in this instance we want to allow requests from blank HTTP referrers to protect users who are on a proxy server that sends blank referrers.
  3. Next we set the domains from which we will allow our images to be linked using the same syntax except now we provide a URL. The [NC] flag at the end of the command simply instructs the engine to ignore casing. You can add as many lines domains as you’d like here, using the same syntax. For the sake of example I added my personal domain, but commented it out.
  4. Finally, the last line is the RewriteRule we wish to use if any of the conditions above are not met. It takes two arguments as well Pattern and Substitution, where pattern is a regular expression match and substitution is what we want to replace any matches with. In this case we are looking for requests that end in jpg, png, and gif; if found we want to use a blank substitution. However in the flags we tell it furthermore what we want to be done, NC means no case, F sends a 403 forbidden error to user, and L tells the engine to stop rewriting so no other rules are applied.

This is fairly straightforward, but perhaps we are interested in telling the user we don’t want them to hotlink our images, so let’s redirect all hotlinked requests to an image instead of sending a 403 forbidden error. This is done by replacing the last line with this code.

  #show an alternate image
    RewriteRule \.(jpg|png|gif)$ http://demo.collegeaintcheap.com/envato/htaccess/hotlink/images/hotlink.jpeg [NC,R,L]

You can change url to any image path you’d like on your domain, but remember it needs to not end in jpg, png, or gif as it will reapply the rule and send the server into a never-ending loop. I chose to use the older .jpeg extension to fix this. The R flag that replaced F simply sends a redirect.

2. Block User By IP Address

This is a great little tip if you have a spammer on your website. If you can find their IP in your logs, simply add it to an htaccess file.

  Order Deny,Allow
  Deny from 24.121.202.23
  # Deny from 0.0.0.0

Using the Order directive in the mod_access module we can specify IPs to deny and allow. Simply using the syntax Deny from IP ADDRESS we can forbid those users from accessing our directory.

3. Error Documents

All production ready sites should use custom error pages for a professional touch. This is easy using the ErrorDocument directive in Apache’s core. A custom page is far better than the default Apache error pages.

  ErrorDocument 404 http://demo.collegeaintcheap.com/envato/htaccess/errors/404.html
  ErrorDocument 403 http://demo.collegeaintcheap.com/envato/htaccess/errors/403.html
  ErrorDocument 500 http://demo.collegeaintcheap.com/envato/htaccess/errors/500.html

ErrorDocument takes two arguments error-code and document. In the code above I created error documents for the 3 most common HTTP errors: 404 not found, 403 forbidden, and 500 server error. Then you can provide the full URL or relative path to your error documents. You could also them redirect to a PHP script that logs the errors in a database or emails them to you (might get annoying though). This is a great way to take control of errors in your web application, be sure to check out Smashing Magazine’s 404 error page showcase for inspiration.

4. Redirect While Performing Upgrades

If you are performing a major site upgrade you most likely should redirect users to a page informing them. This prevents users from seeing broken pages or potential security holes while the application is uploading. One caveat to consider is that we want to allow certain IP addresses into the site for testing before it goes live all of this can be achieved in an htaccess file.

  RewriteEngine on
  RewriteCond %{REQUEST_URI} !/upgrade.html$
  RewriteCond %{REMOTE_HOST} !^24\.121\.202\.30
  RewriteRule $ http://demo.collegeaintcheap.com/envato/htaccess/upgrade/upgrade.html [R=302,L]

We are using the rewrite engine again to do this, but in a kind of reverse way. First we need to set a condition that excludes the document describing the upgrade otherwise our server start a never ending loop. Next we exclude a single IP address from being redirected for testing purposes. Finally we use the rewrite rule to send users to an upgrade page. The flags we have looked at before, except this time we setting the redirect to a 302 status code, telling the browser that the page has temporarily moved and to handle caching accordingly. Smashing Magazine, again, has a great showcase of Effective Maintenance Pages.

5. Hiding Directory Listing

For numerous security reasons it is a good idea to restrict directory listing, the default behavior in Apache. This can be done with a simple line in our htaccess file we can prevent visitors from seeing our directory listings.

  Options -Indexes

Now users who request a directory that doesn’t have an index file it will show them a 403 forbidden error page.

Conclusion

These are several of my favorite uses of htaccess. Leave yours in the comments! I am available for help in the comments or on twitter. If there is a great deal of interest, I will do more htaccess tutorials with solutions to your requests in the comments. Thanks for reading!


Add Comment

Discussion 97 Comments

Comment Page 1 of 21 2
  1. Filip Benes says:

    Thanks! Useful, but could you write another article about mod_rewrite
    I and I think many others would really appreciate it!

  2. crysfel says:

    awesome!! this is really good!! i didn’t know about the “upgrade” redirect.

    thanks you so much!!

  3. Cvitano says:

    Nice list of .htaccess features, but I miss the url rewriting methode. I know it can also be done with .htacces.
    There are not many tutsites that cover the basic of a good structured website. Where a domain with .com/about/ will be redirected to the according about.php page and still show /about/ in the title bar.

  4. Eric M. says:

    Very useful.

  5. Eric says:

    Thanks for the info. Being more of a sysadmin than developer I always appreciate these kinds of tuts.

  6. Paul Davis says:

    Good tutorial, I really should add a few of these to my sites!

    I would also like a tutorial on mod_rewrite as well!

  7. Duncan says:

    Awesome list, this gave me many ideas of what to do with htaccess other than just the cleaning up of dynamic urls.

  8. HMM says:

    Expecting a mod_rewrite tutorial .This is also great !

  9. NickyB says:

    Excellent article.. always nice to see how much you can do with the htaccess file which reminds me..
    /me runs off

  10. Daniel Wood says:

    Guess this tutorial was chosen over mine -_-

    I had a 3 part series planned; basic, intermediate, advanced. I was going to cover mod-rewrite extensively as well.

    Oh well

  11. Mike says:

    None of these are new to me, but the clear and concise explanations have definitely expanded my knowledge.

    A mod-rewrite and pretty urls tutorial would get my vote too.

  12. Ken says:

    Please tell me that email shown in #1 is fake.
    ‘I am an honest business man…’ NOT.
    People like that should be punched repeatedly in the head.

  13. Giovanni says:

    I needed to know some of these solutions, thanks!

  14. Redirect while performing upgrades is very useful. I don’t see that one a lot in other .htaccess tutorials. I actually do it through php so that the upgrade message is styled, but I guess sometimes it wouldn’t be possible.

  15. Is that e-mail from the hot linker real? O_O haha I cant believe that

  16. Aayush says:

    I never quite get comfortable with htaccess….This helped….

  17. Idowebdesign says:

    Nice article, really useful !

  18. yup how to re-write urls that have php variables would be helpful too!

    will the hotlinking code block images in feed readers?

    • Noah Hendrix says:
      Author

      Hmm good question not really sure. If they cache the image then no, but if they are pulling live from the server I guess it probably would. One idea to circumvent that would be if they use an iframe I suppose.

  19. Noah Hendrix says:
    Author

    It appears everyone is clamoring to see an htaccess tutorial using mod_rewrite, I have put that on my list of subjects to cover any specifics you’d like to see be sure to put them here, or @noahhendrx on twitter.

    • mod_rewrite can be hard to grasp without some regex experience. When I was learning mod_rewrite, the best tutorial I found was at phpfreaks.com. Unfortunately, they redesigned their site (after being hacked I believe), and I can’t find it to share with ya’ll.

  20. Brandon says:

    I always run into this issue, someone has a site, they want an update with a CMS, so I install TXP or WordPress (along with their htaccess files, and their setup of mod_rewrite for pretty urls)… but how do I redirect people to a temp page during the updates (as in #4) in this situation, because it ends up conflicting with the mod_rewrite setup for the CMS?

  21. Robbert says:

    Thank you for your information :) Especially no. 4 is useful for me :)

  22. xirclebox says:

    The fact that the “honest business man” was leaching images to build his business and had the nerve to threaten to call his lawyer. Comedy!

    Good info here. Thanks for the post.

  23. Fynn says:

    Nice article! And that email really made my laugh..

    But I also would like to see a indepth article about mod_rewrite..

    Some specific ideas:

    changing url’s in this way:

    normal url: http://www.mysite.com?var1=majorsubject?var2=secondsubject turning into var1.mysite/var2

    Is that possible? To also use (fictive) subdomains in mod_rewrite?

  24. I laughed so hard when I read those hotlinking emails. Those are hilarious. Thanks for these tips.

  25. Dennis says:

    Great article…. I have to say I was quite literally laughing out loud reading his email about how he is such an honorable business man… and the mention of a lawyer? priceless!

  26. lrntlbx says:

    GReat ! So simple, so excellent ! Woaaa !

  27. Ben says:

    Oh excellent post! Thank you very much! haha I especially liked the email from the one on hotlinking :)

  28. Smartarse says:

    For performing upgrades the best solution is to have the holding page return a 503

  29. Zach Dunn says:

    This is really useful, I wish I had this article about a week ago with the IP bans. Great writeup Noah!

  30. really nice… thank you ;)

  31. Robert says:

    Good little collection. I’d definitely add the 301 redirect when you want to say switch a site from an old to a new URL structure nad preserve your search engine rankings as much as possible:

    Redirect 301 /old/old.html http://www.domain.com/new.html

  32. Synapse Syndrome says:

    Another great use for .htaccess, of that can use it to keep URLs meaningful and consistant, even when you change technologies, like from .aspx to .php.

    This is what the inventor of the web has to say about that: http://www.w3.org/Provider/Style/URI

    Also, you can use .htaccess to treat .html files and .shtml, so you do not have to include that weird file extension when you want to use Server Side Includes (which are really cool, otherwise).

  33. Synapse Syndrome says:

    Another good use for .htaccess is to keep meaningful and consistent URLs, even when you rename files or change technologies (like .asp to .php). This is what the inventor of the web has to say about that:
    http://www.w3.org/Provider/Style/URI

    .htaccess is also really useful to make .html files treated like .shtml, so you can use Server Side Includes (which are great) without having to use that weird file extension.

  34. ben chen says:

    thanks ,but in asp how could setting htacess

  35. Seich says:

    Really nice tips.

  36. KC says:

    Love that email. It’s gold.. your article too, of course, but not in the same sense ;)

    thanks!

  37. prakash says:

    hi this tutorial is good

  38. webn says:

    Excellent Hendrix. Very helpful for professionals.

  39. Tomas says:

    Nice article, especially for beginners.

    I also used .htaccess in a funny way. I wanted to experiment with User-Agent filtering… Especially with Web Crawlers, spiders and Bots. So I blocked all “human” visitors on a live website, and allowed only web crawlers to access the site. If you interested in the result look on my blog post:

    http://www.dobrotka.sk/blog/use-htaccess-to-filter-visitors-and-crawlers-based-on-user-agent/

  40. Patrick says:

    Ahm, okay…

    Well, did you have turned off your referer variable in your browser? Than you’ll see, that your number 1 isn’t as good as you thought.

    There are several Plugins, Firewalls and so on, that kills the referer string of a httprequest. And without it users can see every picture.

    Think a php based solution is much better.

    • Some name says:

      Most ways of implementing an anti hotlink system (be it .htaccess, php, asp, whatever) uses the the http referrer header. I don’t think there is any clean way to do it. I think the best solution would be an automated (cron job or something) or manual system that simply checks the logs if there’s a specific domain (checking the referrer field) that has taken a lot of bandwidth, and add those domains to a blacklist as that wont f*ck anything up for normal users.

      • Patrick says:

        I know a really secure solution for it, trust me :D the biggest goal: i don’t need the referer. IP, Browser, Timestamp – or just a unique key – that’s all.

        Needs:
        – mod_rewrite (optional)
        – php
        – some userdata (IP, browser, timestamp of visit…) or unique key to build md5 string
        – a bit coding skill

        the idea:

        build an unique URL to the file for each user who accesses the file, p.e.: domain.com/img/74mnd36z54mf/folder/filename.png or without mod_rewrite: domain.com/file.php?/img/74mnd36z54mf/folder/filename.png

        Important: the real path to the image is _not_ img/folder/filename.png or img/74mnd36z54mf/folder/filename.png, that will be too easy to find out. Use a totally other name for the base image folder. And also impotant: Don’t use indexing on the webserver.

        74mnd36z54mf = sample unique key to identifier user.

        There are two ways to finally restrict the access to one unique user: store the unique key in a $_SESSION (cookiebased or urlbased) or store it in a database. Bind this unique key with the ip address of the visitor. Optional you can set a time limit for accessing. Bingo: Only this unique user will get now the right image.

        Well, okay, true: users can deeplink the images again. But: the unique key is bind to this user, only he can see the right image and he’ll think all is ok. All other users will see a warning, advertising like “Hey guy, this image was deeplinked by the sites administrator, you can get the right image on http://www.domain.com” or whatever. this warning can be set up with an non-expiring header, so that the traffic will be small. Free ads, isn’t that cool? ;)

        I have tested this idea with a simple non-dynamic script (one image only, linked within the php file), it works really perfect. It’s only a lot more complicated, when you want to use it dynamic like a databased gallery, newsscript or whatever.

      • Some name says:

        That’s a pretty good solution but theres a small down, for a site with a big userbase the session managing will increase the server load quite a bit. Other than that it’s quite good, but also extremely easy to circumvent.

      • Patrick says:

        No, its not as easy to circumvent as you think. If you don’t know the real path to the images, you will never be able to circumvent this solution. Every user has a unique ip (okay, there are proxys, right… but this can be ignored). generate a unique key, use it directly in the url, bind the key to the user – no way to circumvent it.

        But in one thing you’ll be right: This solution CAN(!) increase server load. I explicitly said: You need a little bit coding skill – than you’ll know how to work without or only small increasing server load. For example: Think about Expire-Header – you don’t have to read in all images with php on each page impression. And another: its recommended for each larger site to outsource their images on another server to keep connections and server load per user small.

      • Some name says:

        All you need to circumvent this is to generate the set-cookie http header (that’s apache’s default way to store session id’s), this can be done by having an invisible iframe that simply loads the smallest page where the session is set) before loading the images, it would be maximum 10 lines of js to circumvent it… but if someone’s that dedicated to hotlink your images you should feel proud :P

      • Patrick says:

        Right, that can be possible :D But the other side of this fact is, that this is a kind of criminal activity, in germany you can demand compensation. Don’t know how this will be in other countries.

        Okay in this case youre right – but what if you DON’T use PHP-Session? It’s only _one_ way to prevent hotlinking. The other way is over the IP Address of the user. generate a unique key, store it with the visitors ip in a database. right, then you have to check the userip and unique code on every request, but THAT will be really secure. This solution should be used for downloads. The way over a session is really secure enough for images. :P

      • Patrick says:

        Hah, i’ve thought about it.

        No, theres NO way to circumvent my solution – even not when sessions are used. The image-stealer uses a unique key in the linked image url on his site, so that every other user can’t view this image. A “bypass-iframe” wouldn’t have any effect of this fact, because each user get his own unique key in the image url.

  41. Some name says:

    Hi! Nice little list of useful .htaccess features. I’d just like to point out that the hotlinking protection might be more destructive than useful as a lot of users disables the http referrer header (HTTP_REFERER (heh funny thing the common miss spelling of referrer made it’s way into the http protocol :P)) and a lot of firewalls and other applications that’s meant to keep your privacy also disables the http referrer header.

    Off topic:
    I’d like to see some SEO tutorials on here :D

  42. Nokadota says:

    Wow, can’t believe that someone really had the audacity to threaten to sue over not being able to use *someone else’s photos*. Amazing.

    Anyhoo, thanks for the tut.

  43. Webhostright says:

    Thanks, this is extremely useful, i found that mesage that was received hilarious, very cheeky but very funny, it shows how ignorant some people can be at times, either that or naive possibly.

    Thanks for the information regarding 4. especially.

  44. These are some pretty useful tips, especially with Apache being such a popular and free web server platform.

  45. Thanks for the post, I think I’ll be using the Redirect While Performing Upgrades the most.

  46. i like the number 4. but how to do this if the user type http://www.mysite.com it will redirect it to http://mysite.com many thanks.

  47. MGK says:

    Hello,

    thank you for these explanations :)

    I however have one question:

    Using a modalbox plugin (jquery for example) to open a page abc.html from a link on page index.html, I would like to know if we can use htaccess to prevent any user to open page abc.html if its not through the modalbox of page index.html ?

    like maybe something as allow 127.0.0.1 deny all ?
    i don’t even know if that’s possible.

    or maybe its in php, like with a define(”,”) but since its not an include…

    any advises ?

    thank again !

  48. MGK says:

    and also, whats the difference between

    IndexIgnore *

    and

    Options -Indexes

    ?

    • MGK says:

      forget it, I just figured it out…

      IndexIgnore * won’t redirect to an error, but won’t display anything

      whereas

      Options – Indexes will redirect to an error

      (which is quite usefull to make it look as an error for scriptkiddies)

      • Samuel says:

        There is another difference:

        On some shared hostings the use of “Options” Apache directive is forbidden.

        But on those restrictive hostings IndexIgnore is allowed.

  49. Jan says:

    Great tut. but what I’m missing here is the .htpasswd protection

Comment Page 1 of 21 2

Add a Comment

To add a code snippet to your comment, please wrap your code like so: <pre name="code" class="html">YOUR CODE</pre>. You can replace the class name with "js," "css," "sql," or "php." If there are any "<" or ">" within your code, please search and replace them with: &lt; and &gt; respectively.