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 Property | Benefit |
|---|---|
| Confidentiality | Traffic is encrypted |
| Integrity | Data cannot be modified |
| Authentication | Server identity verified |
| Trust | Browser shows secure lock 🔒 |
How HTTP → HTTPS Redirection Works in NGINX
- Client connects via HTTP (port 80)
- NGINX responds with a 301 or 308 redirect
- Browser requests the same URL over HTTPS
- Secure TLS connection is established
Recommended Redirect Status Codes
| Code | Meaning | Recommended? |
|---|---|---|
| 301 | Permanent redirect | ✅ Yes |
| 308 | Permanent redirect (method preserved) | ✅ Best |
| 302 | Temporary | ❌ No |
| 307 | Temporary (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;
}
| Directive | Purpose |
|---|---|
listen 80 | Accept HTTP traffic |
server_name | Match domain |
return 301 | Send permanent redirect |
$host$request_uri | Preserve 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.
Redirect with rewrite (Not Recommended)
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
| Mistake | Risk |
|---|---|
| Using 302 instead of 301 | Downgrade attacks |
| Redirecting in HTTPS block | Redirect loop |
Forgetting $request_uri | Broken URLs |
| Not redirecting all domains | Inconsistent security |
| No HSTS | SSL 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