Writing SEO Friendly URLs using .htaccess


Everybody wants SEO-friendly URLs for their websites, but it isn’t always as easy as it seems.

Despite the tons of examples and docs, mod_rewrite is voodoo. Damned cool voodoo, but still voodoo.
— Brian Moore

SEO, URL, htaccess


So if you’re looking to rewrite your URLs, either to make it easier for users to remember or to help your Search Engine Optimization, here’s some help.

Start Right – the Basics

You’ll need to start with a file called “.htaccess”. Nothing more. It isn’t “code.htaccess” or “smile.htaccess”, just “.htaccess”. It’s easiest to edit the file in a simple text program like Notepad. If you try to edit it in Dreamweaver, keep in mind that you’ll need to right-click the file and choose “Open with… Dreamweaver” to get it to open it.

Next you need to put the following in the top of your file:

RewriteEngine On
RewriteOptions inherit
Options +FollowSymlinks
Options -Multiviews

The first line turns the RewriteEngine on, which is pretty self-explanatory.

If you’re using a virtual host (not your own dedicated host), make sure you add the second line.

I’ve found varied opinions on the third line. Some people say you should use it, some people not. I use it, mainly because lots of people say your file won’t work without it. Voodoo…told ya.

The fourth line is VITAL if you’re using Godaddy (or I’m assuming most virtual hosts) you’ll HAVE to have this line for some of the coding to work.

And, if you’re starting from a folder, add:

RewriteBase /new

where “/new” is the subfolder your website is located in.

External Redirect

When we say “external redirect” we mean that we’re actually changing what the URL looks like in the browser bar. So if you type in “http://mywebsite.com/deal.php” the following code makes the URL “http://mywebsite.com/deal”. This is the first step, you’ll need both the external and internal redirects to make this work (otherwise the computer will be looking for /deal which doesn’t exist).

In .htaccess, you use a “#” sign to comment text out. So the first two lines below are just comments.

## hide .php extension
## To externally redirect /dir/foo.php to /dir/foo
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{THE_REQUEST} ^[A-Z]{3,}s([^.]+).php [NC]
RewriteRule ^ %1 [R,L,NC]

Line 3 and 4 and 5 are all conditions. .htaccess thrives on conditions. We’re checking to see if the URL we put in isn’t a file or isn’t a directory, AND it ends with .php (NC= not case sensitive), then we rewrite it in line 6.

If you want to figure out each individual sign in the coding above, a quick google search will explain each one.

The main ones you should know are these:

^ = indicates the start

$ = indicates the end of the URL (the first portion, the one we’ll want to change)

. = a period has a different meaning in .htaccess, so to actually MEAN a period, you need to put a backward slash in front of it (line 5 at the end, above)

[R,L,NC] = This is additional information for the file

[R] = redirect (external)

[L] = Last part of these rules – for example, the conditions above end at line 6, and anything after that will not be subject to those conditions.

[NC] = Not Case-sensitive

Also, you should know that .htaccess file creates variables automatically, numerically – so it will automatically create $1, $2, $3, according to the coding. You’ll need to know this as we go to the next section.

Internal Forwards

Internal Forwards deal with making the URL that look like this “http://mywebsite.com/deal” and making the computer actually fetch this “http://mywebsite.com/deal.php”.

If you use the external and internal forwards together, it effectively makes your URL SEO friendly.

## To internally forward /dir/foo to /dir/foo.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*?)/([a-zA-Z0-9_-]+)/([0-9]+)$ /new/$1.php?ID=$3 [L]

Again, we check the file and directory in lines 2 and 3, then we start the rewrite rule.

My original URL was this:


I wanted it to be:


In the fourth line, we start the URL and then automatically create a “variable” by matching: (.*?). We create two more variables by using parenthesis. So the first variable ($1) will be “property/page”, the second will be “29021-Avenue-Sherman”, and the third will be “28394”. Remember that Rewrite Base at the beginning? That’s what makes the $1 equal to “property/page”.

NOTE: You cannot rewrite anything that isn’t originally in the URL. So I couldn’t add the address in. It must be included in the original URL to be rewritten.

Then we end that section with a “$”, do one space, and start the rewrite. This rewrite will be hidden because we don’t have a [R] at the end of it, only a [L] to end the conditionals. This new URL is what I’ll need to get the information to the page, namely the ID number of the property. I don’t need the address for my coding, but if you did, you could also add on “&address=$2” to the end of that URL.


.htaccess is complicated. There are a lot of things that can go wrong, some of which you won’t think of or even know in the beginning. But hopefully this will give you a start in accomplishing the (I’d say) most popular thing to do with .htaccess.

And a few Thanks you’s:

Anubhava for his help on my StackOverflow.com question.

Webdeskil who, although he didn’t specifically answer the question I posted, answered another one that gave me the solution.

And the other numerous other .htaccess tutorials online.

  • sultan says:


    when i am using
    Options +FollowSymLinks
    RewriteEngine on
    RewriteRule download-id-(.*)\.htm$ download.php?id=$1

    on my htaccess file, it will convert below code

    # For security reasons, Option followsymlinks cannot be overridden.
    #Options +FollowSymLinks
    Options +SymLinksIfOwnerMatch
    RewriteEngine on
    RewriteRule download-id-(.*)\.html$ download.php?id=$1

    and it’s not working to ReWrite url

    how i solve this …….. 🙁 i am trying ….
    but fail

    please help me

    • Kim Joy Fox says:

      Never seen this before, myself. I would check with your hosting provider – sounds like a server setting. Also, I’d post it on Stack Overflow if they can’t help you.