Skip to main content

    How to Redirect HTTP to HTTPS: Apache, Nginx, IIS & WordPress

    Force HTTPS with a 301 redirect on Apache, Nginx, IIS, and WordPress. Copy-paste configs, redirect-loop fixes behind proxies, and how HSTS finishes the job.

    MS
    My-SSL Security Team
    ·
    14 min read
    ·
    Published June 13, 2026

    Installing an SSL certificate makes your site able to speak HTTPS — it does nothing to stop visitors arriving over plain HTTP. Old links, bookmarks, and anyone typing your bare domain still land on the unencrypted version unless your server actively pushes them to the secure one. That push is a redirect, it takes a few lines of configuration, and getting it slightly wrong produces some of the most confusing errors in web hosting. This guide gives you the exact config for Apache, Nginx, IIS, and WordPress, then covers the proxy and Cloudflare cases where the obvious rule causes an infinite loop.

    In short

    Answer every HTTP request with a 301 redirect to the same path on HTTPS, in one hop, at the server (not with a meta tag or JavaScript). Keep port 80 open to serve that redirect. If a CDN or load balancer terminates TLS for you, base the rule on the X-Forwarded-Proto header or you'll loop. Then add HSTS so returning browsers never touch HTTP again.

    Why force HTTPS at all

    Three reasons, in rough order of urgency. Security: every request that completes over HTTP is readable and modifiable by whoever sits on the network path — a coffee-shop router, an ISP, an attacker running a rogue access point. It doesn't matter that "it's just a redirect page"; an attacker who can intercept that first HTTP request can answer it themselves and send the visitor anywhere. Minimizing how much ever happens over HTTP is the whole game, which is why the redirect should be immediate and carry no content.

    Browsers are done waiting: Chrome has marked HTTP pages "Not secure" for years, and in October 2025 Google announced the endgame — with Chrome 147 (April 2026), users with Enhanced Safe Browsing get the "Always Use Secure Connections" setting switched on, and with Chrome 154 (October 2026) it becomes the default for everyone. Chrome will try HTTPS first and interrupt with a warning before loading a public site over plain HTTP. A site without a working HTTPS setup and redirect stops looking dated and starts looking broken.

    SEO: search engines index http:// and https:// as separate URLs. If both respond with content, your ranking signals split between duplicates. A permanent redirect consolidates everything onto the HTTPS version — Google's documentation is explicit that a server-side 301 is the strongest "this page has moved" signal it accepts. If you haven't installed a certificate yet, start with our guide to choosing one and come back; the redirect is the last step of an HTTPS migration, not the first.

    301, 302, or 308?

    HTTP has several redirect status codes, and for this job the choice is nearly always the same:

    CodeMeaningUse for HTTPS?
    301Moved permanently. Browsers cache it; search engines transfer ranking signals.Yes — the default choice
    302Found (temporary). Not cached long-term; clients keep trying the old URL.No — HTTPS isn't temporary
    308Permanent, and the request method must not change (a POST stays a POST).For APIs that accept non-GET requests

    The subtlety behind 308: RFC 9110 notes that clients historically rewrite a POST into a GET when following a 301. For a website that's irrelevant — page loads are GETs — but if clients POST to an HTTP API endpoint and you redirect them, a 301 silently turns the request into a GET and drops the body. 308 forbids that. (In practice, configure API clients to call the https:// URL directly; a redirect on an API is a latency tax even when it works.)

    One warning before you ship a 301: browsers cache it aggressively, some with no expiry. Test with a 302 if you're unsure of the rule, switch to 301 once it behaves — a wrong 301 keeps biting cached visitors long after you fix the config.

    Before you add the redirect

    • HTTPS must already work. Load https://yourdomain.com directly and confirm there's no certificate warning. A redirect pointing at a broken HTTPS site is strictly worse than no redirect — and since 301s get cached, visitors stay stuck even after you notice. If the padlock shows an error, fix that first with our SSL error guide.
    • Keep port 80 open. The redirect has to be served from somewhere, and that somewhere is your HTTP listener. Closing port 80 doesn't make users go to HTTPS — it makes your site unreachable for anyone who didn't type the scheme. Let's Encrypt's HTTP-01 validation also needs port 80 reachable for issuance and renewal.
    • Redirect server-side, not in the page. A <meta http-equiv="refresh"> tag or a JavaScript redirect means the insecure page fully loads before the hop — the exact thing you're trying to prevent — and search engines treat both as weaker signals than a real 301.
    • Know your topology. If Cloudflare, a CDN, or a load balancer sits in front of your server and terminates TLS, skip ahead to the proxies section before copying any config — the naive rule loops in that setup.

    Apache (.htaccess and vhost)

    If you control the server config, the cleanest approach is a dedicated port-80 virtual host whose only job is redirecting. It uses mod_alias, needs no rewrite engine, and can't accidentally serve content:

    <VirtualHost *:80>
        ServerName example.com
        ServerAlias www.example.com
        Redirect permanent / https://example.com/
    </VirtualHost>

    Redirect permanent sends a 301 and automatically appends the requested path, so http://example.com/pricing lands on https://example.com/pricing. Note the target is the bare domain: this single rule also folds www into the canonical host in one hop. Reload Apache after editing (sudo systemctl reload apache2).

    On shared hosting without vhost access, use .htaccess in the site root instead:

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

    Put these lines before any other rewrite rules (in WordPress, above the # BEGIN WordPress block, which WordPress rewrites on save). If this is part of a first-time SSL setup, our Apache SSL installation guide covers the certificate side, including the port-443 vhost this redirect points at.

    Nginx

    Nginx has a single idiomatic answer — a dedicated port-80 server block with return 301:

    server {
        listen 80;
        listen [::]:80;
        server_name example.com www.example.com;
        return 301 https://$host$request_uri;
    }

    $host echoes whichever hostname was requested and $request_uri preserves the full path and query string. To canonicalize www at the same time, hardcode the target host (return 301 https://example.com$request_uri;). Avoid the older if ($scheme != "https") + rewrite pattern you'll find in old answers — return is what the Nginx documentation itself recommends, and it can't misfire the way if blocks inside location contexts notoriously do.

    One exception worth building in: if you renew free certificates via the ACME HTTP-01 method, the validation request arrives on port 80 and must not be redirected to a path that doesn't answer. Carve it out before the catch-all:

    server {
        listen 80;
        server_name example.com www.example.com;
    
        location /.well-known/acme-challenge/ {
            root /var/www/letsencrypt;
        }
    
        location / {
            return 301 https://example.com$request_uri;
        }
    }

    (Strictly speaking Let's Encrypt follows redirects to HTTPS during validation, so a plain catch-all usually still works — but the carve-out makes renewals immune to whatever else you later do to the HTTPS site.) Test with nginx -t, then reload. The full HTTPS server block lives in our Nginx SSL installation guide.

    IIS (URL Rewrite)

    IIS needs Microsoft's free URL Rewrite module (installable via the Web Platform options or as a standalone download; it's not part of a default IIS install). With it in place, add this rule to your site's web.config:

    <configuration>
      <system.webServer>
        <rewrite>
          <rules>
            <rule name="Redirect to HTTPS" stopProcessing="true">
              <match url="(.*)" />
              <conditions>
                <add input="{HTTPS}" pattern="off" ignoreCase="true" />
              </conditions>
              <action type="Redirect" url="https://{HTTP_HOST}/{R:1}"
                      redirectType="Permanent" />
            </rule>
          </rules>
        </rewrite>
      </system.webServer>
    </configuration>

    Two IIS-specific traps. First, the site must keep an HTTP binding on port 80 — removing it doesn't redirect anyone, it just turns HTTP requests into connection failures. Second, do not tick "Require SSL" under SSL Settings for the site: that makes IIS answer HTTP requests with a 403 error before the rewrite rule ever runs. The rule above does the enforcing. Certificate binding, SNI, and the rest of the Windows side are covered in our IIS 10+ SSL installation guide.

    WordPress and hosting panels

    WordPress adds one step the plain-server cases don't have: the site URL is stored in the database. Change both "WordPress Address (URL)" and "Site Address (URL)" to https:// under Settings → General before adding the server redirect — if WordPress still believes it lives at http://, it generates internal links and canonical tags that fight your redirect, and you'll chase mixed content errors afterwards. Then add the .htaccess rule from the Apache section above (or the Nginx rule if that's your stack). Our WordPress SSL guide walks the whole migration end to end, including WooCommerce and the database-level URL replacement for stubborn http:// references.

    Hosting panels usually hide the same machinery behind a switch. cPanel offers "Force HTTPS Redirect" per domain under Domains; Plesk has "Permanent SEO-safe 301 redirect from HTTP to HTTPS" in Hosting Settings. If the toggle exists, prefer it over hand-editing — the panel will keep it consistent when it regenerates server config.

    Cloudflare, load balancers & proxies

    Everything above assumes the visitor's TLS connection ends at your server. Put Cloudflare, a CDN, or a load balancer in front, and that stops being true: the proxy terminates TLS and often talks to your origin over plain HTTP. Your origin now sees every request as HTTP — including ones that were HTTPS at the front door. Apply the naive rule and you get the classic loop: origin redirects to https://, proxy fetches it from the origin over http://, origin redirects again, browser eventually gives up with ERR_TOO_MANY_REDIRECTS.

    On Cloudflare, don't write the rule at the origin at all. Set SSL/TLS mode to Full (strict) — which requires a valid certificate on the origin, and is the setting you want anyway, because "Flexible" leaves the proxy-to-origin leg unencrypted — then enable Always Use HTTPS under SSL/TLS → Edge Certificates. Cloudflare issues the 301 at the edge and the loop is impossible.

    Behind your own proxy or load balancer, redirect based on what the proxy says the original scheme was — the X-Forwarded-Proto header — rather than the connection your origin sees. In Apache .htaccess:

    RewriteEngine On
    RewriteCond %{HTTP:X-Forwarded-Proto} !https
    RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

    The equivalent logic exists everywhere: Nginx can test $http_x_forwarded_proto, and most load balancers (AWS ALB, for instance) can issue the HTTP-to-HTTPS redirect at the listener so the origin never deals with it — which, as with Cloudflare, is the cleanest place for it. Only trust X-Forwarded-Proto when the header genuinely comes from your proxy; a directly-reachable origin lets anyone spoof it and skip your redirect.

    Redirect loops and other failures

    ERR_TOO_MANY_REDIRECTS

    Nine times out of ten this is the proxy problem from the previous section — TLS terminates upstream, the origin sees HTTP forever. On Cloudflare specifically, the combination of Flexible SSL mode plus an origin redirect rule is the textbook cause: switch to Full (strict). If there's no proxy involved, look for two redirect systems fighting — a panel toggle and a hand-written .htaccess rule, or a WordPress plugin plus a server rule.

    Redirect works for the homepage but deep links 404

    The rule isn't preserving the path. Check that the Apache target ends with a slash (Redirect permanent / https://example.com/), that Nginx uses $request_uri, and that the IIS action includes {R:1}.

    Browser ignores your fix

    Browsers cache 301s hard. After changing a rule, test with curl or a private window before concluding it didn't work — your normal browser may be replaying the old cached redirect. Chrome's cache can be cleared via DevTools (Network tab → Disable cache, or right-click reload → Empty Cache and Hard Reload).

    Redirect chains: http → https → www

    Each extra hop adds a round trip and dilutes crawl efficiency. Write the rules so every variant reaches the canonical URL in one redirect — the Apache and Nginx examples above fold the host canonicalization into the same hop.

    Page loads over HTTPS but shows a broken padlock

    That's not the redirect — it's mixed content: the page itself is secure but loads images, scripts, or styles over http://. See our mixed content guide for the fix.

    What a redirect can't do (HSTS)

    A redirect has one unavoidable weakness: it happens after the browser has already made an insecure request. That first HTTP round trip is a window — small, but real — in which an attacker on the network can intercept the connection and never let the visitor reach HTTPS at all (the SSL-stripping attack). The redirect can't close the window, because the redirect is the window.

    HSTS closes it. Once your HTTPS responses carry the Strict-Transport-Security header, browsers remember the policy and rewrite future http:// requests to https:// internally, before anything touches the network — no HTTP hop, no window. The two mechanisms are complementary, not alternatives: the redirect catches first-time visitors and non-browser clients, HSTS protects everyone who's been there before. Deploy the redirect first, confirm it's stable, then follow our HSTS guide — it covers max-age ramp-up, includeSubDomains pitfalls, and the browser preload list, which removes even the very first HTTP request.

    Testing your redirect

    Don't test in your everyday browser first — cached 301s and HSTS entries will show you yesterday's behavior. curl shows the truth:

    # Expect: HTTP/1.1 301 Moved Permanently + Location: https://example.com/
    curl -I http://example.com
    
    # Follow the whole chain and count the hops (want: exactly one redirect)
    curl -sIL -o /dev/null -w "%{num_redirects} redirects, final: %{url_effective}\n" \
      http://www.example.com/some/path?q=1

    Check all four entry points — http:// and https://, with and without www — and at least one deep path with a query string. Each should land on the canonical HTTPS URL in at most one hop, with the path and query intact. Then confirm the destination itself is healthy: our free SSL checker verifies the certificate, chain, and expiry of the HTTPS site your redirect now sends everyone to.

    Frequently Asked Questions

    Get instant answers to common questions about SSL certificates and our services.

    Still Have Questions?

    Our SSL experts are available 24/7 to help with any questions about certificates, installation, or technical issues.