mod_rewrite is a marvellous feature of the Apache Web server. It’s very flexible and can do all sorts of useful things.
mod_rewrite can be quite tricky for beginners to pick up due to its somewhat complicated syntax and processing mechanism. However, once you understand a few basic concepts then you can use mod_rewrite to do some pretty clever things with your site.
In this tutorial you’ll find out what mod_rewrite is, and the kind of things you can use it for. You’ll learn how to create a few basic mod_rewrite rules, and you’ll explore some useful real-world examples that you can use on your own website.
What is mod_rewrite?
mod_rewrite is an Apache module for manipulating (rewriting) URLs. Frequently this means taking the URL requested by a visitor and sending them content at a different URL. For example, a visitor might type the following URL into their browser:
http://www.example.com/page.html
Normally, Apache then sends back the contents of the page.html
file to the visitor. However, with mod_rewrite you can send back the contents of a different URL, such as:
http://www.example.com/another_page.html
The important thing here is that this rewriting happens inside the Apache server. The browser’s address bar still shows http://www.example.com/page.html
, but Apache sends back the content at http://www.example.com/another_page.html
:

Contrast this with HTTP redirects, which tell the browser to visit a different URL from the one requested.
As you’ll see shortly, you can also use mod_rewrite to do HTTP redirects, as well as other things such as return HTTP error codes.
Things you can do with mod_rewrite
mod_rewrite lets you create all sorts of rules for manipulating URLs. For example, you can insert values pulled from the requested URL into the new URL, letting you rewrite URLs dynamically. Or you can check server variables such as the user agent (browser), and only rewrite a URL if the browser is, say, Safari running on an iPhone.
Here are some common uses of mod_rewrite:
- Creating “friendly” URLs that map to “ugly” URLs. For example, you can map the nice-looking URL
www.example.com/articles/my-article/
to the real URL atwww.example.com/display_article.php?articleId=my-article
. Then everyone can use the friendly URL instead of the real one. - Stopping image leeching/hotlinking. To stop other sites linking to your images in their pages, you can use mod_rewrite to send back a “Forbidden” error if the referring URL isn’t on your own site.
- Redirecting to canonical URLs. Many webpages can be accessed via several URLs — for example,
www.example.com/mypage.html
andexample.com/mypage.html
. You can use mod_rewrite to always redirect browsers to the “correct” URL, such aswww.example.com/mypage.html
. Amongst other things, this ensures that only the correct URL shows up in search results. - Avoiding 404 errors when reorganizing your site. Say you’ve redone your site and moved the page at
www.example.com/myarticle.html
towww.example.com/articles/myarticle.html
. Using mod_rewrite, you can redirectwww.example.com/myarticle.html
towww.example.com/articles/myarticle.html
so that visitors don’t get 404 “not found” errors when visiting the old URL. Thanks to the flexibility of mod_rewrite, you can easily create generic rules that can map all old URLs to your new URL format.
How to use mod_rewrite
To use mod_rewrite, you create Apache directives to tell mod_rewrite what you want to do. Directives are simply configuration settings. Often you’ll put these directives in a .htaccess
file at the top level (document root) folder of your website. The directives then apply to your whole site.
The 2 most important mod_rewrite directives are:
RewriteEngine
: This turns the mod_rewrite engine off or on for the current request.RewriteRule
: This creates a rule for rewriting one URL to another.
Try this very simple example. Create the following .htaccess
file and upload it to the top level folder of your site:
RewriteEngine on
RewriteRule ^dummy.html$ http://www.google.com/ [R=301]
This file does 2 things:
RewriteEngine on
- Turns on the mod_rewrite rewriting engine.
RewriteRule ^dummy.html$ http://www.google.com/ [R=301]
- Redirects requests for the page
dummy.html
to Google, using a 301 HTTP redirect.
^dummy.html$
is a regular expression. It means: “Match the start of the URL (excluding the domain name portion), followed by the text dummy.html
, followed by the end of the URL”. If you’re new to regular expressions, here’s a good introduction.
Now open your Web browser and visit the dummy.html
URL on your site (for example, http://www.example.com/dummy.html
). If all goes well you should be redirected to http://www.google.com
.
If you get a 404 Not Found error then it’s likely that mod_rewrite hasn’t been enabled on your Web server or website. Ask your hosting company if they can turn it on for you.
How RewriteRule
works
You use the RewriteRule
directive to create rewriting rules. The general syntax of the directive is:
RewriteRule Pattern Substitution [Optional Flags]
Pattern
is a regular expression pattern. If a URL matches this pattern, the rule is processed. Otherwise, the rule is skipped.Substitution
is the new URL to use instead of the matched URL.[Optional Flags]
are one or more flags that let you alter the behaviour of the rule. More on flags later.
You can add as many RewriteRule
lines as you like to your .htaccess
file. mod_rewrite works through the rules one at a time, processing any rules that match the requested URL.
If a rule rewrites the requested URL to a new URL, that new URL is then used from that point onward in the .htaccess
file, and might be matched by another RewriteRule
further down the file. (If you don’t want this to happen you can use the L
(“last”) rule, described in a moment.)
A few mod_rewrite examples
There’s a lot more to mod_rewrite than the simple example just shown. The easiest way to explain mod_rewrite is by looking at a few practical examples, which you’ll do in the following sections.
Example 1: Avoiding 404 errors
Occasionally you might change the URL of a page on your site. This can happen if you’re reorganizing your content. However, what if search engines and other sites have linked to your old URL? Visitors will see a “404 Not Found” error if they follow these links.
To solve this problem, you can use mod_rewrite to issue a 301 redirect. This sends an HTTP header to any browser requesting the old URL, telling them that the page has moved permanently to the new URL. This also tells search engines to update their index with the new URL.
The following .htaccess
file will redirect an old URL to a new one:
RewriteEngine on
RewriteRule ^my-old-url.html$ /my-new-url.html [R=301,L]
The RewriteRule
works like this:
^my-old-url.html$
- The regular expression that will match the URL to rewrite. This pattern means: “Match the start of the URL (
^
), followed by the text'my-old-url.html'
, followed by the end of the URL ($
)”. /my-new-url.html
- The second part of the
RewriteRule
is the URL that you want to use instead. In this case, this is simply/my-new-url.html
. [R=301,L]
- The third, optional part of a
RewriteRule
is one or more flags, separated by commas and surrounded by square brackets. These flags let you add specific options and actions to the rule. In this case there are 2 flags:R=301
means “issue a 301 redirect to the new URL”, andL
means “last rule” — in other words, “stop processing if this rule matched the requested URL”.
With regular expressions, a dot (.
) means “match any character”. So, to explicitly match the dot in 'my-old-url.html'
, you need to place a backslash () before the dot to escape it, as shown in the regular expression above.
Example 2: Creating friendly URLs
Say you’ve written a PHP script, display_article.php
, to display articles on your site. You might view an article by using the following URL:
http://www.example.com/display_article.php?articleId=my-article
This URL looks pretty ugly, and the query string within it (?articleId=my-article
) can confuse some search engines. A much nicer URL would be:
http://www.example.com/articles/my-article/
You can use mod_rewrite to rewrite the first URL format to the second. To do this, simply add the following .htaccess
file to the top-level folder of your site:
RewriteEngine on
RewriteRule ^articles/([^/]+)/?$ display_article.php?articleId=$1 [L]
The RewriteRule
line works as follows:
^articles/([^/]+)/?$
- This regular expression matches any URL in the format
articles/(article ID)/
. It reads: “Match the start of the URL (^
), followed by the textarticles/
, followed by 1 or more characters that aren’t slashes([^/]+)
, followed by an optional slash(/?)
, followed by the end of the URL($)
.”Note the parentheses around the
[^/]+
part of the pattern. These tell Apache to store the text that matches this subpattern — for example,"my-article"
— for later use. display_article.php?articleId=$1
- This tells Apache to run the
display_article.php
script, passing in the text that matched the[^/]+
subpattern in the regular expression (e.g."my-article"
) as thearticleId
parameter.$1
is called a backreference — it stores the text that matched the subpattern. If your regular expression contained another subpattern inside parentheses then the text that matched the second subpattern would be stored in$2
, and so on. [L]
- As you saw in the previous example, this flag tells mod_rewrite to stop processing if this rule matched the requested URL. Generally this is a good idea, unless you want the URL to be rewritten further by other
RewriteRule
s later in the.htaccess
file.
So the above RewriteRule
takes a requested URL in the format http://www.example.com/articles/my-article/
and serves up the content at the URL http://www.example.com/display_article.php?articleId=my-article
instead.
Example 3: Preventing hotlinking to images
Another common use of mod_rewrite is to stop other websites linking to images on your own site. Say you have a page on your site, http://www.example.com/mypage.html
, that contains the following img
tag:
<img src="myphoto.jpg" alt="My Photo" />
Another site might then link directly to your photo with the following tag on their page:
<img src="http://www.example.com/myphoto.jpg" alt="My Photo" />
This means that the other site is not only “borrowing” your image for their page, but is also using up your server’s bandwidth to display the image on their page. If the other site gets lots of visitors then this can be a big problem!
You can use the following mod_rewrite directives to stop any site except your own from linking to your images. Place these in a .htaccess
file in the top-level folder of your site, or in a folder of images that you want to protect from hotlinking. Change example.com
to your site’s domain name.
RewriteEngine on
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http://(www.)?example.com/.*$ [NC]
RewriteRule .+.(gif|jpg|png)$ - [F]
Once you’ve done this, any browser requests for an image on your site where the referring URL starts with a domain other than www.example.com
or example.com
will be rejected with a “403 Forbidden” error, resulting in no image being displayed on the linking page (and hardly any of your bandwidth being used).
Here’s how this set of rules works:
RewriteEngine on
- Turns on the mod_rewrite rewriting engine.
RewriteCond %{HTTP_REFERER} !^$
RewriteCond
is another mod_rewrite directive. It allows you to set up a condition that must be true for the followingRewriteRule
to be processed. ThisRewriteCond
directive reads: “If theHTTP_REFERER
server variable is not empty”.RewriteCond %{HTTP_REFERER} !^http://(www.)?example.com/.*$
[NC]- This second
RewriteCond
directive reads: “IfHTTP_REFERER
doesn’t start withhttp://www.example.com/
orhttp://example.com/
“. The[NC]
flag makes the match case-insensitive.If either of these 2
RewriteCond
conditions fail, the followingRewriteRule
is skipped. RewriteRule .+.(gif|jpg|png)$ - [F]
- The actual rewriting rule uses the
[F]
flag to send back a “403 Forbidden” error if the URL contains an image filename (that is, a filename ending in.gif
,.jpg
or.png
). The-
(hyphen) for theSubstitution
parameter means “don’t rewrite the URL to another URL”.
So the whole .htaccess
file reads: “If HTTP_REFERER
isn’t empty, and HTTP_REFERER
doesn’t start with http://example.com/
or http://www.example.com/
, and the requested URL contains an image filename, reject the request with a ‘403 Forbidden’ error”.
Summary
This article introduced you to Apache’s mod_rewrite module for manipulating URLs. You looked at how mod_rewrite works, and what you can do with it. You saw how to create mod_rewrite rules using the RewriteRule
directive, and how to do conditional rewriting with the RewriteCond
directive. Along the way, you looked at 3 practical examples of mod_rewrite:
- 301 redirects
- Creating friendly URLs, and
- Stopping image hotlinking.
This tutorial has just scratched the surface of mod_rewrite. If you want to find out more about what mod_rewrite can do, check out the official documentation. Have fun!
Hi Matt,
thank you for writing this introduction. After reading over a dozen tutorials on .htaccess and mod_rewrite, this is the first that’s able to explain it in clear, normal language.
rgds, Eric
Thanks for your kind words Eric. I’m glad you found the article easy to follow. 🙂
Matt
Hello Matt,
I love this tutorial, so easy to understand. I also have read tutorials on mod_rewrite else where, but you make it perfectly clear.
Thanks again, Joe
Thanks Joe. It’s great to know that this article is helping so many people!
thanks joe, nice introduction;
but… i still have no idea how could i do the following:
a rewrite from subdird.domain.ltd internaly to domain.ldt/index.php ?
so lets say the structure looks like this on my hosting:
/root_www/index.php (we want to rewrite from 3th lvl domain to this)
/subdird/
so when i access in browser subdir.domain.ltd/ it rewrites internaly to domain.ltd/index.php
anyone can help plz?
@webperfection: Something like this perhaps?
well… life would be 2 easy and boring with solution like that 🙂
the thing is that if i enter my 3th lvl domain
3th.domain.ltd
its “impossible” to get out of there
/ == 3th.domain.ltd
with absolute path i cant access anything
cant use ../ ether
once more the folder structure used:
/www_root/index.php (doc root)
/3th/some.html (so to root i tough i can get like ../www_root/ which is impossible)
so following wont help me 🙁
RewriteRule ^/?$ /root_www/index.php [L]
coz / is already /var/www/domain/3th/
as i was despaired with no solution i asked my provider to set vhost serveralias to *.domain
and i had to wrote my own php router for everything :/
so my final question would be: is it apache config related problem or just my lack of experience with mod_rewrite?
thx for replay
@webperfection: Sounds like more of an issue with your virtual server. If your apache can’t address the path of the site you want to redirect to then there’s not much it can do (apart from a 301/302 redirect).
Hello, Matt
I registered here only to express how grateful I am for you tutorial. I found it very helpful.
The official documentation was too difficult to read for me as an introduction, in other tutorials the processing of the directives wasn’t explained clearly enough.
It was a pleasure to read your tutorial. Really well-written. I didn’t have to read anything more than once 🙂
Really, really grateful and delighted to be finally able to use mod_rewrite,
Michael
[Edited by highlyFlammable on 26-Sep-11 18:30]
@highlyFlammable: Thanks for your feedback! I’m really pleased you found the tutorial useful. 🙂
Hi! i just did cms with images and categories and works great, i just want to change urls and i just can’t, like this:
http://ww.ex.com/?action=viewArticle&articleId=14
to
http://ww.ex.com/article/14
I had tried this:
but no success.
Can your help me please?
It’s probably the misspelling of ‘article’.
Negative, Sir. I am in the same boat as Tom. I tried it using;
RewriteRule ^articles/([^/]+)/?$ .?action=viewArticle&articleId=$1 [L]
and was not able to get the desired result. Is there something we are missing?
Thank you for your help!
i created my website by looping my index.php file and doing so it allows me to hook all my webages via anchor link.
The method i used to link my age is as follows:
<a href=”?page=contact”>Contact</a>
and therefore this produce the output of index.php?page=contact but as i use mod_rewrite rule it only remove index.php, hence i get left with link for example: http://www.mysite.com/?page=contact.
My request now is how can i overcome this kind of problem am currently facing as i have tried to couple php with mod_rewrite to solve this but didnt get any solution.
First off, this
<a href=”?page=contact”>Contact</a>
Is a self-referential URL, and will always point to the URL the browser is currently on.
So if you re-write yoursite.tld/contact/, the self referencing link will become yoursite.tld/contact/?page=contact which will result in a 404 response
You need a ‘/’ in the href to make the link root relative.
“… … as i have tried to couple php with mod_rewrite”
What does that even mean?????
PHP and .htaccess directive are NOT connected in any way at all. .htaccess directives operate at the level of the physical folder structure and are complete before PHP even starts up.
[Edited by chrishirst on 22-Feb-17 16:33]
I needed a “first 5-minutes introduction” and you nailed it! Thanks a lot for sharing your knowledge!
You’re welcome – glad it helped 🙂
Hey, Matt. Great Tut. Having a bit of an issue with the clean URL string in .htaccess. I am using the following:
But not getting the desired change in the URL. Can you assist?
Thank you for your time!
I tried this:
RewriteRule ^blog/([^/]+)/?$ .?action=viewArticle&articleId=$1 [L]
but no go. I can’t seem to make this work, no matter what I try. What’s the secret sauce?
This is still useful after over a decade. Excellent.
I’ve been using rewrite rules for years, but this tutorial clarified the basic ideas for me. Thank you! Some questions: 1. once all the rules in the htaccess file have been executed, is the resulting URL used to return the request result to the browser, or are the rules executed in a loop until no rewrite occurs before the result is returned from the server? 2. is there a way to set a variable to true or false, then use that variable to end rewriting early? 3. is there any simple way to debug rewrite rules, such as rewriting to a PHP file that displays variable values? 4. could you please write a second tutorial that assumes what you’ve presented here, then goes on to more complex situations (when you have time, of course)?
One very common situation is to ensure that the user has included “https” and “www” in the URL (maybe someday they will both be assumed, for simplicity). I tried including my code here, but your spam prevention disallowed it.
Hi Matt, thank you for this article, it is helping me to understand how I might resolve an issue I’m having, but I’m not quite there yet. I have a website that has an Accessibility button for setting the contrast. When that button is presed, it changes the url from the incoming requestor ( https://x.y.z/page.aspx/login?ReturnURL=%2Page etc ) to the server IP local host address (xx.xx.xx.xx.:/page.aspx/en/usr/login/?ReturnUrl=%2fpage.aspx….%2fhomepage).. and the Accessibility Conrast Change does not work. Can I use the Rewrite to go back to the originating Url after the Accessibility Feature button has been selected ? Thank you, joe
Hi, and thanks for an introduction that is well-written!
I suspect that
(www.)
should read(www\.)
or please explain why not, thanks!