Note
The http redirect a static host does not add for you
Certificates are automatic almost everywhere now. The redirect is not: port 80 and port 443 are configured in different places, and a host can answer both of them with a cheerful 200. The fix is one line, and the first step is a measurement anybody can take from outside.
- https
- Static hosting
- Deployment
Measure it before fixing it
One request answers the question. Ask for the http address and do not follow the redirect, so what comes back is the first response rather than the last one:
curl -sS -o /dev/null -D - http://example.com/
Three outcomes, and they are not near each other:
- 301 or 308, with a
Locationon https. Correct. Nothing to do here. - 200, with a page body. The site is being served over plain http as well as over https. Everybody who typed the bare name, every old link and every bookmark is reading it unencrypted, and nothing on the page says so.
- Connection refused, or a timeout. Port 80 is closed. Safer than the second case and worse than the first for a human: somebody who types the name into a browser that has not been to the site before gets an error instead of the site.
Why it is not automatic
The certificate and the redirect are two settings owned by two different layers. Issuing a certificate is a one-time ceremony against a name; answering port 80 is routing. A platform that automates the first has no obligation to do anything in particular about the second, and all three defensible defaults — redirect, serve, refuse — exist in the wild.
It is also the last thing anybody checks, because every route a developer takes to the site already begins with https: the dashboard link, the repository link, the browser's own autocomplete. The plain-http request is the one a stranger makes.
The fix, per platform
Four that cover most static hosting. In each case it is a setting or a few lines rather than a project:
- Cloudflare, proxied. SSL/TLS, then Edge Certificates, then Always Use HTTPS — a switch for the whole zone — or a single redirect rule if it has to apply to one hostname only. Pages behind the same proxy inherits it.
- Netlify. Domain management, HTTPS, Force HTTPS. It is a
toggle rather than a
_redirectsrule, because the scheme is not something the redirect engine gets to see. - S3 behind CloudFront. Set the default cache behaviour's viewer
protocol policy to
redirect-to-https. An S3 website endpoint on its own speaks plain http and cannot do this at all, which is the reason the bucket is behind a distribution in the first place. - nginx. A server block whose only job is the redirect:
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
location /.well-known/acme-challenge/ { root /var/www/acme; }
location / { return 308 https://$host$request_uri; }
}
Leave the challenge path on port 80. That first
location is not decoration. An http-01 certificate validation is an
ordinary http request for a file under /.well-known/acme-challenge/, and
although the ACME specification lets the validating server follow redirects, sending it
into an https host that does not yet serve a valid certificate for the name is how a
first issuance deadlocks. Redirect everything else.
301 or 308, decided once
Both are permanent redirects. The difference is what a client may do to the request method: 301 has always been widely treated as licence to turn a POST into a GET, and HTTP Semantics describes exactly that history as the reason 308 exists. 308 preserves the method and the body.
On a site that only serves GET requests this is theoretical. On anything with a form or an API on the same hostname it is not: a POST that silently becomes a GET arrives with no body, and the server answers with something confusing rather than something obviously wrong. Use 308 and stop thinking about it.
Then take the first request out of the equation
A redirect still means one plain-http request, which is one opportunity to intercept it.
The Strict-Transport-Security header removes that for everybody who has
been to the site before: for max-age seconds the browser remembers that
this host is https-only and rewrites the scheme itself, before anything leaves the
machine.
- Send it over https only. A browser is required to ignore the header when it arrives over plain http, so putting it on the redirect response achieves nothing.
- Start with a short max-age. It is a promise the browser holds you to. A long one on a host that later has to serve something over http is a self-inflicted outage with no quick undo.
includeSubDomainsandpreloadare one-way doors. Preload ships inside browser binaries, so removal is a release cycle rather than a deploy. Add them only once every subdomain, including the ones somebody else operates, is certainly https.
In that order: measure, redirect with 308, keep the challenge path reachable, then shorten the window with a header. Each step is independently checkable from outside the host, which is the point — none of it has to be believed.
Sources
Where this is written down
- RFC 9110: HTTP Semantics — 301 and 308 are both permanent, and the difference between them is whether a client may change the request method, which is why 308 exists at all
- RFC 6797: HTTP Strict Transport Security — the header must be ignored when it arrives over plain http, and max-age plus includeSubDomains is a commitment with no fast way back
- RFC 8555: Automatic Certificate Management Environment (ACME) — http-01 validation is an ordinary http request for a file under a well-known path, which is why a blanket port-80 redirect has to leave that path alone
Related
Where this comes up in the work
Web, apps & DevOps
Web and app builds with the DevOps around them: front end, backend, the database under it, and the build, deploy and monitoring work that keeps it up.
More notes
Other things worth writing down
The certificate renewal nobody is watching
Read notAfter off the handshake yourself, learn the four ways an automated renewal still fails, and monitor the certificate a visitor is actually served.
- TLS
- Certificates
- Monitoring
What a browser does with http assets on an https page
A stylesheet or script fetched over http on an https page is blocked outright. What a browser does with each kind, and how to find every one in your HTML.
- https
- Browsers
- Front end
How to build and load a custom Niagara 4 module
What a Niagara module actually is on disk, the two ways to build one, and the three Software Manager refusals that actually mean something.
- Module development
- Build tooling
- Deployment
Next step
Tell us the version, the hardware, and what it has to do.
You will get a written scope and a fixed price against it. If the honest answer is that you do not need us, you will get that instead.