mod_rewrite is an Apache module that rewrites requested URLs on the fly using a rule-based engine powered by PCRE regular expressions. It maps URLs to filesystem paths, redirects URLs to new locations, or triggers internal proxy fetches. For SEO practitioners, this means controlling how users and search engines access your content by creating clean, readable URLs and managing 301 redirects without changing your physical file structure.
What is Mod Rewrite?
mod_rewrite is an Apache HTTP Server module (also identified as rewrite_module) that provides a flexible rewriting engine. By default, it maps a URL to a filesystem path. It can also redirect one URL to another URL or invoke an internal proxy fetch.
The module operates with an unlimited number of rules. Each rule can have an unlimited number of attached conditions based on server variables, HTTP headers, environment variables, or timestamps. It processes the full URL path, including the path-info section.
You can invoke rewrite rules in two contexts: - Server configuration (httpd.conf or VirtualHost blocks): Rules apply before the request maps to the filesystem - Per-directory configuration (.htaccess or Directory blocks): Rules apply after mapping, with the directory path stripped from the URL before pattern matching
Why Mod Rewrite Matters
- Create SEO-friendly URLs: Transform query strings like
results.php?item=shirt&season=summerinto clean paths like/shirt/summerthat users and search engines prefer. - Manage site migrations: Implement 301 permanent redirects when restructuring URLs or changing domains to preserve link equity.
- Enforce canonicalization: Force consistent URL formats by redirecting non-www to www (or vice versa) and HTTP to HTTPS.
- Control access: Block traffic from specific referrers, IP addresses, or file types before they reach your application.
- Prevent duplicate content: Remove file extensions (like .php) and index files from URLs to consolidate page versions.
How Mod Rewrite Works
The rewriting process follows a logical sequence of directives evaluated at runtime:
-
Enable the engine: Set
RewriteEngine Onto activate the module for the current context. Without this directive, no runtime processing occurs. -
Set the base path (per-directory only): Use
RewriteBaseto define the URL prefix for relative substitutions in .htaccess files. This prevents the server from looking for resources in the wrong location when the directory is not under the DocumentRoot. -
Define conditions (optional): Add
RewriteConddirectives to test variables like HTTP headers, server variables, or environment variables. Conditions support boolean AND (default) or OR logic using the[OR]flag. -
Write the rule: Create a
RewriteRulewith three components: - Pattern: PCRE regex matching the requested URL (e.g.,
^about$) - Substitution: The target path, URL, or text string (e.g.,
about.htmlorhttp://newdomain.com/$1) -
Flags: Optional modifiers in brackets (e.g.,
[R=301,L]for permanent redirect and last rule) -
Process sequentially: Apache evaluates rules in the order defined, applying substitutions to the results of previous rules until reaching the end or a termination flag like
[L](Last) or[END].
Best Practices
- Set RewriteBase in .htaccess: Always specify
RewriteBasewhen using relative paths in per-directory context unless the directory sits directly under DocumentRoot or uses Alias. This ensures substitutions resolve to the correct URL path. - Use the [L] flag: Append
[L]to rules that should terminate processing when matched. Without it, Apache continues evaluating subsequent rules, potentially causing unexpected results. - Check file existence before rewriting: Use conditions like
RewriteCond %{REQUEST_FILENAME} !-fand!-dto ensure existing files and directories remain accessible and only rewrite missing resources. - Choose 301 for permanent moves: Use
[R=301]instead of[R]to send proper HTTP 301 status codes, signaling search engines to update their indexes and transfer ranking signals. - Avoid high trace logging in production: [Using a high trace log level for mod_rewrite will slow down your Apache HTTP Server dramatically] (Apache HTTP Server Documentation). Keep logging at
trace2or lower unless actively debugging. - Prefer server config when possible: [The official Apache documentation recommends using server configuration files instead of .htaccess because Apache processes it faster] (DigitalOcean). Use .htaccess only when you lack root access or need per-directory flexibility.
Common Mistakes
- Mistake: Forgetting
RewriteEngine On. Fix: Always include this directive at the top of your .htaccess file or configuration block. The module defaults to off. - Mistake: Skipping
RewriteBasein subdirectories. Fix: You will see 404 errors for rewritten URLs. AddRewriteBase /subdirectory/to ensure relative paths resolve correctly. - Mistake: Creating infinite redirect loops. Fix: You will see "too many redirects" browser errors. Use
RewriteCond %{HTTPS} offor similar conditions to ensure rules only apply when needed, not to their own output. - Mistake: Matching against full paths in .htaccess. Fix: In per-directory context, the directory path is stripped before pattern matching. A pattern like
^/folder/will never match because the leading slash is removed. Use^folder/instead. - Mistake: Using
[R]instead of[R=301]without understanding the default. Fix: Know that[R]alone defaults to 302 (temporary) redirect, which does not pass full link equity like 301.
Examples
Migrate an entire domain: Redirects all requests from an old domain to a new domain while preserving the path structure.
RewriteEngine on
RewriteCond %{HTTP_HOST} ^www.olddomain.com$ [OR]
RewriteCond %{HTTP_HOST} ^olddomain.com$
RewriteRule ^(.*)$ http://www.newdomain.com/$1 [R=301,L]
Force HTTPS connections: Redirects HTTP requests to HTTPS using the server port as a condition.
RewriteEngine On
RewriteCond %{SERVER_PORT} 80
RewriteRule ^(.*)$ https://www.example.com/$1 [R=301,L]
Clean URL for product pages:
Transforms /shirt/summer into results.php?item=shirt&season=summer using regex backreferences.
RewriteRule ^([A-Za-z0-9]+)/(summer|winter|fall|spring)$ results.php?item=$1&season=$2 [QSA]
The [QSA] flag appends any additional query parameters to the rewritten URL.
Remove file extensions: Allows accessing files without typing .php while retaining functionality.
RewriteCond %{THE_REQUEST} ^GET\ (.*)\.php\ HTTP
RewriteRule (.*)\.php$ $1 [R=301,L]
FAQ
What is the difference between mod_rewrite and standard redirects? Standard redirects (like Redirect directive) perform simple URL-to-URL mapping. mod_rewrite offers conditional logic based on headers, variables, or file existence, plus regex pattern matching for dynamic substitutions.
Can I use mod_rewrite without .htaccess? Yes. You can place rules directly in Apache configuration files (httpd.conf or VirtualHost blocks). In fact, this approach offers better performance and security, though it requires server restart and root privileges to modify.
Why are my rewrite rules causing "too many redirects" errors?
This happens when a rule matches its own output, creating a loop. Add conditions to check the current state before rewriting, such as verifying %{HTTPS} is off before redirecting to HTTPS, or checking if the file already exists.
How do I test if mod_rewrite is working?
Create a simple rule in your .htaccess file like RewriteRule ^test$ /testpage.html [L] and try accessing /test. If you see the content of testpage.html, the module is active. You can also check Apache error logs with trace levels enabled, though remember to disable high trace levels in production.
What is the difference between [R] and [R=301] flags?
[R] defaults to a 302 temporary redirect, telling browsers and search engines the move is temporary. [R=301] sends a 301 permanent redirect status, which search engines use to transfer ranking signals to the new URL.
When should I use RewriteCond? Use RewriteCond when a rule should only apply under specific circumstances, such as specific user agents, certain times of day, or when specific files do not exist. It acts as a filter before the RewriteRule executes.