// Engineering Log
HTTP, HTTPS and TLS: Part 7 — Transition to HTTPS: redirects, HSTS, HTTPS-First and the Upgrade header
Published on 2026-10-09
// Fast route
This article belongs to the topic Servers and infrastructure.
The user types example.ru in the address bar without a scheme, follows an old http://… link, or opens a decade-old bookmark. In all these cases the first request may go over plain HTTP, and the site owner’s job is to ensure everything continues over HTTPS — ideally so that there is no plaintext request at all. There are several mechanisms that work at different stages: server redirect, HSTS, the built-in preload list, HTTPS-First mode in browsers, DNS HTTPS record. The Upgrade header, often confused with “HTTPS upgrade”, is covered separately: it switches the connection to a different protocol, for example WebSocket.
Redirect from HTTP to HTTPS
The basic level — the server on port 80 responds with a redirect to the same address over HTTPS:
server {
listen 80;
listen [::]:80;
server_name example.ru www.example.ru;
location /.well-known/acme-challenge/ {
root /var/www/letsencrypt; # Let's Encrypt HTTP-01 verification
}
location / {
return 301 https://$host$request_uri;
}
}Key points:
- 301 or 308. Both are permanent redirects; search engines transfer page weight to the new address. 308 preserves the method and request body; with 301 browsers may turn a POST into a GET. For a website the difference is usually unnoticed; for an API where clients accidentally send POST to
http://, 308 is better. - Preserve the path.
$request_uricontains the path and query. Redirecting all pages to the homepage breaks links and search indexing. - One step. The chain
http://example.ru→https://example.ru→https://www.example.ruis two unnecessary hops. Directly point to the final address. - Let’s Encrypt HTTP-01 follows redirects, so a separate
locationforacme-challengeis not strictly required, but it avoids surprises with nonstandard configurations.
Weakness of redirects: the first request still goes over plaintext. An attacker on the same network (for example on public Wi-Fi) can intercept it and prevent the user from reaching HTTPS, serving the site over HTTP through themselves. This technique is called SSL stripping, and HSTS protects against it.
HSTS
HSTS (HTTP Strict Transport Security, RFC 6797) is a response header by which a site tells the browser: “for the specified period, contact me only over HTTPS.”
Strict-Transport-Security: max-age=31536000; includeSubDomainsmax-age— duration in seconds (31536000 — one year). Each response with the header refreshes the duration;includeSubDomains— the rule applies to all subdomains;preload— consent to inclusion in the preload list (below).
Upon receiving the header, the browser:
- rewrites any
http://requests to this site tohttps://before sending the request — a server redirect is no longer needed (in developer tools this shows up as307 Internal Redirect); - does not allow the user to bypass a certificate error: there is no “Proceed anyway” button.
Rules:
- the browser accepts the header only over HTTPS; it ignores the header in an HTTP response;
- start with a small
max-age(300, then 86400, then a week) and increase it once you’re sure everything works over HTTPS. HSTS cannot be revoked quickly: browsers that have remembered the header will require HTTPS until the duration expires; - test
includeSubDomainscarefully: if you haveintranet.example.ruorprinter.example.ruwithout HTTPS, after enabling it they will stop opening for everyone who visited the main site.
In Nginx:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;HSTS preload list
HSTS only takes effect after the first HTTPS visit. The first visit remains unprotected. To close that gap, there is the preload list — a list of domains baked into Chrome, Firefox, Safari and Edge. For domains on the list, the browser uses HTTPS from the very first request.
Requirements for inclusion (hstspreload.org):
- a valid certificate;
- a redirect from HTTP to HTTPS on the same host name;
- all subdomains available over HTTPS;
- the header on the main domain:
max-ageat least 31536000,includeSubDomainsandpreload.
You can submit an application at hstspreload.org; inclusion in stable browser releases takes weeks. Removal from the list takes months and does not affect old browser versions, so preload is effectively irreversible in practice. Some top-level domains are included in the list entirely: all sites in .dev, .app, .page work only over HTTPS.
HTTPS-First in browsers
Browsers do not wait for sites to configure HSTS and try HTTPS themselves.
- Chrome since version 115 (2023) tries HTTPS first when navigating to
http://and falls back to HTTP on failure (HTTPS-Upgrades). The setting “Always Use Secure Connections” additionally warns before opening a site over HTTP. Google announced that in Chrome 154 (October 2026) this setting will be enabled by default: the browser will ask the user before the first visit to a public site without HTTPS and will not repeat the warning for sites the user visits regularly. For users with Enhanced Safe Browsing this has been enabled since April 2026. - Firefox since version 136 (March 2025) operates in HTTPS-First mode by default: it tries HTTPS and falls back to HTTP if the site does not respond. There is a stricter HTTPS-Only mode available separately.
- Safari also attempts HTTPS for addresses without a scheme.
What this means for site owners: if something other than your site answers on your domain over HTTPS (hosting placeholder, someone else’s site on the same IP, certificate error), users will increasingly see that. HTTPS must work for all names you publish, and sites without HTTPS will display warnings.
Upgrade-Insecure-Requests and mixed content
Mixed content — a page loaded over HTTPS that loads scripts, styles, or images over HTTP. Browsers block such scripts, styles and frames; images, video and audio are attempted over HTTPS and, if unavailable, are not shown.
Two similarly named things:
Request header
Upgrade-Insecure-Requests: 1. The browser sends it when navigating to a page to say “I prefer HTTPS”. The server can respond to it with a redirect to HTTPS. In practice a normal redirect is sufficient and this header is rarely used.CSP directive
upgrade-insecure-requests. A response header that tells the browser to rewrite allhttp://resource URLs on the page tohttps://before loading:Content-Security-Policy: upgrade-insecure-requestsUseful when migrating an old site whose database contains thousands of
http://image links: while the links are not fixed, the directive removes warnings. Resources must be available over HTTPS — the directive does not create HTTPS where there is none.
DNS HTTPS record
A HTTPS record (RFC 9460) informs the client of connection parameters before the first request:
example.ru. 3600 IN HTTPS 1 . alpn="h3,h2" ipv4hint=192.0.2.10- the presence of the record tells the browser the site is available over HTTPS: Chrome and Firefox will go straight to
https://, bypassing plain HTTP, just like with HSTS; alpn— which protocols are supported; withh3the browser can connect over HTTP/3 right away;ech— key for Encrypted Client Hello;ipv4hint,ipv6hint— addresses so the client does not need to wait for A/AAAA responses.
Cloudflare supports the record (creates it automatically) and some DNS hosts do as well. Check with: dig HTTPS example.ru.
Upgrade header: protocol switching
Upgrade is an HTTP/1.1 mechanism to switch from HTTP to another protocol over the same TCP connection. The client offers, the server agrees with a 101 Switching Protocols response, and the connection then carries the new protocol.
WebSocket (RFC 6455) is the main example. How WebSocket differs from SSE and long polling and when to choose each is covered in the article “WebSockets, Long Polling and SSE”. Here — how the switch itself looks:
GET /ws HTTP/1.1
Host: example.ru
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=The address wss:// is WebSocket over TLS, i.e. HTTPS is established first and then the Upgrade occurs inside it.
Upgrade and Connection are hop-by-hop headers and proxies do not forward them. Therefore explicit configuration is needed for WebSocket behind Nginx:
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
location /ws/ {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_read_timeout 3600s; # default 60s — idle connection will be closed
}
}Without these lines the client will receive 400 or 426, and the application log will show a plain GET without Upgrade.
In HTTP/2 and HTTP/3 there is no Upgrade header. WebSocket in them is opened via an extended CONNECT method (RFC 8441 for HTTP/2, RFC 9220 for HTTP/3) with a pseudo-header :protocol: websocket. Browsers and servers negotiate this themselves; Nginx still communicates with the application over HTTP/1.1.
Other uses of Upgrade:
Upgrade: h2c— switch to HTTP/2 without encryption. Browsers never supported this, and RFC 9113 (2022) deprecated the approach. Proxies that passUpgrade: h2cto applications sometimes allow bypassing their access rules (h2c smuggling) — such headers are better to drop at the edge;Upgrade: TLS/1.0— switch to TLS within an HTTP connection (RFC 2817). It did not catch on for the web; instead a separate port 443 is used.
If the server requires switching to another protocol, it responds with status 426 Upgrade Required and an Upgrade header listing the needed protocol.
Steps to migrate a site to HTTPS
- Issue certificates for all used names, including
www, and set up automatic renewal. - Verify the site fully works over HTTPS: internal links, images, forms, third-party widgets. For legacy content links use CSP
upgrade-insecure-requests. - Enable a 301 redirect from HTTP to HTTPS, preserving the path.
- Use
https://in canonical URLs, the sitemap, in Yandex Webmaster and Google Search Console. - Enable HSTS with a short
max-age, after a few weeks increase to one year and addincludeSubDomains. - If you are confident about all subdomains — submit the domain to the preload list.
Common mistakes
- Infinite redirect loop: the application behind a proxy does not see
X-Forwarded-Proto: httpsand redirects back to HTTPS; the same happens with Cloudflare in Flexible mode. - HSTS with
includeSubDomainson the main domain while subdomains lack HTTPS — internal services stop opening. - HSTS header served over HTTP — the browser ignores it and no protection is in place.
- Redirecting to the homepage instead of the same page.
- WebSocket behind Nginx without
proxy_http_version 1.1andUpgrade/Connectionheaders, or with defaultproxy_read_timeout— connections drop every minute.
// Similar task
If you are dealing with something similar
This article belongs to one of the main working topics. You can keep reading on the topic, go to the homepage to understand what I do, or open the service pages directly.
Article topic
Servers and infrastructure
VPS, Linux, web stack, migrations, hosting, databases, and core operations.
Typical tasks behind this topic
- Move a site or service to a new server
- Set up Linux, Nginx, databases, and backups
- Figure out why the system behaves unstably
// Next step
If you need help with this topic, not just another article, it is better to go straight to the service page. The homepage and topic collection stay available as secondary routes.
Open services// Reviews
Related reviews
Thanks to Mikhail for his responsiveness. We spoke by phone; he explained how I could do it myself. This is my second time reaching out — everything’s great and prompt.
Thanks to Mikhail for his responsiveness. We had a call; he explained how I could do it myself. This is my second time contacting him; everything is great and prompt.
Consultation on Nginx Proxy Manager and Portainer
2025-02-25 · ★ 5/5
I want to express my deep gratitude to the specialist who set up SEO-friendly URLs for me on OpenCart. Configuring them turned out to be easy and simple, and I'm glad I finally found a professional who did everything well and without unnecessary complications. Before this I went through four specialists, and each time there were issues with the setup, but this person handled the task perfectly.
I want to express my great gratitude to the specialist who configured SEO-friendly URLs for me on OpenCart. Setting up the URLs turned out to be easy and simple, and I'm glad that I finally found a professional who did …
Excellent work — this isn't the first time I've used them; they find solutions to complex problems. I recommend.
Excellent work, this isn't my first time contacting them; they find solutions to complex problems. I recommend.
Excellent work! He completed the assigned task on time and without errors. It was a pleasure to work with him; I recommend him.
Great job! Completed the assigned task on time and without errors. It was a pleasure to work together, I recommend.
Excellent specialist — he delved into the problem, figured it out, and fixed it. I recommend him.
Excellent specialist, delved into the problem, figured it out, and fixed it. I recommend.
I needed to resolve an SSL certificate issue on a server where the certificate had been issued through Nginx Proxy Manager. Mikhail clarified all the details of my setup and requested access to assess the feasibility of solving the issue, since he hadn't worked with that service before. He quickly figured it out and fixed my problem. Perfect cooperation)
I needed to solve an issue with an SSL certificate on the server that was issued through Ngnix Proxy manager. Mikhail clarified all the details of how everything is set up for me, asked for access to assess the …
Diagnosing Nginx Proxy Manager in a Docker container and resolving the issue
2024-03-15 · ★ 5/5
// Contact
Need help?
Get in touch with me and I'll help solve the problem
I reply within one business day (03:00-13:00 GMT)
Или оставьте заявку здесь:
// Related