How to Configure HSTS in Nginx for Secure HTTPS
To configure
HSTS in nginx, add the header Strict-Transport-Security inside your server block that listens on HTTPS. For example, use add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; to enforce HTTPS for one year including subdomains.Syntax
The Strict-Transport-Security header tells browsers to only use HTTPS for your site for a set time. It has these parts:
- max-age: Time in seconds browsers remember to use HTTPS (e.g., 31536000 for 1 year).
- includeSubDomains: Optional; applies rule to all subdomains.
- preload: Optional; requests inclusion in browser preload lists.
- always: Ensures header is sent on all responses, including errors.
nginx
add_header Strict-Transport-Security "max-age=SECONDS; includeSubDomains; preload" always;Example
This example shows how to enable HSTS in an HTTPS server block for one year, including subdomains and preload request.
nginx
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /etc/ssl/certs/example.com.crt;
ssl_certificate_key /etc/ssl/private/example.com.key;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
location / {
root /var/www/html;
index index.html;
}
}Output
When a browser visits https://example.com, the response header includes:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Common Pitfalls
Common mistakes when configuring HSTS in nginx include:
- Adding the header in the HTTP (port 80) block instead of HTTPS (port 443) block, so browsers never receive it securely.
- Omitting
always, causing the header to be missing on error pages. - Setting
max-agetoo low or forgettingincludeSubDomainswhen needed. - Enabling HSTS before HTTPS is fully working, which can lock users out.
nginx
server {
listen 80;
server_name example.com;
# Wrong: HSTS header on HTTP block
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload";
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /etc/ssl/certs/example.com.crt;
ssl_certificate_key /etc/ssl/private/example.com.key;
# Correct: HSTS header with 'always' to send on all responses
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
location / {
root /var/www/html;
index index.html;
}
}Quick Reference
Remember these tips when configuring HSTS in nginx:
- Always add the header in the HTTPS server block.
- Use
alwaysto ensure header is sent on all responses. - Set
max-ageto at least 6 months (recommended 1 year). - Include
includeSubDomainsif you want all subdomains secured. - Use
preloadonly if you plan to submit your site to browser preload lists.
Key Takeaways
Add the Strict-Transport-Security header only in the HTTPS server block.
Use the 'always' parameter to send HSTS header on all responses including errors.
Set max-age to a long duration like 31536000 seconds (1 year) for strong security.
Include 'includeSubDomains' to protect all subdomains under your domain.
Test HTTPS fully before enabling HSTS to avoid locking out users.