[{"data":1,"prerenderedAt":366},["ShallowReactive",2],{"blog-best-practices/ssl":3},{"id":4,"title":5,"body":6,"category":341,"date":342,"dateModified":343,"description":344,"draft":345,"extension":346,"faq":347,"featured":345,"headerVariant":351,"image":352,"keywords":352,"meta":353,"navigation":354,"ogDescription":355,"ogTitle":352,"path":356,"readTime":357,"schemaOrg":358,"schemaType":359,"seo":360,"sitemap":361,"stem":362,"tags":363,"twitterCard":364,"__hash__":365},"blog/blog/best-practices/ssl.md","SSL/TLS Best Practices: HTTPS Configuration and Certificate Management",{"type":7,"value":8,"toc":330},"minimark",[9,16,25,30,33,108,123,127,130,139,148,152,155,164,170,174,177,186,190,193,202,206,209,236,245,250,272,276,279,299,318],[10,11,12],"tldr",{},[13,14,15],"p",{},"The #1 SSL/TLS best practice is enforcing TLS 1.2+ only (disable TLS 1.0/1.1). Get free certificates from Let's Encrypt with auto-renewal. Enable HSTS to force HTTPS. Use modern cipher suites and test your configuration with SSL Labs. Certificate expiration is the most common cause of HTTPS outages.",[17,18,19],"quotable-box",{},[20,21,22],"blockquote",{},[13,23,24],{},"\"HTTPS is not optional. An expired certificate is worse than no certificate at all-it tells users you stopped caring about their security.\"",[26,27,29],"h2",{"id":28},"best-practice-1-use-tls-12-or-higher-3-min","Best Practice 1: Use TLS 1.2 or Higher 3 min",[13,31,32],{},"Older TLS versions have known vulnerabilities:",[34,35,36,52],"table",{},[37,38,39],"thead",{},[40,41,42,46,49],"tr",{},[43,44,45],"th",{},"Version",[43,47,48],{},"Status",[43,50,51],{},"Recommendation",[53,54,55,67,78,89,98],"tbody",{},[40,56,57,61,64],{},[58,59,60],"td",{},"TLS 1.3",[58,62,63],{},"Current",[58,65,66],{},"Enable (preferred)",[40,68,69,72,75],{},[58,70,71],{},"TLS 1.2",[58,73,74],{},"Acceptable",[58,76,77],{},"Enable (compatibility)",[40,79,80,83,86],{},[58,81,82],{},"TLS 1.1",[58,84,85],{},"Deprecated",[58,87,88],{},"Disable",[40,90,91,94,96],{},[58,92,93],{},"TLS 1.0",[58,95,85],{},[58,97,88],{},[40,99,100,103,106],{},[58,101,102],{},"SSL 3.0",[58,104,105],{},"Insecure",[58,107,88],{},[109,110,112],"code-block",{"label":111},"Nginx TLS configuration",[113,114,119],"pre",{"className":115,"code":117,"language":118},[116],"language-text","# /etc/nginx/conf.d/ssl.conf\n\n# Only allow TLS 1.2 and 1.3\nssl_protocols TLSv1.2 TLSv1.3;\n\n# Modern cipher suites\nssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305;\n\n# Prefer server ciphers\nssl_prefer_server_ciphers off;  # Let client choose for TLS 1.3\n\n# Session settings\nssl_session_timeout 1d;\nssl_session_cache shared:SSL:50m;\nssl_session_tickets off;\n\n# OCSP Stapling\nssl_stapling on;\nssl_stapling_verify on;\nresolver 8.8.8.8 8.8.4.4 valid=300s;\nresolver_timeout 5s;\n","text",[120,121,117],"code",{"__ignoreMap":122},"",[26,124,126],{"id":125},"best-practice-2-automate-certificate-management-5-min","Best Practice 2: Automate Certificate Management 5 min",[13,128,129],{},"Certificate expiration causes outages. Automate renewal:",[109,131,133],{"label":132},"Let's Encrypt with Certbot",[113,134,137],{"className":135,"code":136,"language":118},[116],"# Install Certbot\nsudo apt install certbot python3-certbot-nginx\n\n# Get certificate with auto-configuration\nsudo certbot --nginx -d example.com -d www.example.com\n\n# Auto-renewal is enabled by default\n# Check with:\nsudo systemctl status certbot.timer\n\n# Test renewal\nsudo certbot renew --dry-run\n\n# Manual renewal (if needed)\nsudo certbot renew\n",[120,138,136],{"__ignoreMap":122},[109,140,142],{"label":141},"AWS Certificate Manager (ACM)",[113,143,146],{"className":144,"code":145,"language":118},[116],"# Terraform: ACM certificate with auto-renewal\nresource \"aws_acm_certificate\" \"main\" {\n  domain_name               = \"example.com\"\n  subject_alternative_names = [\"*.example.com\"]\n  validation_method         = \"DNS\"\n\n  lifecycle {\n    create_before_destroy = true\n  }\n}\n\n# DNS validation record\nresource \"aws_route53_record\" \"cert_validation\" {\n  for_each = {\n    for dvo in aws_acm_certificate.main.domain_validation_options : dvo.domain_name => {\n      name   = dvo.resource_record_name\n      record = dvo.resource_record_value\n      type   = dvo.resource_record_type\n    }\n  }\n\n  zone_id = aws_route53_zone.main.zone_id\n  name    = each.value.name\n  type    = each.value.type\n  records = [each.value.record]\n  ttl     = 60\n}\n",[120,147,145],{"__ignoreMap":122},[26,149,151],{"id":150},"best-practice-3-enable-hsts-2-min","Best Practice 3: Enable HSTS 2 min",[13,153,154],{},"HTTP Strict Transport Security prevents downgrade attacks:",[109,156,158],{"label":157},"HSTS configuration",[113,159,162],{"className":160,"code":161,"language":118},[116],"# Nginx\nadd_header Strict-Transport-Security \"max-age=31536000; includeSubDomains; preload\" always;\n\n# Apache\nHeader always set Strict-Transport-Security \"max-age=31536000; includeSubDomains; preload\"\n\n# Express.js with Helmet\nimport helmet from 'helmet';\n\napp.use(helmet.hsts({\n  maxAge: 31536000,       // 1 year\n  includeSubDomains: true,\n  preload: true,\n}));\n\n# Vercel (vercel.json)\n{\n  \"headers\": [\n    {\n      \"source\": \"/(.*)\",\n      \"headers\": [\n        {\n          \"key\": \"Strict-Transport-Security\",\n          \"value\": \"max-age=31536000; includeSubDomains; preload\"\n        }\n      ]\n    }\n  ]\n}\n",[120,163,161],{"__ignoreMap":122},[165,166,167],"info-box",{},[13,168,169],{},"HSTS Preload Warning:\nBefore enabling the preload directive, ensure all subdomains support HTTPS. Once your domain is in the preload list, HTTP access is permanently blocked in browsers. This cannot be easily undone.",[26,171,173],{"id":172},"best-practice-4-redirect-http-to-https-2-min","Best Practice 4: Redirect HTTP to HTTPS 2 min",[13,175,176],{},"Force all traffic to use HTTPS:",[109,178,180],{"label":179},"HTTP to HTTPS redirect",[113,181,184],{"className":182,"code":183,"language":118},[116],"# Nginx\nserver {\n  listen 80;\n  listen [::]:80;\n  server_name example.com www.example.com;\n\n  # Redirect all HTTP to HTTPS\n  return 301 https://$server_name$request_uri;\n}\n\n# Apache\nRewriteEngine On\nRewriteCond %{HTTPS} off\nRewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]\n\n# Express.js middleware\nfunction requireHTTPS(req, res, next) {\n  if (req.headers['x-forwarded-proto'] !== 'https' &&\n      process.env.NODE_ENV === 'production') {\n    return res.redirect(301, `https://${req.hostname}${req.url}`);\n  }\n  next();\n}\n\napp.use(requireHTTPS);\n",[120,185,183],{"__ignoreMap":122},[26,187,189],{"id":188},"best-practice-5-monitor-certificate-expiration-10-min","Best Practice 5: Monitor Certificate Expiration 10 min",[13,191,192],{},"Set up alerts before certificates expire:",[109,194,196],{"label":195},"Certificate expiration monitoring",[113,197,200],{"className":198,"code":199,"language":118},[116],"#!/bin/bash\n# Check certificate expiration\n\nDOMAIN=\"example.com\"\nWARN_DAYS=30\n\nEXPIRY=$(echo | openssl s_client -servername $DOMAIN -connect $DOMAIN:443 2>/dev/null | \\\n         openssl x509 -noout -enddate | cut -d= -f2)\n\nEXPIRY_EPOCH=$(date -d \"$EXPIRY\" +%s)\nNOW_EPOCH=$(date +%s)\nDAYS_LEFT=$(( ($EXPIRY_EPOCH - $NOW_EPOCH) / 86400 ))\n\nif [ $DAYS_LEFT -lt $WARN_DAYS ]; then\n  echo \"WARNING: Certificate for $DOMAIN expires in $DAYS_LEFT days\"\n  # Send alert\n  curl -X POST \"https://hooks.slack.com/...\" \\\n    -d \"{\\\"text\\\": \\\"SSL cert for $DOMAIN expires in $DAYS_LEFT days\\\"}\"\nfi\n\n# Prometheus/Grafana approach\n# Use blackbox exporter to monitor SSL\n- job_name: 'ssl'\n  metrics_path: /probe\n  params:\n    module: [http_2xx]\n  static_configs:\n    - targets:\n      - https://example.com\n  relabel_configs:\n    - source_labels: [__address__]\n      target_label: __param_target\n    - target_label: __address__\n      replacement: blackbox-exporter:9115\n",[120,201,199],{"__ignoreMap":122},[26,203,205],{"id":204},"best-practice-6-test-your-configuration-5-min","Best Practice 6: Test Your Configuration 5 min",[13,207,208],{},"Regularly verify your SSL/TLS setup:",[210,211,212,224,227,230,233],"ul",{},[213,214,215,216,223],"li",{},"Test with ",[217,218,222],"a",{"href":219,"rel":220},"https://www.ssllabs.com/ssltest/",[221],"nofollow","SSL Labs"," (aim for A+ rating)",[213,225,226],{},"Check for certificate chain issues",[213,228,229],{},"Verify all subdomains have valid certs",[213,231,232],{},"Test mixed content (HTTP resources on HTTPS pages)",[213,234,235],{},"Verify HSTS is working correctly",[109,237,239],{"label":238},"Command-line SSL testing",[113,240,243],{"className":241,"code":242,"language":118},[116],"# Check certificate details\nopenssl s_client -connect example.com:443 -servername example.com\n\n# Check TLS versions supported\nnmap --script ssl-enum-ciphers -p 443 example.com\n\n# Check certificate chain\nopenssl s_client -connect example.com:443 -showcerts\n\n# Test specific TLS version\nopenssl s_client -connect example.com:443 -tls1_2\nopenssl s_client -connect example.com:443 -tls1_3\n\n# Check for common vulnerabilities\ntestssl.sh example.com\n",[120,244,242],{"__ignoreMap":122},[165,246,247],{},[13,248,249],{},"External Resources:\nFor comprehensive SSL/TLS guidance, see the\nLet's Encrypt Documentation\nfor free certificate automation and the\nOWASP Transport Layer Security Cheat Sheet\nfor industry-standard TLS configuration recommendations.",[251,252,253,260,266],"faq-section",{},[254,255,257],"faq-item",{"question":256},"Should I use a wildcard certificate?",[13,258,259],{},"Wildcard certs (*.example.com) are convenient but require careful key protection since one compromised key affects all subdomains. Use them for internal services or when you have many subdomains. For public-facing sites, individual certs are often safer.",[254,261,263],{"question":262},"Do I need an EV (Extended Validation) certificate?",[13,264,265],{},"No. Browsers no longer display EV certificates differently from standard DV (Domain Validation) certificates. A free Let's Encrypt certificate provides the same encryption. EV only matters if you need organizational identity verification for compliance.",[254,267,269],{"question":268},"How do I handle certificate rotation?",[13,270,271],{},"For auto-renewed certs (Let's Encrypt, ACM), rotation is automatic. For manual certs, deploy new certs before old ones expire, test, then remove old certs. Use certificate pinning only when absolutely necessary, as it makes rotation harder.",[26,273,275],{"id":274},"further-reading","Further Reading",[13,277,278],{},"Put these practices into action with our step-by-step guides.",[210,280,281,287,293],{},[213,282,283],{},[217,284,286],{"href":285},"/blog/how-to/add-security-headers","Add security headers to your app",[213,288,289],{},[217,290,292],{"href":291},"/blog/checklists/pre-deployment-security-checklist","Pre-deployment security checklist",[213,294,295],{},[217,296,298],{"href":297},"/blog/getting-started/first-scan","Run your first security scan",[300,301,302,308,313],"related-articles",{},[303,304],"related-card",{"description":305,"href":306,"title":307},"CSP, HSTS, and more","/blog/best-practices/headers","Security Headers",[303,309],{"description":310,"href":311,"title":312},"Secure deployment practices","/blog/best-practices/deployment","Deployment Security",[303,314],{"description":315,"href":316,"title":317},"Automatic SSL with Vercel","/blog/best-practices/vercel","Vercel Security",[319,320,323,327],"cta-box",{"href":321,"label":322},"/","Start Free Scan",[26,324,326],{"id":325},"test-your-ssl-configuration","Test Your SSL Configuration",[13,328,329],{},"Check your TLS settings and certificate health.",{"title":122,"searchDepth":331,"depth":331,"links":332},2,[333,334,335,336,337,338,339,340],{"id":28,"depth":331,"text":29},{"id":125,"depth":331,"text":126},{"id":150,"depth":331,"text":151},{"id":172,"depth":331,"text":173},{"id":188,"depth":331,"text":189},{"id":204,"depth":331,"text":205},{"id":274,"depth":331,"text":275},{"id":325,"depth":331,"text":326},"best-practices","2026-02-04","2026-02-16","SSL/TLS security best practices. Learn proper HTTPS configuration, certificate management, cipher suites, and TLS version settings for secure connections.",false,"md",[348,349,350],{"question":256,"answer":259},{"question":262,"answer":265},{"question":268,"answer":271},"vibe-green",null,{},true,"Configure HTTPS correctly with proper TLS settings and certificate management.","/blog/best-practices/ssl","10 min read","[object Object]","Article",{"title":5,"description":344},{"loc":356},"blog/best-practices/ssl",[],"summary_large_image","p-fCeVJk2fTGLJmONKbCg8N7FsUe4cBNMN_zEn6U-JY",1775843925135]