HostiServer
2025-12-30 11:00:00
301 Redirect HTTP to HTTPS: Complete Guide for Apache, Nginx, Cloudflare
⏱️ Reading time: ~11 minutes | 📅 Updated: December 30, 2025
HTTP in 2026 — it's not just outdated. It's dangerous
Browsers mark HTTP sites as "Not Secure". Google ranks them lower in search results. Users see warnings and close the tab. And if your site has a form — password, email, credit card number — all that data flies across the network in plain text.
SSL/TLS certificates are free today (thanks to Let's Encrypt). There's no reason to stay on HTTP. But installing a certificate is only half the job. The other half is properly configuring the redirect so all traffic automatically goes through HTTPS.
Seems simple, right? Add one line to the config and you're done. But in practice, this is where problems arise: endless redirect loops, mixed content, loss of search rankings due to improper canonicalization, CDN issues.
This article covers how to do everything right the first time. Specific configs for Apache, Nginx, Cloudflare. What can go wrong and how to fix it.
301 redirect: what it is and why specifically 301
An HTTP redirect is an instruction to the browser: "The page isn't here, go to this address". Code 301 means "Moved Permanently".
Why 301, not 302 or 307?
301 (Moved Permanently) — permanent redirect. Search engines pass link weight to the new address. Browsers cache the redirect, so repeat requests go directly to HTTPS.
302 (Found / Temporary Redirect) — temporary. Search engines don't pass weight because they consider it temporary. Wrong choice for HTTP→HTTPS.
307 (Temporary Redirect) — also temporary, but preserves the request method (POST stays POST). Not suitable for regular HTTPS redirect.
308 (Permanent Redirect) — like 301, but preserves method. Can be used, but 301 is more compatible with older browsers.
Redirect chains: why they're bad
Common mistake: http://example.com → http://www.example.com → https://www.example.com → https://example.com. Four hops instead of one.
Each redirect adds 50-200ms delay. For mobile users on slow connections, this is critical. Google counts this as part of load time.
Correct approach: one redirect straight to the final address. Decide which version is canonical (with www or without), and redirect everything there.
Apache: proper configuration
For Apache, the recommended method is through VirtualHost configuration, not .htaccess. VirtualHost is faster because .htaccess is re-read on every request.
Basic redirect via VirtualHost
<VirtualHost *:80>
ServerName example.com
ServerAlias www.example.com
Redirect permanent / https://example.com/
</VirtualHost>
<VirtualHost *:443>
ServerName example.com
SSLEngine on
SSLCertificateFile /etc/ssl/cert.pem
SSLCertificateKeyFile /etc/ssl/key.pem
DocumentRoot /var/www/html
</VirtualHost>
Differences between Apache 2.2 and 2.4
If you're upgrading from Apache 2.2 to 2.4, the access control configuration has changed. This is a common source of "403 Forbidden" errors after upgrade.
| Feature | Apache 2.2 | Apache 2.4 |
|---|---|---|
| Access control | Order allow,deny |
Require all granted |
| Authorization module | mod_authz_host.so |
mod_authz_core.so |
| AllowOverride | AllowOverride All |
AllowOverride None |
| Logging | LogLevel warn |
LogLevel warn rewrite:trace3 |
Apache behind Reverse Proxy
If Apache sits behind a load balancer or proxy, the client connects to the proxy via HTTPS, and the proxy forwards the request to Apache via HTTP. A regular redirect will create a loop.
First, enable the required modules:
a2enmod proxy proxy_http headers rewrite ssl
systemctl reload apache2
Configuration for reverse proxy:
<VirtualHost *:80>
ServerName example.com
ProxyPreserveHost On
ProxyRequests Off
ProxyPass / http://127.0.0.1:8080/
ProxyPassReverse / http://127.0.0.1:8080/
RequestHeader set X-Forwarded-Proto "http"
</VirtualHost>
<VirtualHost *:443>
ServerName example.com
SSLEngine on
SSLCertificateFile /etc/ssl/cert.pem
SSLCertificateKeyFile /etc/ssl/key.pem
ProxyPreserveHost On
ProxyRequests Off
ProxyPass / http://127.0.0.1:8080/
ProxyPassReverse / http://127.0.0.1:8080/
RequestHeader set X-Forwarded-Proto "https"
</VirtualHost>
The backend application checks the X-Forwarded-Proto header and redirects only if it's not "https":
RewriteCond %{HTTP:X-Forwarded-Proto} !=https
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
Nginx: optimal configuration
Nginx is the most popular web server for high-load projects. Redirect setup here is simpler than in Apache.
return 301 vs rewrite: which is better?
Use return 301 — this is the recommended option. It's simpler, processes faster (no regex), immediately forms a response and doesn't go through other processing phases.
rewrite is only needed if you require complex logic with regular expressions.
Basic redirect
server {
listen 80;
server_name example.com www.example.com;
return 301 https://example.com$request_uri;
}
HTTPS with HTTP/2
HTTP/2 is stable and recommended whenever HTTPS is enabled. Provides noticeable loading speed improvement through request multiplexing.
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /etc/ssl/cert.pem;
ssl_certificate_key /etc/ssl/key.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off; # for TLS 1.3
keepalive_timeout 65;
keepalive_requests 1000;
gzip on;
gzip_types text/plain text/css application/json application/javascript;
root /var/www/html;
}
HTTP/3 (QUIC) — experimental
HTTP/3 in Nginx is still experimental. Use only if you're ready for testing and potential issues.
server {
listen 443 ssl http2;
listen 443 quic reuseport;
ssl_protocols TLSv1.3;
ssl_certificate /etc/ssl/cert.pem;
ssl_certificate_key /etc/ssl/key.pem;
add_header Alt-Svc 'h3=":443"; ma=86400';
}
The Alt-Svc header tells the browser that HTTP/3 is available. The browser will try the next connection via QUIC.
Nginx with Upstream (load balancing)
If Nginx works as a load balancer in front of multiple backend servers:
upstream backend {
server 127.0.0.1:8080;
keepalive 32;
}
server {
listen 80;
server_name example.com www.example.com;
return 301 https://example.com$request_uri;
}
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /etc/ssl/cert.pem;
ssl_certificate_key /etc/ssl/key.pem;
location / {
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $remote_addr;
}
}
Note the X-Forwarded-Proto — the backend receives information about the original protocol and can properly form links.
Cloudflare and CDN: redirect at the edge
If you use Cloudflare or another CDN, you can redirect at the CDN level — before the request even reaches your server.
Recommended architecture
Client
↓
Cloudflare (redirects, edge logic)
↓
Nginx (origin, app logic)
↓
Upstream / Backend
Benefits of CDN-level redirect: faster (response from nearest edge server), less load on origin.
How to avoid redirect loops
Most common problem: CDN redirects to HTTPS, and the server also redirects because it sees an HTTP connection from the CDN. Result — endless loop.
Solution: set SSL mode to "Full (strict)" in Cloudflare. This means:
- Cloudflare connects to your server via HTTPS
- Validates the certificate on the server
- Your server sees an HTTPS connection and doesn't redirect
"Flexible" mode (Cloudflare→server via HTTP) is a compromise for servers without a certificate. If you have a certificate — use Full (strict).
Page Rules for HTTPS
In Cloudflare, you can set up Page Rules for automatic redirect:
| URL Pattern | Action |
|---|---|
http://example.com/* |
Always Use HTTPS |
http://www.example.com/* |
Always Use HTTPS |
https://www.example.com/* |
301 Redirect → https://example.com/$1 |
The first two rules convert HTTP to HTTPS. The third canonicalizes www to the non-www version (or vice versa, depending on your choice).
HSTS: enforced HTTPS at the browser level
HSTS (HTTP Strict Transport Security) is a header that tells the browser: "Never connect to this domain via HTTP. Even if the user types http:// — use https://".
How to configure
Strict-Transport-Security: max-age=31536000; includeSubDomains
max-age=31536000 — the browser will remember this policy for one year (in seconds).
includeSubDomains — the policy applies to all subdomains.
For Nginx:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
HSTS Preload — use with caution!
HSTS Preload means adding your domain to a list built into browsers. The browser will use HTTPS even on the first visit, without needing to receive the header first.
⚠️ In most cases, we DO NOT recommend HSTS Preload.
Recommended only for rock-solid domains where you're 100% certain HTTP will never be needed.
HSTS risks
- Complete unavailability during TLS issues: if the certificate expires or something breaks — the site becomes inaccessible. The browser won't let users bypass the warning.
- No quick rollback possible: after removal from the preload list, it takes months for all browsers to update.
- includeSubDomains breaks subdomains: if you have dev.example.com without HTTPS — it becomes inaccessible.
- Direct IP access impossible: if someone accesses the server by IP — HSTS won't work because it's tied to the domain. But if the domain previously worked with HSTS, the browser will block HTTP even when trying to bypass.
Start with a short max-age (86400 — one day). Make sure everything works. Gradually increase to one year.
Tools for verification
After configuring redirects, be sure to verify everything works correctly. Here are the tools we recommend.
Security and HTTPS/TLS
| Tool | What it checks |
|---|---|
| SSL Labs (Qualys) | TLS, certificate chain, protocols, ciphers — deep audit |
| Hardenize | TLS, HSTS, DNSSEC, cookies, PKI — comprehensive security assessment |
| Observatory (Mozilla) | Headers, CORS, TLS — quick security health-check |
| SecurityHeaders.com | HSTS, CSP, X-Frame-Options — HTTP security headers |
Checking the redirect chain
The simplest way — curl from terminal:
curl -IL https://example.com | grep -Ei 'HTTP/|Location|Server|cf-'
The -I flag shows only headers, -L follows redirects. You'll see the entire chain: HTTP/1.1 301, Location, then HTTP/2 200 on the final page.
Performance and CDN
| Tool | What it checks |
|---|---|
| WebPageTest | RUM/LAB metrics, filmstrip, waterfall — detailed breakdown |
| Lighthouse (Chrome DevTools) | SEO, performance, accessibility — all in one |
| GTmetrix | PageSpeed + Waterfall — practical optimization plan |
What to look for
- One redirect, no more. http:// → https:// directly.
- Correct response code: 301 for permanent redirect.
- Canonical version: either with www or without — but one.
- HSTS header present on the HTTPS version.
- Certificate is valid and chain is complete.
Common mistakes and how to avoid them
Redirect Loop (ERR_TOO_MANY_REDIRECTS)
Browser shows error "This page isn't working" with code ERR_TOO_MANY_REDIRECTS.
Causes:
- CDN redirects to HTTPS, server also redirects (because it sees HTTP from CDN)
- Double redirect in .htaccess and VirtualHost simultaneously
- WordPress with HTTPS plugin + server-side redirect
- Incorrect rules for www/non-www
Diagnosis: curl -IL http://example.com — see how many redirects and where.
Solution: redirect should be in one place only. If CDN — only on CDN. If server — only on server. When using Cloudflare — SSL mode Full (strict).
Mixed Content
Page loads via HTTPS, but some resources (images, scripts, styles) load via HTTP. Browser blocks or shows warning.
Diagnosis:
- Chrome DevTools → Console — look for "Mixed Content" warnings
- Chrome DevTools → Security tab — will show insecure resources
Solution:
- Find all http:// links in code and replace with https:// or //
- Check database (WordPress often stores absolute URLs)
- Add CSP header:
Content-Security-Policy: upgrade-insecure-requests— browser will automatically replace http with https
Certificate doesn't cover www
Certificate issued for example.com, but not for www.example.com. Visiting www shows browser warning.
Solution: get a certificate for both variants. Let's Encrypt allows including multiple domains: certbot -d example.com -d www.example.com
Redirect without preserving path
http://example.com/about → https://example.com/ (without /about)
User loses context, search engines see 404 for old URLs.
Solution: make sure the redirect preserves URI:
# Nginx — correct
return 301 https://example.com$request_uri;
# Nginx — incorrect (loses path)
return 301 https://example.com;
SSL certificates: Let's Encrypt and Wildcard
Let's Encrypt — automation
Let's Encrypt — free certificates with automatic renewal. This is the standard for most websites.
Certificates are issued for 90 days, so automatic renewal is critically important. Certbot usually sets up a cron job automatically:
# Check if auto-renewal is configured
systemctl list-timers | grep certbot
# Or check cron
cat /etc/cron.d/certbot
Test renewal run (without actual renewal):
certbot renew --dry-run
Wildcard certificates
A wildcard certificate (*.example.com) covers all single-level subdomains: blog.example.com, shop.example.com, api.example.com.
When we recommend:
- Many subdomains that change frequently
- Dynamically created subdomains (user1.example.com, user2.example.com)
- Simplified management — one certificate instead of dozens
Important: wildcard covers only one level. *.example.com covers blog.example.com, but does NOT cover dev.blog.example.com.
Let's Encrypt issues wildcard certificates via DNS challenge:
certbot certonly --manual --preferred-challenges dns \
-d example.com -d *.example.com
For automating DNS challenge, you need a plugin for your DNS provider (Cloudflare, Route53, DigitalOcean, etc.).
Checklist: 301 redirect HTTP→HTTPS
Before launching, go through this list:
Preparation
- ☐ SSL certificate installed and valid
- ☐ Certificate covers all required domains (main + www)
- ☐ Automatic certificate renewal configured
- ☐ Canonical version determined (with www or without)
Redirect configuration
- ☐ Redirect in only one place (server OR CDN, not both)
- ☐ Using code 301 (not 302)
- ☐ Full path preserved ($request_uri)
- ☐ Single redirect, not a chain
If using CDN
- ☐ SSL mode Full (strict) in Cloudflare
- ☐ Page Rules for HTTPS configured
- ☐ Server-side redirect disabled (to avoid loop)
After launch
- ☐ Verified curl -IL — one 301, then 200
- ☐ SSL Labs shows A or higher
- ☐ No Mixed Content in browser console
- ☐ HSTS header present
- ☐ Internal links updated to https://
- ☐ Sitemap updated with https:// URLs
- ☐ Google Search Console — HTTPS version added
Need help with configuration?
We'll configure redirects, SSL and HSTS on our servers. Or help you figure out your configuration.
💻 Cloud (VPS) Hosting
- From $19.95/month — Start small, scale instantly
- KVM virtualization — Guaranteed resources without overselling
- Instant upgrades — No downtime
- NVMe storage — Fast performance
- 24/7 support — <10 min response
🖥️ Dedicated Servers
- From $200/month — Modern configurations
- Custom configurations — Intel or AMD, latest models
- Multiple locations — EU + USA
- 99.9% uptime — Reliability
- DDoS protection — Included
- Free migration — We'll help
- Private Cloud support — Proxmox, VMware, OpenStack
💬 Not sure which option you need?
💬 Contact us and we'll help with everything!
FAQ:Frequently Asked Questions
- Will the redirect affect SEO?
-
A proper 301 redirect passes ~90-99% of link weight. Google officially confirms that HTTPS is a ranking factor.
Short-term ranking drops are possible (while Google re-indexes), but in the long term HTTPS is better for SEO.
- Do I need a paid certificate?
-
For most sites — no. Let's Encrypt provides the same level of encryption.
Paid certificates (OV, EV) provide extended company validation, but this only matters for:
- Banks
- Financial institutions
- Large e-commerce sites
- What about old links?
-
301 redirect automatically forwards old HTTP links. But it's better to update manually:
- Internal links on the site
- Links in social media and profiles
- Google Search Console and Analytics settings
- Sitemap (should contain only https:// URLs)
- How do I check if HSTS is working?
-
Option 1: Open DevTools → Network → select any request → Response Headers. Look for
Strict-Transport-Security.Option 2: Check on securityheaders.com — it will show the score and all headers.
- Redirect works, but site is slow. Why?
-
Possible causes:
- Long redirect chain: Check using
curl -IL - Slow TLS handshake: Outdated server settings
- Server location: Too far from users (need CDN)
- OCSP stapling: Check if enabled — without it, the browser makes an extra request to verify the certificate.
- Long redirect chain: Check using
- Can HSTS be rolled back?
-
Yes, but slowly. Set
max-age=0and wait for the old term to expire in browser caches.Warning: If you used HSTS Preload, the process will take months. That's why you should start with a short max-age.