HTTP Strict Transport Security (HSTS) is a security header that instructs browsers to always connect to your website over HTTPS, even if the user types http:// or clicks an HTTP link. Enabling HSTS prevents downgrade attacks and protocol confusion. This guide shows you how to enable it safely on the most common web servers and platforms.
Before Enabling HSTS: Checklist
HSTS is difficult to reverse once browsers have cached it. Before enabling, confirm:
- Your website has a valid, trusted SSL certificate installed.
- HTTPS works correctly on all subdomains (if using
includeSubDomains). - HTTP traffic redirects to HTTPS (301 redirect).
- You do not plan to move away from HTTPS — HSTS makes HTTP unavailable for the duration of
max-age. - Your SSL certificate is set to auto-renew.
max-age. If your SSL certificate expires or is misconfigured, users will be completely blocked from your site. Only enable HSTS when your HTTPS setup is confirmed stable.The HSTS Header
The HSTS header is Strict-Transport-Security. A complete header looks like:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload| Directive | Description |
|---|---|
max-age=31536000 | How long (in seconds) browsers remember to use HTTPS. 31536000 = 1 year. |
includeSubDomains | Apply HSTS to all subdomains. Only add if all subdomains have valid HTTPS. |
preload | Request inclusion in browser HSTS preload lists. Only add when ready for full commitment. |
Recommended Rollout: Start Small
Start with a short max-age and no includeSubDomains, then gradually increase:
# Stage 1: Test — 5 minutes
Strict-Transport-Security: max-age=300
# Stage 2: Short term — 1 day
Strict-Transport-Security: max-age=86400
# Stage 3: Medium term — 1 month
Strict-Transport-Security: max-age=2592000
# Stage 4: Include subdomains — 6 months
Strict-Transport-Security: max-age=15768000; includeSubDomains
# Stage 5: Full — 1 year with preload
Strict-Transport-Security: max-age=31536000; includeSubDomains; preloadEnabling HSTS on Nginx
server {
listen 443 ssl;
server_name example.com www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# Add HSTS header
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
# ... rest of your config
}
# Redirect HTTP to HTTPS
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}After editing, test and reload Nginx:
sudo nginx -t && sudo systemctl reload nginxEnabling HSTS on Apache
<VirtualHost *:443>
ServerName example.com
SSLEngine on
SSLCertificateFile /etc/ssl/fullchain.pem
SSLCertificateKeyFile /etc/ssl/private.key
# Enable HSTS
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
</VirtualHost>
<VirtualHost *:80>
ServerName example.com
# Redirect HTTP to HTTPS
Redirect permanent / https://example.com/
</VirtualHost>Make sure mod_headers is enabled:
sudo a2enmod headers
sudo systemctl restart apache2Enabling HSTS on Cloudflare
- Log in to the Cloudflare dashboard and select your domain.
- Go to SSL/TLS → Edge Certificates.
- Scroll to HTTP Strict Transport Security (HSTS).
- Click Enable HSTS.
- Configure
max-age,includeSubDomains, andpreloadas needed. - Click Save.
Enabling HSTS in Next.js
// next.config.mjs
const nextConfig = {
async headers() {
return [
{
source: '/(.*)',
headers: [
{
key: 'Strict-Transport-Security',
value: 'max-age=31536000; includeSubDomains; preload',
},
],
},
];
},
};
export default nextConfig;Verifying HSTS Is Active
Check that the HSTS header is being sent correctly:
# Check with curl
curl -I https://example.com | grep -i "strict-transport"
# Expected: strict-transport-security: max-age=31536000; includeSubDomains; preload
# Check with openssl
openssl s_client -connect example.com:443 -quiet | head -20Or use the ShowDNS HSTS Checker to verify the header is present and correctly configured.
Frequently Asked Questions
Can I remove HSTS once set?
To remove HSTS, set max-age=0 in the Strict-Transport-Security header. This tells browsers to stop enforcing HSTS for your domain. However, users who already have the old HSTS cached will still enforce HTTPS until their cached value expires.
What happens if my SSL certificate expires while HSTS is active?
Users with HSTS cached will be unable to access your site. Their browser will refuse both the HTTP and HTTPS connections — HTTP because of HSTS, HTTPS because of the invalid certificate. This is why HSTS requires a robust SSL renewal process.
Should I add the preload directive immediately?
No. The preload directive requests inclusion in browser HSTS preload lists. Once included, removing the domain from these lists takes months. Only add preload when you are fully committed to HTTPS for your domain and all subdomains indefinitely.