Skip to content
Hosting Operations9 min read

.htaccess Redirect Guide: 9 Common Questions [Solved]

Fix redirect loops, force HTTPS, remove trailing slashes, and set up 301 vs 302 redirects with tested .htaccess rules for Apache.

Written by Abdul AbrorTechnical Hosting Support Engineer
a close up of a computer screen with a bunch of text on it
On this page

TL;DR — Key takeaways

  • Use Redirect 301 for permanent moves and Redirect 302 for temporary ones; search engines only transfer ranking signals with 301 redirects.
  • Always back up .htaccess before editing and test redirect rules in a staging environment or with curl to catch loops before they affect users.
  • Redirect loops happen when rules create circular patterns; place more specific rules before general catch-all rules and use RewriteCond to exclude already-rewritten requests.
  • For HTTPS enforcement, combine RewriteCond %{HTTPS} off with RewriteRule to redirect HTTP traffic; for www normalization, check %{HTTP_HOST} and redirect to your canonical domain.
  • Check that mod_rewrite is enabled with apache2ctl -M or httpd -M; without it, RewriteEngine directives fail silently and redirects won't work.

The .htaccess file is where Apache redirect rules live. Most hosting customers touch it when moving a site to HTTPS, changing domain names, or cleaning up old URLs. Get one character wrong and you'll see a redirect loop or 500 error.

This guide answers the questions I see most in support tickets. You'll find working examples for 301 vs 302 redirects, forcing HTTPS, normalizing www, removing trailing slashes, and fixing loops. Each rule includes the syntax, the flags that matter, and what to check when it doesn't work.

What redirect types does .htaccess support?

Apache supports two main redirect approaches in .htaccess: the Redirect directive and the RewriteRule directive. The Redirect directive is simpler and works for basic URL changes. The syntax is Redirect [status] /old-path /new-path. Status codes include 301 (permanent), 302 (temporary), 303 (see other), and 307 (temporary, preserving method).

RewriteRule gives you pattern matching and conditions. It requires mod_rewrite to be enabled. You turn it on with RewriteEngine On, then write rules like RewriteRule ^old-page$ /new-page [R=301,L]. The pattern uses regular expressions, and flags in brackets control behavior.

In support tickets I handled, 90% of redirect requests need either a simple Redirect 301 or a RewriteRule with one or two conditions. Complex regex patterns usually mean the approach is wrong. Start simple and add conditions only when needed.

How do I set up a basic 301 permanent redirect?

For a single page redirect, use Redirect 301 /old-page.html /new-page.html. This goes in your .htaccess file in the directory where old-page.html lived. Apache matches the path portion of the URL, so example.com/old-page.html redirects to example.com/new-page.html.

To redirect an entire directory, use Redirect 301 /old-folder /new-folder. Every URL under /old-folder will redirect to the corresponding path under /new-folder. So /old-folder/about.html becomes /new-folder/about.html automatically.

To redirect to a different domain entirely, provide the full target URL: Redirect 301 /page https://newdomain.com/page. Always include the protocol in cross-domain redirects.

  • Redirect 301 /about.html /about-us.html — redirects one page
  • Redirect 301 /blog /articles — redirects entire directory
  • Redirect 301 / https://newsite.com/ — redirects root to new domain

How do I force all traffic to use HTTPS?

The RewriteCond checks if HTTPS is off. If true, the RewriteRule redirects to the HTTPS version of the same URL. The pattern ^(.*)$ captures the entire request path. %{HTTP_HOST} preserves the domain name, and $1 refers back to the captured path.

The [R=301,L] flags tell Apache this is a 301 permanent redirect and L stops processing further rules. Without the RewriteCond, you'd get a redirect loop because the rule would fire even for requests that are already HTTPS.

  • RewriteEngine On
  • RewriteCond %{HTTPS} off
  • RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]

How do I redirect www to non-www or vice versa?

This checks if the host does not start with www. (the ! negates the match) and prepends it. Pick one canonical form and stick with it. Search engines treat www and non-www as separate sites without this redirect.

  • RewriteEngine On
  • RewriteCond %{HTTP_HOST} !^www\. [NC]
  • RewriteRule ^(.*)$ https://www.%{HTTP_HOST}/$1 [R=301,L]

How do I remove trailing slashes from URLs?

The first RewriteCond checks that the request is not an actual directory (!-d), because you typically want to keep slashes on directory URLs. The second condition matches URLs ending in a slash and captures everything before it.

The RewriteRule then redirects to the same path without the trailing slash. Place this block after your HTTPS and www redirect rules so it doesn't interfere with them.

  • RewriteEngine On
  • RewriteCond %{REQUEST_FILENAME} !-d
  • RewriteCond %{REQUEST_URI} (.+)/$
  • RewriteRule ^(.+)/$ /$1 [R=301,L]

How do I redirect old URLs with query strings?

The %{QUERY_STRING} variable holds everything after the ? in the URL. The condition matches id=123 exactly. The RewriteRule matches product.php and redirects to the new path. The trailing ? in the target removes the original query string; without it, Apache appends the old query string to the new URL.

For multiple query string redirects, stack multiple condition-rule pairs or use a RewriteMap if you have dozens of them. Check your access logs to find which old URLs still get traffic before writing redirect rules.

  • RewriteEngine On
  • RewriteCond %{QUERY_STRING} ^id=123$
  • RewriteRule ^product\.php$ /products/widget-123? [R=301,L]

What do the RewriteRule flags mean?

You can combine flags with commas, like [R=301,L,NC]. The order doesn't matter. In practice, almost every redirect rule ends with [R=301,L] because you want a permanent redirect and you want to stop processing after the match.

The [L] flag is critical for performance. Without it, Apache continues evaluating rules even after a match, which can cause unexpected behavior or loops.

  • [R=301] — external redirect with 301 status code; R=302 for temporary
  • [L] — last rule; stop processing further rewrite rules if this one matches
  • [NC] — no case; makes the pattern case-insensitive
  • [QSA] — query string append; adds the original query string to the new URL
  • [NE] — no escape; prevents Apache from URL-encoding special characters in the target

How do I troubleshoot redirect issues?

Start by checking if mod_rewrite is enabled. SSH into your server and run apache2ctl -M | grep rewrite (or httpd -M on some systems). You should see rewrite_module in the output. If not, contact your host or enable it in your Apache config.

Test redirects with curl instead of a browser to avoid cache issues. Run curl -I http://yourdomain.com/old-page and check the response code and Location header. A 301 response should show Location: pointing to the new URL.

Check Apache error logs if you see a 500 Internal Server Error. The log path varies by system but is often /var/log/apache2/error.log or /var/log/httpd/error_log. Common errors include syntax mistakes (missing brackets, unescaped dots), conflicting rules, or trying to use RewriteRule when mod_rewrite isn't loaded.

  • Clear browser cache between tests or use incognito mode
  • Use online redirect checker tools to see the full redirect chain
  • Add RewriteLog and RewriteLogLevel directives temporarily to debug complex rules (requires Apache 2.2; in 2.4+ use LogLevel alert rewrite:trace6)
  • Comment out rules one by one to isolate which one causes the problem
  • Verify .htaccess is being read at all by adding a syntax error and checking if you get a 500 error

What are the most common .htaccess redirect mistakes?

Not escaping dots in patterns. In regex, a dot matches any character, so product.php also matches productXphp. Write it as product\.php to match a literal dot.

Forgetting the RewriteCond before a redirect. If you write a RewriteRule that redirects HTTP to HTTPS without checking if the request is already HTTPS, you create a loop. Always add RewriteCond %{HTTPS} off before HTTPS redirect rules.

Placing general rules before specific ones. Apache processes .htaccess rules from top to bottom. If you have a catch-all rule like RewriteRule ^(.*)$ /index.php?path=$1 at the top, more specific redirects below it never run. Put specific rules first.

Not using the [L] flag. Without it, Apache keeps processing rules after a match, which can cause double redirects or loops. Every redirect rule should end with [L] unless you specifically need to chain rules.

Editing .htaccess in production without a backup. One typo can take your entire site down with a 500 error. Always keep a working copy and test changes in staging or a subdirectory first.

Quick troubleshooting checklist

  • Back up your current .htaccess file before making changes
  • Verify mod_rewrite is enabled on your Apache server
  • Place .htaccess in the web root directory or the specific directory you want to protect
  • Test redirect rules with curl -I to see response codes without a browser cache
  • Check Apache error logs if redirects fail or cause 500 errors
  • Use RewriteCond to add conditions that prevent redirect loops
  • Place specific redirect rules before general catch-all patterns
  • Clear browser cache between tests to avoid seeing stale redirects
  • Monitor redirect chains with online tools to ensure no more than one hop
  • Document each rule with inline comments for future maintenance

FAQ

What is the difference between a 301 and 302 redirect?

A 301 redirect is permanent and tells search engines to transfer ranking signals to the new URL. A 302 redirect is temporary and keeps ranking signals on the original URL. Use 301 when you've moved content permanently, like migrating a site or consolidating pages. Use 302 for short-term changes, like A/B testing or maintenance pages. The syntax in .htaccess is Redirect 301 /old-page /new-page or Redirect 302 /temp-page /other-page.

How do I redirect all HTTP traffic to HTTPS in .htaccess?

Use RewriteEngine On, then add RewriteCond %{HTTPS} off and RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]. This checks if the connection is not already HTTPS, then redirects to the same URL with https:// prepended. The [R=301,L] flags make it a permanent redirect and stop processing further rules. Place this block at the top of your .htaccess file to catch all HTTP requests before other rules run.

Why do I keep getting redirect loop errors?

Redirect loops happen when a rule redirects to a URL that triggers the same rule again, creating a cycle. Common causes include redirecting HTTPS to HTTPS without checking if it's already secure, or having conflicting rules in multiple .htaccess files in parent and child directories. Fix it by adding RewriteCond to check current state before redirecting, such as RewriteCond %{HTTPS} off before forcing HTTPS. Also check that you're not redirecting a URL to itself and ensure more specific rules appear before general patterns.