Apache Mod_rewrite
The Apache mod_rewrite module is a powerful and versatile tool for manipulating web page URLs. It allows you to rewrite requested URLs on the fly, redirecting them to different URLs or serving different content based on a set of rules. This can be incredibly useful for search engine optimization (SEO), user-friendly URLs, security, and website maintenance.
How mod_rewrite works:
At its core, mod_rewrite works by comparing incoming URL requests against a series of rules you define in your server configuration or, more commonly, in an .htaccess file within your website’s directory. When a request matches a rule’s pattern, mod_rewrite can alter the URL or redirect the request.
Here are the key components you’ll encounter:
- RewriteEngine On: This directive is essential and must be present to enable the rewriting engine. Without it, none of your rules will be processed.
- RewriteCond (Rewrite Condition): This directive defines a condition that must be met for the subsequent
RewriteRuleto be applied. You can have multipleRewriteConddirectives, and by default, they all must be true for the rule to be executed. - RewriteRule: This is the actual rule that does the rewriting. It consists of a pattern to match against the requested URL, a substitution string (the new URL or path), and optional flags that modify the rule’s behavior.
- Flags: These are appended to
RewriteRuledirectives and control how the rule is interpreted and processed. Common flags include:[L](Last): If this rule matches, no further rules will be processed.[R](Redirect): Issues an HTTP redirect to the browser. You can specify a status code like[R=301]for a permanent redirect or[R=302]for a temporary one.[NC](No Case): Makes the pattern matching case-insensitive.[OR]: Used with multiple RewriteCond directives to specify that if *this* condition OR the *next* condition is true, the rule should be applied.[PT](Pass Through): Passes the rewritten URL back to Apache for further processing by other modules (like mod_alias).
The mod_rewrite engine processes rules in the order they appear in the .htaccess file. When a URL comes in, mod_rewrite checks it against each rule. If a rule matches and has the [L] flag, processing stops for that request. If not, it continues down the list.
Common mod_rewrite Examples:
Let’s explore some practical examples you can use on your website. These rules are typically placed in an .htaccess file in your website’s root directory (e.g., public_html).
1. URI redirect on the same domain
Sometimes you might want to redirect an old page to a new page on the same website. For example, changing /old-page.html to /new-page.html.
RewriteEngine On
RewriteRule ^old-page.html$ /new-page.html [R=301,L]
^old-page.html$: This is the pattern.^asserts the start of the URI (the part after your domain name).old-page.htmlmatches “old-page.html” literally. The backslashescapes the dot, so it’s treated as a literal dot and not a special character meaning “any character”.$asserts the end of the URI.
/new-page.html: This is the substitution string – the new URI to which the user will be redirected.[R=301,L]:R=301tells the browser and search engines that this is a permanent redirect.Lmeans if this rule matches, no other rewrite rules below it will be processed.
2. Non-WWW to WWW redirect
It’s generally good practice for SEO to have a canonical version of your domain (either with “www” or without it). This example redirects requests for example.com to www.example.com.
RewriteEngine On
RewriteCond %{HTTP_HOST} ^example.com [NC]
RewriteRule ^(.*)$ http://www.example.com/$1 [L,R=301]
RewriteCond %{HTTP_HOST} ^example.com [NC]: This is the condition.%{HTTP_HOST}is a server variable containing the hostname requested by the browser.^example.comchecks if the hostname starts with “example.com”.[NC]makes this check case-insensitive.
RewriteRule ^(.*)$ http://www.example.com/$1 [L,R=301]: This is the rule.^(.*)$matches the entire requested URI and captures it in the$1backreference.http://www.example.com/$1is the new URL, prepending “www.” and appending the captured URI.[L,R=301]ensures it’s a permanent redirect and no other rules are processed.
Note: Replace example.com with your actual domain name.
3. HTTP to HTTPS redirect
Forcing all traffic over HTTPS is crucial for security. This rule redirects all HTTP requests to their HTTPS equivalent.
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
RewriteCond %{HTTPS} off: This condition checks if the connection is not already using HTTPS (%{HTTPS}server variable will be “off”).RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]:^(.*)$matches the entire requested URI.https://%{HTTP_HOST}%{REQUEST_URI}constructs the new HTTPS URL.%{HTTP_HOST}is the domain name (e.g., www.example.com or example.com).%{REQUEST_URI}is the path and query string of the requested URL (e.g., /some-page.html?query=test).
[L,R=301]ensures it’s a permanent redirect and no other rules are processed.
Many hosting control panels (like cPanel or Plesk) offer a feature to enforce HTTPS, which might be an easier alternative to manually editing your .htaccess file.
4. Basic WordPress rewrite
WordPress uses mod_rewrite to create its “pretty permalinks” (e.g., example.com/my-blog-post/ instead of example.com/index.php?p=123). The standard WordPress rules in your .htaccess file look like this:
# BEGIN WordPress
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^index.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
# END WordPress
Let’s break it down:
# BEGIN WordPressand# END WordPress: These are comments. WordPress uses them to identify and manage its block of rewrite rules. You shouldn’t manually edit rules between these lines if you want WordPress to manage them.RewriteEngine On: Enables the rewrite engine.RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]: This rule is primarily for passing HTTP Authorization headers, sometimes used for password-protected sites.RewriteBase /: Specifies that the base URL for per-directory rewrites is the root directory (/). If your WordPress installation is in a subdirectory (e.g.,example.com/blog/), this would be/blog/.RewriteRule ^index.php$ - [L]: If the request is directly forindex.php, this rule tells mod_rewrite to stop processing and serveindex.phpdirectly. The hyphen (-) means no substitution.RewriteCond %{REQUEST_FILENAME} !-f: This condition checks if the requested URL is not an existing file (!-f).RewriteCond %{REQUEST_FILENAME} !-d: This condition checks if the requested URL is not an existing directory (!-d).RewriteRule . /index.php [L]: If both of the above conditions are true (meaning the request is not for an existing file or directory), then this rule rewrites the request to/index.php. WordPress’sindex.phpthen handles the “pretty URL” and figures out what content to display. The.(dot) matches any single character (effectively meaning any request that hasn’t been handled yet).
Essentially, these rules ensure that if a requested URL doesn’t point to an actual file or directory on your server, the request is passed to WordPress’s main index.php file, which then parses the URL to display the correct page or post.
5. Blocking access by IP address
You can use mod_rewrite to block requests from specific IP addresses. This can be useful for mitigating malicious activity.
RewriteEngine On
RewriteCond %{REMOTE_ADDR} ^192.168.1.100$ [OR]
RewriteCond %{REMOTE_ADDR} ^10.0.0.5$
RewriteRule ^(.*)$ - [F,L]
RewriteCond %{REMOTE_ADDR} ^192.168.1.100$ [OR]: This condition checks if the visitor’s IP address (%{REMOTE_ADDR}) is exactly192.168.1.100. The[OR]flag means if this condition is true OR the next one is true, the rule applies.RewriteCond %{REMOTE_ADDR} ^10.0.0.5$: This condition checks if the visitor’s IP address is10.0.0.5.RewriteRule ^(.*)$ - [F,L]: If either of the conditions is met:^(.*)$matches any requested URL.-means no substitution.[F](Forbidden): Sends a 403 Forbidden response to the client.[L](Last): No further rules are processed.
Note: While mod_rewrite can do this, for extensive IP blocking, using firewall rules at the server level (e.g., via iptables or a firewall like CSF) is often more efficient.
6. Preventing image hotlinking
Hotlinking is when other websites display images hosted on your server directly, consuming your bandwidth. This rule prevents that by checking the referrer.
RewriteEngine On
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http(s)?://(www.)?example.com [NC]
RewriteRule .(jpg|jpeg|png|gif)$ - [NC,F,L]
RewriteCond %{HTTP_REFERER} !^$: This condition ensures there is a referrer. If someone is directly accessing the image by typing its URL in the browser, the referrer will be blank, and we want to allow that. The!means “not”.RewriteCond %{HTTP_REFERER} !^http(s)?://(www.)?example.com [NC]: This condition checks if the referrer is NOT your own domain (example.comorwww.example.com, with or without https).RewriteRule .(jpg|jpeg|png|gif)$ - [NC,F,L]: If both conditions are true (i.e., there is a referrer, and it’s not your own site), this rule applies to any request ending in.jpg,.jpeg,.png, or.gif.[NC]makes the image extension matching case-insensitive.[F,L]sends a 403 Forbidden response and stops further processing.
You can replace the [F,L] with a rule to show a specific “don’t hotlink” image instead, for example: [NC,R=/images/dont-hotlink.jpg,L]
Important considerations
- Backup your
.htaccessfile: Before making any changes, always create a backup of your existing.htaccessfile. A small syntax error can make your entire website inaccessible. - Test thoroughly: After adding or modifying rules, test your website extensively to ensure everything works as expected. Check different pages, links, and functionalities.
- Order matters: The order of your rewrite rules is crucial. mod_rewrite processes them from top to bottom. A rule with the
[L]flag will stop further processing for that request. - Performance: While powerful, overly complex
.htaccessfiles with many rules can slightly impact server performance because the file is read and parsed for every request. For high-traffic sites, moving rules to the main server configuration file (if you have access) can be more efficient, but.htaccessoffers more convenience and per-directory control. - Debugging: Debugging mod_rewrite can be tricky. You can enable rewrite logging (
RewriteLogandRewriteLogLeveldirectives in your Apache configuration if you have server access) to see how rules are being processed. However, this is typically done at the server configuration level, not within.htaccess.
The mod_rewrite module offers a vast range of possibilities for URL manipulation. The examples above cover some of the most common use cases. By understanding the basic syntax and logic, you can tailor these rules to your specific needs or create new ones to further enhance your website.