Enabling HTTP Strict Transport Security (HSTS) forces modern browsers to stick to HTTPS for a site, shutting down protocol-downgrade attacks and accidental plain-HTTP visits that can leak cookies or session tokens.
HSTS works by sending a Strict-Transport-Security response header over a successful HTTPS connection. The browser caches the policy for the declared max-age, automatically upgrading future HTTP navigations to HTTPS for that host while the policy is valid.
Because browsers ignore the header on HTTP responses, the HTTPS endpoint must be healthy first and plain HTTP should redirect to HTTPS. Examples below use the Debian-style Apache layout (/etc/apache2, apache2 service); adjust file paths and the service name on other distributions, and remember that rollback is client-cached (a temporary Strict-Transport-Security: max-age=0 over HTTPS is the usual way to clear a policy early).
Steps to enable HSTS in Apache:
- Confirm the site responds over HTTPS without certificate errors.
$ curl --head https://mysite.example/ HTTP/1.1 200 OK Date: Sat, 13 Dec 2025 12:34:56 GMT Server: Apache Content-Type: text/html; charset=UTF-8
- Confirm the HTTP endpoint redirects to HTTPS.
$ curl --head http://mysite.example/ HTTP/1.1 301 Moved Permanently Location: https://mysite.example/ Connection: close Content-Type: text/html; charset=iso-8859-1
If the Location header does not point at https://mysite.example, add or fix the VirtualHost *:80 redirect before enabling HSTS.
- Enable the headers module to allow Apache to emit the Strict-Transport-Security header.
$ sudo a2enmod headers Enabling module headers. To activate the new configuration, you need to run: systemctl restart apache2
On RHEL-family systems, mod_headers is commonly available already and the service name is usually httpd.
- Open the site’s HTTPS VirtualHost configuration file.
$ sudo vi /etc/apache2/sites-available/000-mysite.conf
- Add the Strict-Transport-Security header inside the <VirtualHost *:443> block.
<VirtualHost *:443> # ... <IfModule mod_headers.c> Header always set Strict-Transport-Security "max-age=86400" </IfModule> </VirtualHost>A long max-age can lock browsers into HTTPS for that hostname until the timer expires, even if the header is later removed; start small, validate, then increase. Avoid includeSubDomains unless every subdomain is reachable over HTTPS, or browsers will refuse HTTP on subdomains too, and treat preload as a one-way door if a preload list submission is intended.
After a clean rollout, a common hardened value is max-age=31536000; includeSubDomains; a rollback policy is typically max-age=0 until clients expire the cached setting.
Related: Apache mod_headers documentation
- Validate the Apache configuration syntax.
$ sudo apache2ctl -t Syntax OK
- Restart the apache2 service to apply the change.
$ sudo systemctl restart apache2
A restart can briefly interrupt in-flight connections; use a reload if the deployment requires a graceful config apply.
- Check the HTTPS response headers for a Strict-Transport-Security line.
$ curl --head https://mysite.example/ HTTP/1.1 200 OK Date: Sat, 13 Dec 2025 12:36:02 GMT Server: Apache Strict-Transport-Security: max-age=86400 Content-Type: text/html; charset=UTF-8
HTTP/2 responses may show lower-case header names in curl output; the presence of the policy and the max-age value is what matters.
Mohd Shakir Zakaria is a cloud architect with deep roots in software development and open-source advocacy. Certified in AWS, Red Hat, VMware, ITIL, and Linux, he specializes in designing and managing robust cloud and on-premises infrastructures.
Comment anonymously. Login not required.
