2026年11月12日
2026年11月12日
Redirect HTTP to HTTPS with .htaccess: Rule Placement and Loop Fixes
This article is a localized edition of the Japanese original. Read the Japanese original
Once your site can be served over HTTPS, redirect visitors who arrive on http:// to https://. This article explains how to write a 301 redirect from HTTP to HTTPS in Apache's .htaccess, and what to watch for when you use it with WordPress. It assumes Apache 2.4 as of October 2026.
Check before you start
- The site opens over HTTPS. If you redirect before an SSL certificate is set up, visitors are sent to a certificate error page. First open the
https://URL in a browser and confirm it loads without warnings - Rewrites work in
.htaccess. Apache must allowAllowOverride FileInfo(orAll) for that directory, and mod_rewrite must be enabled. If WordPress permalinks such as "Post name" already work, these conditions are met - Whether your server control panel has an HTTPS redirect feature. Some hosting providers let you turn on an HTTPS redirect in the control panel. If you use that feature, you do not need to write the same redirect in
.htaccess. Setting up both makes problems harder to isolate
If you can edit the server configuration files (httpd.conf or the virtual host configuration), the official Apache documentation recommends writing a Redirect in the port 80 virtual host rather than using .htaccess.
<VirtualHost *:80>
ServerName example.com
ServerAlias www.example.com
Redirect permanent "/" "https://example.com/"
</VirtualHost>
The rest of this article covers .htaccess, for shared hosting and other setups where you cannot edit the configuration files.
Step 1: Back up .htaccess
.htaccess is in the directory where WordPress is installed (the same place as wp-config.php). A typo can take the whole site down with "500 Internal Server Error", so make a copy before editing.
cp .htaccess .htaccess.bak
If you edit it over FTP or with the control panel's file manager, download the original file to your computer first.
Step 2: Write the redirect rule
Add the following at the top of .htaccess, before # BEGIN WordPress.
# Redirect HTTP to HTTPS
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
</IfModule>
# BEGIN WordPress
(The part written by WordPress. Do not change it.)
# END WordPress
Each line means the following.
| Line | Meaning |
|---|---|
RewriteEngine On |
Use rewrites in this .htaccess |
RewriteCond %{HTTPS} !=on |
Run the next line only for requests that are not HTTPS |
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301] |
Redirect with 301 to https:// on the same host name and path, and stop processing here |
%{REQUEST_URI} does not include the query string (the part after ?), but as long as you do not write a ? in the target, the original query string is appended automatically. http://example.com/?p=123 is redirected to https://example.com/?p=123.
Why it goes before the WordPress rules
The part from # BEGIN WordPress to # END WordPress is managed by WordPress. WordPress rewrites it, for example when you save the permalink settings, so anything you write there is lost. Also, the WordPress rules hand every non-existent URL to index.php and stop processing, so if you put the redirect rule after them, the redirect does not run for most URLs.
Step 3: Also unify www (optional)
If you want to settle on either www.example.com or example.com, combining it with the HTTPS redirect into a single redirect avoids two redirects in a row. The following example settles on the non-www version (replace example.com with your domain).
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTPS} !=on [OR]
RewriteCond %{HTTP_HOST} ^www\. [NC]
RewriteRule ^ https://example.com%{REQUEST_URI} [L,R=301]
</IfModule>
[OR] means "if either condition matches", and [NC] makes the match case-insensitive. To settle on the www version instead, change the second condition to RewriteCond %{HTTP_HOST} !^www\. [NC] and the target to https://www.example.com%{REQUEST_URI}. Whichever you choose, make it match "Site Address (URL)" under Settings → General in WordPress.
Step 4: Test the redirect
Browsers remember 301 redirects, so if a mistaken redirect is cached, you may keep being sent to the old target for a while even after fixing it. Testing with curl is not affected by the browser's memory.
curl -sI http://example.com/sample-page/?test=1 | grep -iE '^(HTTP|location)'
If you see 301 and an HTTPS target like the following, it works.
HTTP/1.1 301 Moved Permanently
Location: https://example.com/sample-page/?test=1
Then check the HTTPS URL too and confirm it returns 200 (no further redirect).
curl -sI https://example.com/sample-page/ | grep -iE '^(HTTP|location)'
While testing the rule, you can also use R=302 (a temporary redirect) instead of R=301 and switch to R=301 once it works. Browsers are less likely to remember a 302, which makes rewriting the rule easier.
Step 5: Switch the WordPress URLs to HTTPS
The redirect alone leaves the link and image URLs that WordPress outputs on http://. In WordPress, go to Settings → General, change "WordPress Address (URL)" and "Site Address (URL)" to https://, and save.
If images or links written as http:// remain in post content, the browser may show "Not secure" or fail to load images (mixed content). If you can use WP-CLI, back up the database and then replace them like this.
wp search-replace 'http://example.com' 'https://example.com' --skip-columns=guid --dry-run
wp search-replace 'http://example.com' 'https://example.com' --skip-columns=guid
Check the number of replacements with --dry-run, then run it again without --dry-run. How to find and fix mixed content is explained in causes and fixes for mixed content errors after switching to HTTPS.
If the browser says the page redirected too many times
If the browser shows ERR_TOO_MANY_REDIRECTS and the site will not open, the redirect is looping. A common cause is Apache sitting behind a CDN such as Cloudflare or behind a load balancer. Even though visitors talk to the CDN over HTTPS, the CDN connects to Apache over HTTP, so %{HTTPS} is always off from Apache's point of view and the redirect repeats.
In that case, decide based on the X-Forwarded-Proto header that the CDN or load balancer adds.
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-Proto} !=https
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
</IfModule>
However, any client can set this header freely, even on direct requests that do not go through the CDN. Do not use this version if you are not behind a CDN. On Cloudflare, if the SSL/TLS encryption mode is Flexible, the connection from the CDN to Apache uses HTTP. If your server has a valid certificate, switching to Full (strict) lets the first version based on %{HTTPS} work as is.
WordPress itself can also loop redirects in the admin area when it cannot tell that the page is served over HTTPS. In that case, add the following to wp-config.php before the /* That's all, stop editing! */ line.
<?php
if ( isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) && 'https' === $_SERVER['HTTP_X_FORWARDED_PROTO'] ) {
$_SERVER['HTTPS'] = 'on';
}
(wp-config.php already starts with <?php, so add only the second line onward.)
If it still does not work, check that the control panel's HTTPS redirect and the .htaccess redirect are not both active, and that no plugin is also redirecting. For details, see fixing HTTPS redirect loops in Apache.
Troubleshooting
| Symptom | What to check |
|---|---|
| 500 Internal Server Error | A typo. Restore .htaccess.bak and rewrite the rule. The server error log shows the cause |
| Nothing is redirected | Whether the rule is after # BEGIN WordPress, and whether AllowOverride allows rewrites |
ERR_TOO_MANY_REDIRECTS |
As in the section above, whether redirects from a CDN, load balancer, or the control panel overlap |
| Still sent to the old target after fixing | The browser remembers the 301. Check with curl or open the page in a private window |
Summary
- Confirm the site opens over HTTPS before setting up the redirect
- In
.htaccess, before# BEGIN WordPress, writeRewriteCond %{HTTPS} !=onandRewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301] - To unify www, combine the conditions with
[OR]so there is only one redirect - Check
301andLocationwithcurl -sI - Set WordPress's "WordPress Address (URL)" and "Site Address (URL)" to
https://, and replace anyhttp://left in content - If redirects loop behind a CDN, decide with
X-Forwarded-Protoand tell WordPress about HTTPS as well
To add HSTS so browsers always connect over HTTPS, see how to set up HSTS in Apache.
Related articles:
- 301 redirect from HTTP to HTTPS for WordPress (.htaccess, Nginx, Cloudflare)
- How to redirect HTTP to HTTPS in Nginx
- Causes and fixes for mixed content errors after switching to HTTPS (WordPress)
Questions about WordPress? The publisher of this site is based in Japan and replies in Japanese. Contact (Japanese)