301 Redirects with .htaccess
How to set up www, HTTPS and old-URL redirects with .htaccess on Apache while preserving SEO value, how to test them and how to fix redirect loops.

For htaccess redirects, mod_rewrite must be enabled on Apache and the rules must be written after the RewriteEngine On line in the .htaccess file in the site's root folder. For permanent moves, use the R=301 flag; browsers and search engines then switch to the new address, and the old address's ranking value is largely preserved. Test the rules with curl -I first.
What Is a 301 Redirect and When Do You Need One?
A 301 redirect is an HTTP response that says an address has been moved permanently to another one. The browser automatically takes the visitor to the new address, while search engines gradually replace the old address in their index with the new one.
302 and 307 are temporary redirects, used for short-term situations such as a campaign or a maintenance page. Using a temporary redirect for a permanent change can cause search engines to keep the old address in their index.
The need for a redirect usually arises when you move a site to HTTPS, choose between the www and non-www versions, change page URLs, change the domain name or move to a new site. In site redesigns, mapping old URLs one by one is one of the most critical steps of an SEO-friendly web design process.
Prerequisites: mod_rewrite and AllowOverride
The .htaccess file works only on Apache and Apache-compatible servers (such as LiteSpeed). Nginx does not read this file; if you use Nginx, you need to write the same rules in the server block, with details in our Nginx setup guide.
On shared hosting, mod_rewrite is usually enabled and you can go straight to the rules. If you manage your own server, you need to enable the module and turn on AllowOverride in the virtual host settings; otherwise Apache ignores the .htaccess file completely.
sudo a2enmod rewrite
sudo nano /etc/apache2/sites-available/ornek.com.conf
sudo apache2ctl configtest
sudo systemctl restart apache2<Directory /var/www/ornek.com/public_html>
AllowOverride All
Require all granted
</Directory>HTTPS and www Redirects
A site can be opened with at least four different addresses: http and https, with and without www. The cleanest solution is to choose a single canonical address and redirect the other three to it in one step. Chained redirects (first to HTTPS, then to www) are both slow and a waste of crawl budget.
Before moving to an HTTPS redirect, make sure the server has a valid certificate; we covered setup in our SSL certificate installation guide. Redirecting to HTTPS without a certificate makes visitors see a security warning.
We explained in detail why HTTPS is no longer a choice but a requirement, and the certificate types, in our what is an SSL certificate article. After choosing your canonical address, make sure canonical tags, the sitemap and internal links all use that address; otherwise you send conflicting signals to the search engine.
Forcing non-www and HTTPS
The rule below redirects the request in a single step to the https, non-www address if HTTPS is off or the address starts with www. The last condition captures the domain name, and %1 uses the captured value.
RewriteEngine On
RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} ^www\. [NC]
RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+)$ [NC]
RewriteRule ^ https://%1%{REQUEST_URI} [L,R=301]Forcing www and HTTPS
If your canonical address is the www version, write the rule like this.
RewriteEngine On
RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+)$ [NC]
RewriteRule ^ https://www.%1%{REQUEST_URI} [L,R=301]Moving Old Pages, Folders and Domains
When the URL structure changes, every old page must redirect to the closest new page in terms of content. Redirecting all old URLs to the homepage looks easy, but search engines often treat it as a soft 404 and the old page's value is lost.
The order of the rules matters: specific rules go on top and general rules below. Apache processes rules from top to bottom, and the L flag stops processing in that round after a matching rule.
For large migrations, start by preparing a redirect map: a table with the old URL on the left, the new URL on the right, and the traffic and link count each page received next to it. This list guides you both when writing the rules and when checking them one by one after launch. For pages that truly have no equivalent and have been removed, returning a 410 or 404 response instead of a redirect is a more honest signal.
- For simple single-page moves, mod_alias's Redirect 301 line can also be used, but not mixing it with RewriteRule in the same file avoids surprises about ordering.
- Compile the list of old URLs from Search Console and the old sitemap; don't miss any important page.
- When changing the domain name, also use the Change of address tool in Search Console.
RewriteEngine On
# Tek sayfa
RewriteRule ^eski-sayfa\.html$ /yeni-sayfa/ [R=301,L]
# Folder move: /haberler/... -> /blog/...
RewriteRule ^haberler/(.*)$ /blog/$1 [R=301,L]
# Redirect while dropping the query string
RewriteCond %{QUERY_STRING} ^id=15$
RewriteRule ^urun\.php$ /urunler/deri-canta/ [R=301,L,QSD]
# Domain change (in the old domain's .htaccess file)
RewriteCond %{HTTP_HOST} ^(www\.)?eskialan\.com$ [NC]
RewriteRule ^(.*)$ https://yenialan.com/$1 [R=301,L]Removing the .html Extension
On static sites you may want clean URLs such as /about instead of /about.html. This takes two rules: one redirects requests with the extension to the extensionless URL with a 301, and the other maps the extensionless request to the matching .html file behind the scenes.
Using %{THE_REQUEST} in the first rule is important; this variable holds the original request sent by the browser and prevents the internal rewrite from turning into a redirect again and creating an infinite loop.
RewriteEngine On
# /sayfa.html -> /sayfa (301)
RewriteCond %{THE_REQUEST} \s/([^.\s]+)\.html[\s?] [NC]
RewriteRule ^ /%1 [R=301,L]
# Map the /sayfa request to the sayfa.html file (internal rewrite)
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule ^(.+)$ $1.html [L]How Do I Test Redirects?
Browsers cache 301 responses. When you fix a wrong rule, your browser may keep remembering the old redirect; so use R=302 while testing and switch to 301 once everything is correct. Testing in a private window or from the command line is the most reliable way.
The curl command clearly shows the response code and the Location header. With the -L parameter you can follow the whole chain, and if there is more than one step you can collapse them into a single redirect.
- In Windows PowerShell, type curl.exe instead of curl; otherwise a different command may run.
- To try it locally, you can use a package that includes Apache, such as XAMPP.
- After going live, monitor the redirect and indexing reports in Search Console for a few weeks.
curl -I http://www.ornek.com/eski-sayfa.html
# To see the whole chain
curl -sIL http://ornek.com | grep -iE '^(HTTP|location)'Common Errors and Fixes
Most redirect problems show up with a few familiar symptoms. The Apache error log (/var/log/apache2/error.log on Ubuntu) usually tells you which line the problem is on.
| Symptom | Likely cause and fix |
|---|---|
| 500 Internal Server Error | A typo, or mod_rewrite is off; undo the last line you added and check the error log. |
| ERR_TOO_MANY_REDIRECTS | The rules redirect to each other, or HTTPS is not detected behind a proxy. |
| The rule doesn't work at all | AllowOverride None, or the file is in the wrong folder; check the virtual host settings. |
| The new URL returns 404 | The target path is wrong or written as relative; add / at the start of the target. |
| The fix doesn't show | The browser is using the old 301 from its cache; test in a private window or with curl. |
Behind Cloudflare or a load balancer
If SSL terminates at the proxy, requests reaching the server always look like HTTP and the %{HTTPS} off condition causes an infinite loop. In that case, check the X-Forwarded-Proto header sent by the proxy, or do the HTTPS redirect from the proxy's panel.
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]Frequently Asked Questions
01Does a 301 redirect pass on SEO value completely?
A permanent redirect to the right target passes most of the old URL's signals to the new one. Still, rankings may fluctuate temporarily during the transition; redirects to targets whose content does not match cause a loss of value.
02How long should I keep redirects?
Do not remove redirects as long as other sites link to the old URLs. In practice, keeping them for at least a year, and indefinitely for important pages, is the safest approach.
03Do I need a redirect for the trailing slash too?
Search engines may see /about and /about/ as separate pages. Deciding which one to use and redirecting the other to it with a 301 prevents the same content from being indexed at two addresses. What matters is that the choice is consistent across the whole site.
04Do many redirects slow the site down?
A few hundred lines of rules won't cause noticeable slowness, but because .htaccess is read on every request, thousands of lines add load. At that scale, moving the rules to the virtual host configuration or to a mapping file with RewriteMap is more efficient.
Correctly set up 301 redirects make sure your effort and traffic are not lost when addresses change. If you want to run the old-URL mapping, redirects and technical SEO checks together during a redesign, see our SEO-friendly web design service, and for post-launch speed improvements, our speed and performance optimization work. You can also use our SEO and analytics support to monitor your search data regularly, and work with our web design team on e-commerce platform migration projects.


