Skip to main content

HTTP to HTTPS

HTTP → HTTPS redirection forces all users who access your site over unencrypted HTTP (port 80) to be automatically redirected to encrypted HTTPS (port 443).

http://example.com/page → https://example.com/page

This is a fundamental web security control.

Why Redirecting HTTP to HTTPS Is Critical for Security

Without HTTPS redirection:

  • Credentials can be sniffed on public Wi-Fi
  • Session cookies can be stolen
  • Data can be modified in transit
  • Users can be subjected to MITM (Man-in-the-Middle) attacks

Redirecting HTTP → HTTPS ensures:

Security PropertyBenefit
ConfidentialityTraffic is encrypted
IntegrityData cannot be modified
AuthenticationServer identity verified
TrustBrowser shows secure lock 🔒

How HTTP → HTTPS Redirection Works in NGINX

  1. Client connects via HTTP (port 80)
  2. NGINX responds with a 301 or 308 redirect
  3. Browser requests the same URL over HTTPS
  4. Secure TLS connection is established
CodeMeaningRecommended?
301Permanent redirect✅ Yes
308Permanent redirect (method preserved)✅ Best
302Temporary❌ No
307Temporary (method preserved)❌ No

Best practice: Use 301 or 308

Best Practice: Separate HTTP Server Block

Most Secure & Clean Method

server {
listen 80;
server_name example.com www.example.com;

return 301 https://$host$request_uri;
}
DirectivePurpose
listen 80Accept HTTP traffic
server_nameMatch domain
return 301Send permanent redirect
$host$request_uriPreserve domain + path

Using 308 Redirect (Method-Preserving)

Why 308?

  • Preserves HTTP methods (POST, PUT)
  • Prevents form resubmission issues
server {
listen 80;
server_name example.com;

return 308 https://$host$request_uri;
}

Ideal for APIs and REST services.

server {
listen 80;
server_name example.com;

rewrite ^ https://$host$request_uri? permanent;
}

Problems:

  • Slower than return
  • Harder to read
  • Regex overhead

Works, but avoid unless necessary

Redirect Inside HTTPS Server Block

server {
listen 443 ssl;
return 301 https://$host$request_uri;
}

This causes:

  • Infinite redirect loops
  • Broken SSL negotiation

Redirect All Domains to One Canonical HTTPS Domain

Example: redirect www → non-www

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

HTTPS version:

server {
listen 443 ssl;
server_name www.example.com;

ssl_certificate /path/fullchain.pem;
ssl_certificate_key /path/privkey.pem;

return 301 https://example.com$request_uri;
}
  • Prevents duplicate content
  • Improves SEO
  • Simplifies certificates

Combining HTTP → HTTPS Redirect with SSL Config

# HTTP → HTTPS
server {
listen 80;
server_name example.com www.example.com;
return 301 https://example.com$request_uri;
}

# HTTPS Server
server {
listen 443 ssl http2;
server_name example.com;

ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

root /var/www/html;
index index.html;
}

Enforcing HTTPS with HSTS (Advanced Security)

HTTP Strict Transport Security tells browsers:

“Never use HTTP for this site again”

add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;

Effect:

  • Browser skips HTTP entirely
  • Protects against SSL stripping attacks

Warning:

  • HSTS is hard to undo
  • Enable only after HTTPS works perfectly

Common Security Mistakes

MistakeRisk
Using 302 instead of 301Downgrade attacks
Redirecting in HTTPS blockRedirect loop
Forgetting $request_uriBroken URLs
Not redirecting all domainsInconsistent security
No HSTSSSL stripping possible

How to Test HTTP → HTTPS Redirect

CLI Test

curl -I http://example.com

Expected:

HTTP/1.1 301 Moved Permanently
Location: https://example.com/

Browser Test

  • Enter http://example.com
  • Should auto-switch to HTTPS