Introduction to Apache mod_rewrite
The .htaccess file is one of the most powerful tools in a WordPress administrator’s arsenal. This configuration file allows you to override server settings at the directory level, giving you granular control over URL redirections, access restrictions, and performance optimizations.
What is mod_rewrite?
mod_rewrite is an Apache module that provides a rule-based rewriting engine to rewrite requested URLs on the fly. It’s the engine behind WordPress’s pretty permalinks and is essential for modern SEO-friendly URL structures.
Key Benefits:
- SEO Preservation: Redirect old URLs to new ones without losing search rankings
- User Experience: Ensure visitors always reach the correct content
- Security: Force HTTPS and block malicious requests
- Performance: Implement caching headers and compression
When to Use 301 vs 302 Redirects
Understanding HTTP status codes is crucial for proper SEO implementation:
| Redirect Type | Use Case | SEO Impact |
|---|---|---|
| 301 Permanent | Content moved permanently, domain changes, HTTPS migration | Passes 90-99% link equity, search engines update index |
| 302 Found | Temporary maintenance, A/B testing, short-term content moves | No link equity passed, original URL remains indexed |
| 307 Temporary | Strict HTTP/1.1 temporary redirect, POST data preservation | Same as 302 but preserves HTTP method |
| 308 Permanent | Strict HTTP/1.1 permanent redirect, POST data preservation | Same as 301 but preserves HTTP method |
Golden Rule: If the change is permanent, always use 301. Using 302 for permanent moves can significantly hurt your SEO rankings.
Common Redirect Scenarios
1. Single Page Redirects
The simplest form of redirection moves one specific URL to another:
# Redirect a single page (simple syntax)
Redirect 301 /old-page.html https://www.domain.com/new-page.html
# Alternative using RewriteRule
RewriteEngine on
RewriteRule ^old-page\.html$ /new-page.html [R=301,L]
When to use each:
- Use
Redirect 301for simple, exact URL matches - Use
RewriteRulewhen you need pattern matching or conditions
2. Entire Site Redirection
Moving your entire website to a new domain requires careful handling:
# Redirect entire site to new domain
Redirect 301 / https://www.newdomain.com/
# Preserve full URL structure
RewriteEngine on
RewriteBase /
RewriteRule (.*) https://www.newdomain.com/$1 [R=301,L]
Important: Always test with a few URLs first before implementing site-wide redirects.
3. Subfolder to Root (or vice versa)
Common when restructuring content:
# Redirect entire site to a subfolder
Redirect 301 / https://www.domain.com/subfolder/
# Redirect subfolder to another site
Redirect 301 /subfolder https://www.domain.com/
# Using RewriteRule with full path preservation
RewriteEngine on
RewriteRule ^subfolder/(.*)$ /$1 [R=301,L]
4. File Extension Changes
When migrating from .html to .php or implementing pretty permalinks:
# Redirect .html to .php
RedirectMatch 301 (.*)\.html$ https://www.domain.com$1.php
# Remove .php extension (make URLs cleaner)
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^\.]+)$ $1.php [NC,L]
5. Force HTTPS (SSL)
Essential for security and SEO:
# Force HTTPS - Method 1 (simple)
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
# Force HTTPS - Method 2 (with www handling)
RewriteEngine On
RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} !^www\.
RewriteRule ^(.*)$ https://www.domain.com/$1 [L,R=301]
6. Force www or non-www
Consistency in URL structure matters for SEO:
# Force www
RewriteEngine on
RewriteCond %{HTTP_HOST} ^domain.com [NC]
RewriteRule ^(.*)$ https://www.domain.com/$1 [L,R=301]
# Force non-www (naked domain)
RewriteEngine on
RewriteCond %{HTTP_HOST} ^www\.domain\.com [NC]
RewriteRule ^(.*)$ http://domain.com/$1 [L,R=301]
Advanced Rewrite Rules
Query String Redirects
Handling URLs with parameters requires special attention:
# Redirect specific query parameter
RewriteEngine on
RewriteCond %{QUERY_STRING} id=1
RewriteRule ^index.php$ /path-to-new-location/? [R=301,L]
# Redirect with query string preservation
RewriteEngine On
RewriteCond %{QUERY_STRING} ^category=([^&]+)
RewriteRule ^index.php$ /category/%1/? [R=301,L]
# Remove query strings entirely
RewriteEngine On
RewriteCond %{QUERY_STRING} .
RewriteRule ^$ /? [R=301,L]
Note: The trailing ? in the destination URL strips the original query string.
Pattern Matching with Regex
Regular expressions provide powerful pattern matching:
# Redirect date-based URLs
RewriteEngine On
RewriteRule ^blog/([0-9]{4})/([0-9]{2})/(.+)$ /news/$1/$2/$3 [R=301,L]
# Redirect with wildcards
RewriteEngine On
RewriteRule ^products/(.*)$ /shop/$1 [R=301,L]
# Multiple pattern matches
RewriteEngine On
RewriteRule ^(blog|news|articles)/(.+)$ /content/$2 [R=301,L]
Domain Change with Path Preservation
When migrating to a completely new domain:
# Old domain to new domain with full path
RewriteEngine On
RewriteCond %{HTTP_HOST} ^old-domain.com$ [OR]
RewriteCond %{HTTP_HOST} ^www.old-domain.com$
RewriteRule (.*)$ https://www.new-domain.com/$1 [R=301,L]
# With subdirectory adjustment
RewriteEngine On
RewriteCond %{REQUEST_URI} ^/blog/(.*)$
RewriteRule ^(.*)$ https://www.newdomain.com/news/%1 [R=301,L]
Testing Redirects Safely
Before Going Live
- Use 302 Temporary First: Test with 302 redirects before making them permanent
- Check Redirect Chains: Ensure you’re not creating redirect loops
- Test Multiple Scenarios: Check with and without www, HTTP and HTTPS
- Validate with Tools: Use online redirect checkers
Testing Methods
# Using curl to check headers
curl -I http://yourdomain.com/old-page
# Follow redirects with curl
curl -L http://yourdomain.com/old-page
# Check specific status codes
curl -I -L http://yourdomain.com/old-page 2>&1 | grep HTTP
Online Testing Tools
- Redirect Checker: httpstatus.io
- HTTP Status: httpstatus.io
- Google Search Console: Check for crawl errors after implementation
Troubleshooting Redirect Loops
Common Causes
- Circular References: Rule A redirects to B, Rule B redirects back to A
- Protocol Mismatches: HTTP rule conflicting with HTTPS forcing
- WWW Conflicts: www and non-www rules fighting each other
- WordPress Conflicts: Plugin redirects conflicting with .htaccess
Diagnosis Steps
# Add this temporarily to see what's happening
RewriteEngine On
RewriteLog "/var/log/apache2/rewrite.log"
RewriteLogLevel 3
Note: This requires server-level access and should be removed after debugging.
Solutions
# Prevent loops by checking if already redirected
RewriteEngine On
RewriteCond %{ENV:REDIRECT_STATUS} 200
RewriteRule ^ - [L]
# Specific protocol handling to avoid loops
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
Performance Impact of .htaccess Rules
Understanding the Cost
Every RewriteRule adds processing overhead:
- Simple Redirects: Minimal impact (< 1ms)
- Complex Regex: Moderate impact (1-5ms per rule)
- Multiple Conditions: Cumulative impact (5-20ms+)
Optimization Best Practices
- Order Matters: Place most frequently matched rules first
- Use Specific Patterns: More specific patterns are faster
- Limit Regex Complexity: Avoid greedy quantifiers where possible
- Consider Server-Level Config: For high-traffic sites, use httpd.conf instead
# Optimized ordering example
RewriteEngine On
# Most common redirects first
RewriteRule ^wp-admin$ /wp-admin/ [R=301,L]
# Then specific patterns
RewriteRule ^old-product/(.*)$ /shop/$1 [R=301,L]
# Generic patterns last
RewriteRule ^blog/(.*)$ /news/$1 [R=301,L]
Caching Considerations
# Enable mod_expires for better caching
<IfModule mod_expires.c>
ExpiresActive On
ExpiresDefault "access plus 1 month"
</IfModule>
# Enable compression
<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE text/html text/css application/javascript
</IfModule>
WordPress-Specific Considerations
Integration with WordPress Rewrite Rules
WordPress uses its own rewrite rules in .htaccess. Always place custom rules before the WordPress block:
# BEGIN Custom Redirects
RewriteEngine On
# Your custom rules here
# END Custom Redirects
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
Common WordPress Redirect Scenarios
# Redirect attachment pages to parent post
RewriteEngine On
RewriteRule ^attachment/(.*)$ / [R=301,L]
# Redirect author archives to homepage
RewriteEngine On
RewriteRule ^author/(.*)$ / [R=301,L]
# Redirect category archives to specific page
RewriteEngine On
RewriteRule ^category/old-category$ /new-section/ [R=301,L]
Security Considerations
Protecting Sensitive Files
# Block access to sensitive WordPress files
<FilesMatch "^\.">
Order allow,deny
Deny from all
</FilesMatch>
# Protect wp-config.php
<Files wp-config.php>
order allow,deny
deny from all
</Files>
# Block access to .htaccess itself
<Files .htaccess>
order allow,deny
deny from all
</Files>
Blocking Malicious Requests
# Block SQL injection attempts
RewriteCond %{QUERY_STRING} (<|%3C).*script.*(>|%3E) [NC,OR]
RewriteCond %{QUERY_STRING} GLOBALS(=|\[|\%[0-9A-Z]{0,2}) [OR]
RewriteCond %{QUERY_STRING} _REQUEST(=|\[|\%[0-9A-Z]{0,2})
RewriteRule ^(.*)$ index.php [F,L]
Complete Reference: Redirect Types
Simple Redirect Syntax
# Basic 301 redirect
Redirect 301 /old /new
# 302 temporary redirect
Redirect 302 /maintenance /temp-page
# Redirect with full URL
Redirect 301 /page http://example.com/new-page
RedirectMatch Syntax
# Pattern-based redirect
RedirectMatch 301 ^/blog/(.*)$ http://example.com/news/$1
# Case-insensitive
RedirectMatch 301 (?i)^/old-folder/(.*)$ /new-folder/$1
RewriteRule Syntax
# Basic structure
RewriteRule Pattern Substitution [Flags]
# Common flags:
# [R=301] - Permanent redirect
# [R=302] - Temporary redirect
# [L] - Last rule (stop processing)
# [NC] - No case (case-insensitive)
# [QSA] - Query string append
# [NE] - No escape
FAQ
Q: Why are my redirects not working? A: ‘Common causes include: mod_rewrite not enabled, .htaccess not allowed in Apache config, syntax errors, or conflicting rules. Check your Apache error logs for details.’
Q: How do I redirect without losing SEO value?
Q: Can I redirect based on user agent?
RewriteCond %{HTTP_USER_AGENT} ^Mozilla.*
RewriteRule ^(.*)$ /mobile-version/$1 [R=301,L]
Q: How do I fix “too many redirects” errors?
Q: Should I use plugins or .htaccess for redirects?
Q: How do I redirect a subdomain?
RewriteCond %{HTTP_HOST} ^subdomain\.domain\.com$ [NC]
RewriteRule ^(.*)$ https://www.domain.com/subfolder/$1 [R=301,L]
Q: Can I chain multiple redirects?
Summary Checklist
Before implementing redirects:
- Test redirects with 302 before making them 301
- Verify no redirect loops exist
- Check mobile and desktop behavior
- Test with both www and non-www URLs
- Verify HTTPS enforcement if applicable
- Monitor Google Search Console for crawl errors
- Update internal links to point to new URLs
- Create a backup of your .htaccess file
Remember: A well-planned redirect strategy preserves your SEO rankings and ensures a seamless user experience during site migrations or restructuring.
Advanced Techniques for 2026
NGINX Compatibility Considerations
While .htaccess is Apache-specific, understanding how rules translate to NGINX is crucial for developers working across platforms:
Apache (.htaccess) to NGINX Conversion:
| Apache Directive | NGINX Equivalent |
|---|---|
Redirect 301 /old /new | return 301 /new; |
RewriteRule ^old$ /new [R=301,L] | location = /old { return 301 /new; } |
RewriteCond %{HTTPS} off | if ($scheme != 'https') |
NGINX server block example:
server {
listen 80;
server_name example.com;
# Permanent redirect to HTTPS
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl;
server_name example.com;
# WordPress rewrite rules
location / {
try_files $uri $uri/ /index.php?$args;
}
}
Edge Cases and Special Scenarios
1. Multilingual Site Redirects
# Redirect based on Accept-Language header
RewriteEngine On
RewriteCond %{HTTP:Accept-Language} ^de [NC]
RewriteRule ^$ /de/ [L,R=302]
RewriteCond %{HTTP:Accept-Language} ^fr [NC]
RewriteRule ^$ /fr/ [L,R=302]
2. Mobile Device Detection
# Detect mobile user agent
RewriteEngine On
RewriteCond %{HTTP_USER_AGENT} (android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge\ |maemo|midp|mmp|mobile.+firefox|netfront|opera\ m(ob|in)i|palm\ (os)?|phone|p(ixi|re)\\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows\ ce|xda|xiino [NC,OR]
RewriteCond %{HTTP_USER_AGENT} ^(1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a\ wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|l\ |nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1\ u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g\ |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/ [NC]
RewriteRule ^$ /mobile/ [L,R=302]
3. Time-Based Redirects
# Redirect during maintenance window
RewriteEngine On
RewriteCond %{TIME_HOUR}%{TIME_MIN} >0800 [NC]
RewriteCond %{TIME_HOUR}%{TIME_MIN} <1700 [NC]
RewriteRule ^$ /maintenance/ [L,R=302]
4. HTTP/HTTPS Detection for Load Balancers
# Handle X-Forwarded-Proto header from load balancers
RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
Debugging and Logging
Enable detailed rewrite logging:
# For Apache 2.4+
LogLevel alert rewrite:trace6
# Log to file
ErrorLog ${APACHE_LOG_DIR}/rewrite.log
Common debugging commands:
# Check Apache modules
apache2ctl -M | grep rewrite
# Test .htaccess syntax
apache2ctl configtest
# Check if mod_rewrite is enabled
a2enmod rewrite
# View Apache error logs
tail -f /var/log/apache2/error.log
Migration Checklist for Large Sites
When migrating a large WordPress site with thousands of redirects:
-
Inventory Phase
- Export all URLs from Google Analytics
- Crawl existing site with Screaming Frog
- Export all indexed pages from Google Search Console
- Document all 404 errors
-
Planning Phase
- Map old URLs to new URLs
- Group redirects by pattern
- Prioritize high-traffic pages
- Plan redirect chains to minimize hops
-
Implementation Phase
- Test redirects on staging environment
- Implement in batches
- Monitor server response times
- Check for redirect loops
-
Verification Phase
- Use online redirect checkers
- Monitor Search Console for crawl errors
- Check server response times
- Verify link equity transfer
-
Cleanup Phase
- Remove temporary 302 redirects (convert to 301)
- Remove unnecessary rules
- Document all redirects for future reference
- Update XML sitemap with new URLs
WordPress Plugin Alternatives
For non-technical users or complex redirect management:
Redirection
- Free, widely used
- Supports regex patterns
- 404 logging
- Import/export functionality
Yoast SEO Premium
- Built-in redirect manager
- Automatic 404 monitoring
- Seamless WordPress integration
- Regex support
Safe Redirect Manager
- WordPress.org plugin
- Whitelist-based redirects
- HTTP status code selection
- Multisite compatible
Rank Math SEO
- Comprehensive SEO suite
- 301/302/307 redirects
- 404 monitoring
- 301 bulk import
Conclusion
Mastering .htaccess redirects is essential for any WordPress developer or site administrator. The key takeaways are:
- Always use 301 for permanent moves to preserve SEO value
- Test thoroughly before deployment using 302 redirects first
- Avoid redirect chains that create unnecessary hops
- Order rules logically with most specific patterns first
- Monitor performance as complex rules can impact page load times
- Document all redirects for future maintenance and troubleshooting
With the techniques and examples in this guide, you can confidently handle any redirect scenario, from simple page moves to complex multi-domain migrations.
WordPress-Specific .htaccess Optimizations
Default WordPress .htaccess Structure
WordPress generates a default .htaccess file when you enable pretty permalinks. Understanding its structure is crucial for adding custom rules:
# BEGIN WordPress
<IfModule mod_rewrite.c>
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]
</IfModule>
# END WordPress
Adding Custom Rules Without Breaking WordPress
When adding custom rules, always place them before the WordPress rules:
# BEGIN Custom Rules
Redirect 301 /old-page /new-page
# END Custom Rules
# BEGIN WordPress
<IfModule mod_rewrite.c>
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]
</IfModule>
# END WordPress
Handling WordPress Multisite
WordPress Multisite requires additional configuration:
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteRule ^([_0-9a-zA-Z-]+/)?wp-admin$ $1wp-admin/ [R=301,L]
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
RewriteRule ^([_0-9a-zA-Z-]+/)?(wp-(content|admin|includes).*) $2 [L]
RewriteRule ^([_0-9a-zA-Z-]+/)?(.*\.php)$ $2 [L]
RewriteRule . index.php [L]
Security Rules for .htaccess
Blocking Access to Sensitive Files
# Block access to wp-config.php
<files wp-config.php>
order allow,deny
deny from all
</files>
# Block access to .htaccess itself
<files ^\.htaccess>
order allow,deny
deny from all
</files>
# Block directory browsing
Options -Indexes
IP-Based Access Control
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{REQUEST_URI} ^(.*)?wp-admin(.*)? [OR]
RewriteCond %{REQUEST_URI} ^(.*)?wp-login\.php(.*)?
RewriteCond %{REMOTE_ADDR} !^192\.168\.1\.100$
RewriteRule .* https://%{HTTP_HOST}/ [R=301,L]
</IfModule>
Performance Optimization with .htaccess
Browser Caching Headers
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType image/jpeg "access plus 1 year"
ExpiresByType image/gif "access plus 1 year"
ExpiresByType image/png "access plus 1 year"
ExpiresByType image/webp "access plus 1 year"
ExpiresByType text/css "access plus 1 month"
ExpiresByType text/javascript "access plus 1 month"
</IfModule>
# GZIP Compression
<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css application/javascript
</IfModule>
Troubleshooting Redirect Loops
Common causes:
- Conflicting rules
- Protocol mismatch (HTTP/HTTPS)
- Missing conditions
- WordPress conflicts
Debugging:
curl -I http://example.com/old-url
Migration Scenarios
HTTP to HTTPS Migration
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
Domain Migration
RewriteEngine On
RewriteCond %{HTTP_HOST} ^old-domain\.com$ [NC]
RewriteRule (.*)$ https://www.new-domain.com/$1 [R=301,L]
URL Structure Changes
RewriteEngine On
RewriteRule ^blog/([0-9]{4})/([0-9]{2})/(.+)$ /articles/$3 [R=301,L]
Advanced Techniques
Mobile Redirects
RewriteCond %{HTTP_USER_AGENT} (android|bb\d+|meego)|mobile|up\.browser [NC]
RewriteRule ^(.*)$ https://mobile.example.com/$1 [R=301,L]
Hotlink Protection
RewriteEngine On
RewriteCond %{HTTP_REFERER} !^https://(www\.)?yourdomain\.com [NC]
RewriteRule \.(jpg|jpeg|png|gif|webp)$ - [F]
Force Download Files
<FilesMatch "\.pdf$">
Header set Content-Disposition attachment
</FilesMatch>
FAQ
When to use Redirect vs RewriteRule?
- Use
Redirect 301for simple, exact URL matches - Use
RewriteRulefor complex pattern matching
How to test redirects before permanent change?
Use 302 first:
RewriteRule ^old-page$ /new-page [R=302,L]
What causes 500 Internal Server Error?
- Syntax errors
- Invalid regex patterns
- Conflicting rules causing loops
Additional Resources:
Additional Resources:



