Plain HTTP does not redirect to HTTPS
What this check looks for
The insecure port serves the site instead of sending visitors to the secure one. Anyone typing your address without https:// gets an unencrypted page.
Why it matters
The first request a visitor makes is almost always plaintext — typed addresses, old bookmarks, links in emails. Without a redirect that request travels in the clear, and anything on the path can read it or change it before HSTS ever gets a chance to apply.
When the check passes, your report says: “Plain HTTP redirects visitors to the secure address”.
What it costs your score
When this check fails it removes 30 points from your HTTP score, before the status, confidence and repeat multipliers are applied. HTTP carries a weight of 7 in the overall score.
It shares the http.reachability family ceiling of 60 points: however many findings that family produces, together they cannot remove more than that from HTTP. One underlying problem showing up in several places is still one problem.
- Severity
- high
- Default confidence
- confirmed
- Status when triggered
- fail
- Deduction
- 30 points
- Family cap
- http.reachability · 60
- Category
- HTTP
- Module
- Http reachability
- Fix owned by
- user
- In the ruleset since
- 2026.09
How to fix it
Redirect every plain HTTP request to the same URL on HTTPS with a 301.
Without it, the first request of every visit is unencrypted and interceptable.
Add a port-80 server block that redirects to
https://on the same host and path.Use 301 (or 308 to preserve the method), not 302 — a temporary redirect is re-requested every time.
Preserve the path and query string; a blanket redirect to the home page loses deep links.
Once the redirect is in place, add HSTS so browsers stop making the plaintext request at all.
How to confirm it worked
curl -sSI http://‹host›/ — expect '301' and a Location beginning https://‹host›/
A named slot like ‹domain› — and the braces left in the configuration below — is filled in with your own values when this rule appears on a report.
Remediation by platform
server {
listen 80;
listen [::]:80;
server_name ‹host›;
# Keep the ACME challenge on plain HTTP, or renewal breaks.
location ^~ /.well-known/acme-challenge/ {
root /var/www/html;
}
location / {
return 301 https://$host$request_uri;
}
}<VirtualHost *:80>
ServerName ‹host›
RedirectMatch 301 ^/(?!\.well-known/acme-challenge/)(.*)$ https://‹host›/$1
</VirtualHost># Caddy redirects HTTP to HTTPS automatically for any site it has a certificate for.
# An explicit block is only needed to change the status code:
http://‹host› {
redir https://‹host›{uri} permanent
}SSL/TLS → Edge Certificates → Always Use HTTPS → On.Use
return, notrewrite: rewrite re-enters location matching and is easy to make loop.Shown for Apache because the response identified Apache. It belongs in the virtual host, not in .htaccess — .htaccess is read on every request and cannot see the port-80/443 distinction reliably behind a proxy.
This runs at Cloudflare's edge and applies only to traffic that reaches visitors through it. An origin that is reachable directly — by IP, or through a DNS record that is not proxied — still answers on port 80 exactly as before. Configure the redirect on the origin as well.
Technical detail
http://‹host›/ returned HTTP ‹status›. ‹detail›
The redirect must be a permanent one (301 or 308) to the same path on HTTPS. Two details matter: redirect to the *same* host and path first, because a redirect that also changes host means the browser never sees an HSTS header for the original name; and keep /.well-known/acme-challenge/ served over plain HTTP, or certificate renewal breaks.
Standards and references
Test this on your domain
Run the check that produces this finding, on its own, against any domain.