[{"data":1,"prerenderedAt":895},["ShallowReactive",2],{"blog-how-to/hsts-setup":3},{"id":4,"title":5,"body":6,"category":865,"date":866,"dateModified":866,"description":867,"draft":868,"extension":869,"faq":870,"featured":868,"headerVariant":881,"image":882,"keywords":882,"meta":883,"navigation":884,"ogDescription":885,"ogTitle":882,"path":886,"readTime":882,"schemaOrg":887,"schemaType":888,"seo":889,"sitemap":890,"stem":891,"tags":892,"twitterCard":893,"__hash__":894},"blog/blog/how-to/hsts-setup.md","How to Set Up HSTS (HTTP Strict Transport Security)",{"type":7,"value":8,"toc":833},"minimark",[9,13,17,21,39,44,63,67,74,83,87,97,151,156,228,232,271,337,375,414,476,543,567,571,575,581,585,600,604,620,624,630,634,643,647,651,671,675,699,703,722,726,750,759,763,797,809],[10,11],"category-badge",{"category":12},"How-To Guide",[14,15,5],"h1",{"id":16},"how-to-set-up-hsts-http-strict-transport-security",[18,19,20],"p",{},"Force HTTPS connections and prevent downgrade attacks",[22,23,24,27],"tldr",{},[18,25,26],{},"TL;DR (15 minutes)",[18,28,29,30,34,35,38],{},"HSTS forces browsers to use HTTPS only. Add the header ",[31,32,33],"code",{},"Strict-Transport-Security: max-age=31536000; includeSubDomains"," after verifying your site works over HTTPS. Start with a short max-age (300 seconds) for testing. Only use ",[31,36,37],{},"includeSubDomains"," if all subdomains support HTTPS. Consider preload list submission for maximum security.",[40,41,43],"h2",{"id":42},"prerequisites","Prerequisites",[45,46,47,51,54,57,60],"ul",{},[48,49,50],"li",{},"Valid SSL/TLS certificate installed (Let's Encrypt, commercial CA, etc.)",[48,52,53],{},"Your site accessible via HTTPS without certificate errors",[48,55,56],{},"All resources (images, scripts, styles) loaded over HTTPS",[48,58,59],{},"HTTP to HTTPS redirect already configured",[48,61,62],{},"If using includeSubDomains: all subdomains must support HTTPS",[40,64,66],{"id":65},"what-is-hsts","What is HSTS?",[18,68,69,70,73],{},"HSTS (HTTP Strict Transport Security) tells browsers to only connect to your site using HTTPS, even if a user types ",[31,71,72],{},"http://"," or clicks an HTTP link.",[75,76,77,80],"warning-box",{},[18,78,79],{},"Why HSTS Matters",[18,81,82],{},"Without HSTS, an attacker can intercept the initial HTTP request before your redirect happens. This is called a \"protocol downgrade attack\" or \"SSL stripping.\" HSTS prevents this by making browsers refuse HTTP connections entirely.",[40,84,86],{"id":85},"hsts-header-syntax","HSTS Header Syntax",[88,89,94],"pre",{"className":90,"code":92,"language":93},[91],"language-text","Strict-Transport-Security: max-age=\u003Cseconds>; includeSubDomains; preload\n","text",[31,95,92],{"__ignoreMap":96},"",[98,99,100,116],"table",{},[101,102,103],"thead",{},[104,105,106,110,113],"tr",{},[107,108,109],"th",{},"Directive",[107,111,112],{},"Required",[107,114,115],{},"Description",[117,118,119,131,141],"tbody",{},[104,120,121,125,128],{},[122,123,124],"td",{},"max-age",[122,126,127],{},"Yes",[122,129,130],{},"How long (in seconds) browsers should remember to use HTTPS",[104,132,133,135,138],{},[122,134,37],{},[122,136,137],{},"No",[122,139,140],{},"Apply HSTS to all subdomains (*.example.com)",[104,142,143,146,148],{},[122,144,145],{},"preload",[122,147,137],{},[122,149,150],{},"Consent to being added to browser preload lists",[152,153,155],"h3",{"id":154},"common-max-age-values","Common max-age Values",[98,157,158,171],{},[101,159,160],{},[104,161,162,165,168],{},[107,163,164],{},"Value",[107,166,167],{},"Duration",[107,169,170],{},"Use Case",[117,172,173,184,195,206,217],{},[104,174,175,178,181],{},[122,176,177],{},"300",[122,179,180],{},"5 minutes",[122,182,183],{},"Initial testing",[104,185,186,189,192],{},[122,187,188],{},"86400",[122,190,191],{},"1 day",[122,193,194],{},"Extended testing",[104,196,197,200,203],{},[122,198,199],{},"604800",[122,201,202],{},"1 week",[122,204,205],{},"Staging/verification",[104,207,208,211,214],{},[122,209,210],{},"31536000",[122,212,213],{},"1 year",[122,215,216],{},"Production (recommended)",[104,218,219,222,225],{},[122,220,221],{},"63072000",[122,223,224],{},"2 years",[122,226,227],{},"Maximum security",[40,229,231],{"id":230},"step-by-step-implementation","Step-by-Step Implementation",[233,234,236,240,243,249],"step",{"number":235},"1",[152,237,239],{"id":238},"verify-https-is-working-properly","Verify HTTPS is Working Properly",[18,241,242],{},"Before enabling HSTS, ensure your site is fully HTTPS-ready:",[88,244,247],{"className":245,"code":246,"language":93},[91],"# Check SSL certificate\ncurl -vI https://yoursite.com 2>&1 | grep -A 6 \"Server certificate\"\n\n# Check for mixed content (HTTP resources on HTTPS page)\n# Open Chrome DevTools > Console > Look for \"Mixed Content\" warnings\n\n# Verify redirect is in place\ncurl -I http://yoursite.com\n# Should return 301/302 redirect to https://\n",[31,248,246],{"__ignoreMap":96},[75,250,251,254],{},[18,252,253],{},"Pre-flight Checklist",[45,255,256,259,262,265,268],{},[48,257,258],{},"SSL certificate is valid and not expiring soon",[48,260,261],{},"All pages accessible via HTTPS",[48,263,264],{},"No mixed content warnings in browser console",[48,266,267],{},"HTTP to HTTPS redirect working",[48,269,270],{},"All subdomains support HTTPS (if using includeSubDomains)",[233,272,274,278,281,287,293,298,304,309,315,320,326,331],{"number":273},"2",[152,275,277],{"id":276},"start-with-a-short-max-age-for-testing","Start with a Short max-age for Testing",[18,279,280],{},"Add HSTS with a 5-minute max-age to test safely:",[18,282,283],{},[284,285,286],"strong",{},"nginx:",[88,288,291],{"className":289,"code":290,"language":93},[91],"server {\n    listen 443 ssl http2;\n    server_name yoursite.com;\n\n    # HSTS - Start with short max-age for testing\n    add_header Strict-Transport-Security \"max-age=300\" always;\n\n    # ... rest of config\n}\n",[31,292,290],{"__ignoreMap":96},[18,294,295],{},[284,296,297],{},"Apache:",[88,299,302],{"className":300,"code":301,"language":93},[91],"\u003CVirtualHost *:443>\n    ServerName yoursite.com\n\n    # HSTS - Start with short max-age for testing\n    Header always set Strict-Transport-Security \"max-age=300\"\n\n    # ... rest of config\n\u003C/VirtualHost>\n",[31,303,301],{"__ignoreMap":96},[18,305,306],{},[284,307,308],{},"Express.js:",[88,310,313],{"className":311,"code":312,"language":93},[91],"const helmet = require('helmet');\n\n// HSTS with short max-age for testing\napp.use(helmet.hsts({\n  maxAge: 300, // 5 minutes\n  includeSubDomains: false,\n  preload: false\n}));\n",[31,314,312],{"__ignoreMap":96},[18,316,317],{},[284,318,319],{},"Vercel (vercel.json):",[88,321,324],{"className":322,"code":323,"language":93},[91],"{\n  \"headers\": [\n    {\n      \"source\": \"/(.*)\",\n      \"headers\": [\n        {\n          \"key\": \"Strict-Transport-Security\",\n          \"value\": \"max-age=300\"\n        }\n      ]\n    }\n  ]\n}\n",[31,325,323],{"__ignoreMap":96},[18,327,328],{},[284,329,330],{},"Netlify (_headers):",[88,332,335],{"className":333,"code":334,"language":93},[91],"/*\n  Strict-Transport-Security: max-age=300\n",[31,336,334],{"__ignoreMap":96},[233,338,340,344,350,353],{"number":339},"3",[152,341,343],{"id":342},"verify-the-header-is-being-sent","Verify the Header is Being Sent",[88,345,348],{"className":346,"code":347,"language":93},[91],"# Check HSTS header with curl\ncurl -I https://yoursite.com | grep -i strict-transport-security\n\n# Expected output:\n# strict-transport-security: max-age=300\n",[31,349,347],{"__ignoreMap":96},[18,351,352],{},"Or check in browser DevTools:",[354,355,356,359,362,365,368],"ol",{},[48,357,358],{},"Open DevTools (F12)",[48,360,361],{},"Go to Network tab",[48,363,364],{},"Reload the page",[48,366,367],{},"Click on the document request",[48,369,370,371,374],{},"Find ",[31,372,373],{},"strict-transport-security"," in Response Headers",[233,376,378,382,385,403,408],{"number":377},"4",[152,379,381],{"id":380},"test-hsts-behavior","Test HSTS Behavior",[18,383,384],{},"Verify browsers redirect HTTP to HTTPS without contacting your server:",[354,386,387,390,397,400],{},[48,388,389],{},"Visit your site via HTTPS to receive the HSTS header",[48,391,392,393,396],{},"Type ",[31,394,395],{},"http://yoursite.com"," in the address bar",[48,398,399],{},"The browser should redirect to HTTPS immediately (internal redirect)",[48,401,402],{},"Check Network tab - you should see a \"307 Internal Redirect\"",[18,404,405],{},[284,406,407],{},"Check HSTS status in Chrome:",[88,409,412],{"className":410,"code":411,"language":93},[91],"# Visit this URL in Chrome\nchrome://net-internals/#hsts\n\n# Query your domain to see HSTS status\n# Delete the entry if you need to reset during testing\n",[31,413,411],{"__ignoreMap":96},[233,415,417,421,424,428,434,438,444,448,454,459,465,470],{"number":416},"5",[152,418,420],{"id":419},"increase-max-age-for-production","Increase max-age for Production",[18,422,423],{},"Once verified, increase to 1 year (required for preload list):",[18,425,426],{},[284,427,286],{},[88,429,432],{"className":430,"code":431,"language":93},[91],"add_header Strict-Transport-Security \"max-age=31536000; includeSubDomains\" always;\n",[31,433,431],{"__ignoreMap":96},[18,435,436],{},[284,437,297],{},[88,439,442],{"className":440,"code":441,"language":93},[91],"Header always set Strict-Transport-Security \"max-age=31536000; includeSubDomains\"\n",[31,443,441],{"__ignoreMap":96},[18,445,446],{},[284,447,308],{},[88,449,452],{"className":450,"code":451,"language":93},[91],"app.use(helmet.hsts({\n  maxAge: 31536000, // 1 year\n  includeSubDomains: true,\n  preload: false // Don't add preload yet\n}));\n",[31,453,451],{"__ignoreMap":96},[18,455,456],{},[284,457,458],{},"Vercel:",[88,460,463],{"className":461,"code":462,"language":93},[91],"{\n  \"headers\": [\n    {\n      \"source\": \"/(.*)\",\n      \"headers\": [\n        {\n          \"key\": \"Strict-Transport-Security\",\n          \"value\": \"max-age=31536000; includeSubDomains\"\n        }\n      ]\n    }\n  ]\n}\n",[31,464,462],{"__ignoreMap":96},[18,466,467],{},[284,468,469],{},"Netlify:",[88,471,474],{"className":472,"code":473,"language":93},[91],"/*\n  Strict-Transport-Security: max-age=31536000; includeSubDomains\n",[31,475,473],{"__ignoreMap":96},[233,477,479,483,486,491,511,516,522,535],{"number":478},"6",[152,480,482],{"id":481},"submit-to-hsts-preload-list-optional","Submit to HSTS Preload List (Optional)",[18,484,485],{},"For maximum security, submit your domain to the browser preload list:",[18,487,488],{},[284,489,490],{},"Requirements for preload:",[45,492,493,496,499,502,505,508],{},[48,494,495],{},"Serve a valid SSL certificate",[48,497,498],{},"Redirect all HTTP to HTTPS on the same host",[48,500,501],{},"All subdomains must support HTTPS",[48,503,504],{},"HSTS header with: max-age of at least 1 year (31536000)",[48,506,507],{},"HSTS header with: includeSubDomains directive",[48,509,510],{},"HSTS header with: preload directive",[18,512,513],{},[284,514,515],{},"Update your HSTS header for preload:",[88,517,520],{"className":518,"code":519,"language":93},[91],"Strict-Transport-Security: max-age=31536000; includeSubDomains; preload\n",[31,521,519],{"__ignoreMap":96},[18,523,524,527,528],{},[284,525,526],{},"Submit at:"," ",[529,530,534],"a",{"href":531,"rel":532},"https://hstspreload.org/",[533],"nofollow","hstspreload.org",[75,536,537,540],{},[18,538,539],{},"Preload Warning",[18,541,542],{},"Once on the preload list, removal is difficult and takes months. Your domain will be hardcoded in browsers to always use HTTPS. Only submit if you're certain your domain and ALL subdomains will support HTTPS permanently.",[75,544,545,548],{},[18,546,547],{},"HSTS Security Checklist",[45,549,550,553,556,558,561,564],{},[48,551,552],{},"SSL certificate is valid and set to auto-renew",[48,554,555],{},"Tested with short max-age first before production values",[48,557,270],{},[48,559,560],{},"No planned migration to HTTP-only subdomains",[48,562,563],{},"Have a process for SSL certificate renewal",[48,565,566],{},"Understand preload list implications before submitting",[40,568,570],{"id":569},"how-to-verify-it-worked","How to Verify It Worked",[152,572,574],{"id":573},"method-1-command-line","Method 1: Command Line",[88,576,579],{"className":577,"code":578,"language":93},[91],"# Check HSTS header\ncurl -sI https://yoursite.com | grep -i strict-transport-security\n\n# Expected output:\nstrict-transport-security: max-age=31536000; includeSubDomains\n",[31,580,578],{"__ignoreMap":96},[152,582,584],{"id":583},"method-2-browser-devtools","Method 2: Browser DevTools",[354,586,587,590,593,595],{},[48,588,589],{},"Open DevTools (F12) > Network tab",[48,591,592],{},"Reload your HTTPS site",[48,594,367],{},[48,596,597,598],{},"Check Response Headers for ",[31,599,373],{},[152,601,603],{"id":602},"method-3-check-internal-redirect","Method 3: Check Internal Redirect",[354,605,606,609,612,617],{},[48,607,608],{},"First, visit your HTTPS site to cache the HSTS policy",[48,610,611],{},"Open DevTools > Network tab",[48,613,392,614,616],{},[31,615,395],{}," in address bar",[48,618,619],{},"You should see \"307 Internal Redirect\" (not a server redirect)",[152,621,623],{"id":622},"method-4-chrome-hsts-inspector","Method 4: Chrome HSTS Inspector",[88,625,628],{"className":626,"code":627,"language":93},[91],"# Open in Chrome\nchrome://net-internals/#hsts\n\n# In \"Query HSTS/PKP domain\" section:\n# Enter your domain and click \"Query\"\n# Should show \"Found\" with your max-age\n",[31,629,627],{"__ignoreMap":96},[152,631,633],{"id":632},"method-5-online-scanner","Method 5: Online Scanner",[18,635,636,637,642],{},"Use ",[529,638,641],{"href":639,"rel":640},"https://securityheaders.com",[533],"securityheaders.com"," to verify HSTS is correctly configured.",[40,644,646],{"id":645},"common-errors-and-troubleshooting","Common Errors and Troubleshooting",[152,648,650],{"id":649},"hsts-header-not-appearing","HSTS header not appearing",[45,652,653,659,665],{},[48,654,655,658],{},[284,656,657],{},"Not on HTTPS",": HSTS header is only sent over HTTPS, not HTTP",[48,660,661,664],{},[284,662,663],{},"CDN stripping headers",": Check CDN configuration for header passthrough",[48,666,667,670],{},[284,668,669],{},"Server config not reloaded",": Restart nginx/Apache after changes",[152,672,674],{"id":673},"cant-access-site-after-enabling-hsts","Can't access site after enabling HSTS",[45,676,677,683,693],{},[48,678,679,682],{},[284,680,681],{},"Certificate expired",": Renew your SSL certificate immediately",[48,684,685,688,689,692],{},[284,686,687],{},"Clear HSTS cache",": In Chrome, go to ",[31,690,691],{},"chrome://net-internals/#hsts"," and delete the entry",[48,694,695,698],{},[284,696,697],{},"Wait for max-age",": If using a long max-age, you may need to wait or clear browser data",[152,700,702],{"id":701},"subdomain-not-accessible","Subdomain not accessible",[45,704,705,711,717],{},[48,706,707,710],{},[284,708,709],{},"includeSubDomains issue",": If you used includeSubDomains but a subdomain doesn't support HTTPS",[48,712,713,716],{},[284,714,715],{},"Solution",": Add HTTPS to the subdomain, or remove includeSubDomains from the main domain",[48,718,719,721],{},[284,720,687],{},": Users who visited before need to clear their HSTS cache",[152,723,725],{"id":724},"cant-remove-from-preload-list","Can't remove from preload list",[45,727,728,734,740],{},[48,729,730,733],{},[284,731,732],{},"Long process",": Submit removal request at hstspreload.org",[48,735,736,739],{},[284,737,738],{},"Takes months",": Changes propagate with browser releases",[48,741,742,745,746,749],{},[284,743,744],{},"Send max-age=0",": While waiting, send ",[31,747,748],{},"max-age=0"," to clear client caches",[751,752,753,756],"tip-box",{},[18,754,755],{},"Pro Tip: Gradual HSTS Rollout",[18,757,758],{},"Increase max-age gradually: 5 min -> 1 day -> 1 week -> 1 month -> 1 year. This gives you time to identify issues before browsers cache a long-lived policy. Monitor for certificate renewal issues and subdomain problems at each stage.",[40,760,762],{"id":761},"frequently-asked-questions","Frequently Asked Questions",[764,765,766,773,779,785,791],"faq-section",{},[767,768,770],"faq-item",{"question":769},"What is HSTS and why do I need it?",[18,771,772],{},"HSTS tells browsers to only connect via HTTPS. It prevents downgrade attacks where attackers force HTTP connections to intercept traffic. Without HSTS, even with HTTP->HTTPS redirects, the first request can be intercepted.",[767,774,776],{"question":775},"What max-age should I use for HSTS?",[18,777,778],{},"Start with max-age=300 (5 minutes) for testing. Use max-age=31536000 (1 year) for production. For preload list submission, you need at least 1 year. Never use max-age=0 unless intentionally disabling HSTS.",[767,780,782],{"question":781},"What happens if I enable HSTS but my HTTPS breaks?",[18,783,784],{},"Browsers refuse HTTP connections until max-age expires or you send max-age=0. Start with a short max-age for testing. If on the preload list, HSTS is hardcoded in browsers and cannot be easily disabled.",[767,786,788],{"question":787},"Should I use includeSubDomains?",[18,789,790],{},"Only if ALL subdomains support HTTPS. This applies HSTS to every subdomain, including future ones. If any subdomain doesn't support HTTPS, users can't access it.",[767,792,794],{"question":793},"What is the HSTS preload list?",[18,795,796],{},"A list of domains hardcoded into browsers to always use HTTPS. Browsers never attempt HTTP for preloaded domains, even on first visit. Requires 1-year max-age, includeSubDomains, and preload directive.",[798,799,802,806],"cta-box",{"href":800,"label":801},"/","Start Free Scan",[40,803,805],{"id":804},"check-your-hsts-configuration","Check Your HSTS Configuration",[18,807,808],{},"Scan your site to verify HSTS is properly configured and check for other security headers.",[810,811,812,818,823,828],"related-articles",{},[813,814],"related-card",{"description":815,"href":816,"title":817},"Complete guide to all essential security headers.","/blog/how-to/add-security-headers","Security Headers Overview",[813,819],{"description":820,"href":821,"title":822},"Configure CSP to prevent XSS attacks.","/blog/how-to/csp-setup","Content Security Policy Setup",[813,824],{"description":825,"href":826,"title":827},"Configure SSL certificates correctly.","/blog/best-practices/ssl","SSL/TLS Best Practices",[813,829],{"description":830,"href":831,"title":832},"Understand HTTPS and transport security.","/blog/vulnerabilities/insecure-transport","Insecure Transport Explained",{"title":96,"searchDepth":834,"depth":834,"links":835},2,[836,837,838,842,850,857,863,864],{"id":42,"depth":834,"text":43},{"id":65,"depth":834,"text":66},{"id":85,"depth":834,"text":86,"children":839},[840],{"id":154,"depth":841,"text":155},3,{"id":230,"depth":834,"text":231,"children":843},[844,845,846,847,848,849],{"id":238,"depth":841,"text":239},{"id":276,"depth":841,"text":277},{"id":342,"depth":841,"text":343},{"id":380,"depth":841,"text":381},{"id":419,"depth":841,"text":420},{"id":481,"depth":841,"text":482},{"id":569,"depth":834,"text":570,"children":851},[852,853,854,855,856],{"id":573,"depth":841,"text":574},{"id":583,"depth":841,"text":584},{"id":602,"depth":841,"text":603},{"id":622,"depth":841,"text":623},{"id":632,"depth":841,"text":633},{"id":645,"depth":834,"text":646,"children":858},[859,860,861,862],{"id":649,"depth":841,"text":650},{"id":673,"depth":841,"text":674},{"id":701,"depth":841,"text":702},{"id":724,"depth":841,"text":725},{"id":761,"depth":834,"text":762},{"id":804,"depth":834,"text":805},"how-to","2026-01-15","Complete guide to HSTS setup. Configure Strict-Transport-Security header, understand max-age, includeSubDomains, preload list submission, and avoid common mistakes.",false,"md",[871,873,875,877,879],{"question":769,"answer":872},"HSTS (HTTP Strict Transport Security) tells browsers to only connect to your site via HTTPS. It prevents protocol downgrade attacks where attackers force HTTP connections to intercept traffic. Without HSTS, even if you redirect HTTP to HTTPS, the first request could be intercepted.",{"question":775,"answer":874},"Start with max-age=300 (5 minutes) for testing. Once verified, use max-age=31536000 (1 year) for production. For HSTS preload list submission, you need at least max-age=31536000. Never use max-age=0 unless you're intentionally disabling HSTS.",{"question":781,"answer":876},"Browsers will refuse to connect via HTTP until the max-age expires or you send max-age=0. This is why starting with a short max-age is crucial. If you're on the preload list, you cannot easily disable HSTS as it's hardcoded in browsers.",{"question":787,"answer":878},"Only if ALL subdomains support HTTPS. includeSubDomains applies HSTS to every subdomain, including ones you might create in the future. If any subdomain doesn't support HTTPS, users won't be able to access it.",{"question":793,"answer":880},"The preload list is a list of domains hardcoded into browsers to always use HTTPS. Once added, browsers will never attempt HTTP for your domain, even on first visit. Submission requires max-age of at least 1 year, includeSubDomains, and the preload directive.","yellow",null,{},true,"Complete guide to HSTS headers, preload list, and safe deployment strategies.","/blog/how-to/hsts-setup","[object Object]","HowTo",{"title":5,"description":867},{"loc":886},"blog/how-to/hsts-setup",[],"summary_large_image","jwfCq2QRSBcaeN8C1isPutNSdyLf37orIKSwy_lFPP4",1775843928295]