HTTP security headers: set up HSTS, CSP and more
Published on July 9, 2026 10 min read
Learn what HTTP security headers like HSTS and CSP do and how to set them up safely through .htaccess on Plesk or a WordPress plugin, step by step.
Did a security scan such as securityheaders.com or the MDN HTTP Observatory report that your website is missing security headers? HTTP security headers like HSTS and CSP are short instructions that your server sends with every page, telling the browser how to handle your site safely. This article explains what the most important security headers do, which attacks they stop, and how to set them up through .htaccess on your Plesk hosting or with a WordPress plugin.
What are HTTP security headers?
Every time a visitor requests a page, your web server sends a set of HTTP response headers alongside the content. These are short lines that work in the background and control all sorts of things, from caching to the type of content. Security headers are a special group of them: they give the browser stricter rules about what is allowed to happen with your page.
Security headers do not replace safe code, strong passwords or updates. They add an extra layer of defence, often called defence in depth. If a flaw does slip into your site or a plugin, the headers often limit the damage an attacker can do.
Which attacks do security headers stop?
Each header targets a specific risk. These are the main ones:
- Clickjacking: an attacker loads your page inside an invisible frame (iframe) on another site and tricks visitors into clicks they did not intend. Stopped by X-Frame-Options and CSP.
- Cross-site scripting (XSS): malicious scripts injected into your page that run in your visitor's browser. Limited by Content-Security-Policy.
- Downgrade attacks and SSL stripping: an attacker pushes the visitor back to an unencrypted http connection to eavesdrop. Stopped by HSTS.
- MIME sniffing: the browser guesses the file type itself and runs, for example, an uploaded file as a script. Stopped by X-Content-Type-Options.
- Leaking data through the referring URL: controlled with Referrer-Policy.
- Unwanted use of camera, microphone or location: controlled with Permissions-Policy.
The most important security headers at a glance
The table below gives an overview. Underneath, you can read what each header does and which value is a good starting point.
| Header | Protects against | Recommended starting value |
|---|---|---|
| Strict-Transport-Security | Downgrade attacks, SSL stripping | max-age=63072000; includeSubDomains |
| Content-Security-Policy | XSS, code injection, clickjacking | Start in report-only (see below) |
| X-Frame-Options | Clickjacking | SAMEORIGIN |
| X-Content-Type-Options | MIME sniffing | nosniff |
| Referrer-Policy | Leaking URL data | strict-origin-when-cross-origin |
| Permissions-Policy | Misuse of browser features | geolocation=(), camera=(), microphone=() |
Strict-Transport-Security (HSTS)
HSTS forces browsers to reach your site only over https, even if someone types http by mistake. The max-age value sets how long the browser remembers this, in seconds. With includeSubDomains the rule also applies to all your subdomains, and with the optional preload flag you can have your domain added to a list that is already built into browsers.
A widely used, safe value is max-age=63072000 (two years) with includeSubDomains. Important: a browser only accepts HSTS when the header is sent over https. At LJPc, HSTS is already switched on by default, see the section below.
Content-Security-Policy (CSP)
CSP is the most powerful header, but also the trickiest. It lets you decide exactly which sources (scripts, images, stylesheets) may load and from which domains. That makes CSP your strongest weapon against XSS. Its frame-ancestors directive also handles clickjacking and is the modern successor to X-Frame-Options.
Because a policy that is too strict can break your site, it is best to set CSP up in report-only mode first. We explain that approach step by step further down.
X-Frame-Options
This header decides whether your page may be loaded in an iframe on another site, protecting you against clickjacking. The value SAMEORIGIN allows framing only on your own domain, while DENY blocks it entirely. The old value ALLOW-FROM is obsolete and is ignored by modern browsers.
CSP frame-ancestors does the same thing, but with more control. You may set both: older browsers understand only X-Frame-Options, newer ones follow frame-ancestors.
X-Content-Type-Options
The only valid value is nosniff. It stops the browser from guessing what kind of file it receives. Without this header a browser can, for example, run an uploaded text file as HTML or a script, which makes XSS possible.
Referrer-Policy
This header controls how much of the previous URL is sent along when a visitor clicks through from your site. The value strict-origin-when-cross-origin sends the full address within your own site, but only your domain without the path to other sites. Modern browsers already use this as the default, but setting it explicitly makes your intent clear.
Permissions-Policy
With Permissions-Policy (the successor to Feature-Policy) you decide which browser features your page may use, such as camera, microphone and location. An empty list in brackets, for example camera=(), switches a feature off completely. Disable every feature your site does not need.
An outdated header you may still come across in scans is X-XSS-Protection. It is discouraged: do not set it any more, or give it the value 0. CSP has taken over its job.
What LJPc already handles for you: HSTS and OCSP stapling
As soon as an SSL certificate is activated on your website, LJPc switches HSTS on automatically, with a max-age of two years and includeSubDomains. OCSP stapling is enabled by default too. That last one speeds up the https handshake and is not a header you manage yourself. So you do not need to add the HSTS header yourself, and it is best not to add it through .htaccess either, because that risks a duplicate header.
HSTS only works when your site is genuinely reachable over https. So first make sure you have a valid SSL certificate. Every hosting package includes a free Let's Encrypt certificate that is issued and renewed automatically. Focus your own work on the other headers: CSP, X-Frame-Options, X-Content-Type-Options, Referrer-Policy and Permissions-Policy.
Setting up security headers through .htaccess on Plesk
On Plesk hosting with Apache, the easiest way to add headers is through the .htaccess file in the httpdocs folder. Apache then sends the headers with every page. Work through these steps:
- Make a backup of your current .htaccess first, so you can always restore it.
- Open .htaccess in the Plesk file manager or over FTP/SFTP. If the file does not exist yet, create it in the httpdocs web root.
- Paste the block below at the top of the file and save it.
- Refresh your site and check that everything still works. Then test your headers (see further down).
<IfModule mod_headers.c>
Header always set X-Frame-Options "SAMEORIGIN"
Header always set X-Content-Type-Options "nosniff"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Permissions-Policy "geolocation=(), camera=(), microphone=()"
</IfModule>
The always keyword makes sure the header is sent on error pages too, such as a 404. The IfModule line prevents an error if the mod_headers module is ever inactive. HSTS is deliberately left out of this block, because LJPc already sends it. If you would rather not touch .htaccess, and your package gives you access to the Apache and nginx settings in Plesk, you can add the same lines in the field for additional Apache directives.
Setting up security headers in WordPress
If you would rather not edit .htaccess, you can use a plugin in WordPress. A popular, free option is Headers Security Advanced & HSTS WP, which adds the headers for you through a settings screen.
- In your WordPress dashboard, go to Plugins and then Add Plugin, and search for Headers Security Advanced.
- Install and activate the plugin.
- Open the plugin settings and switch on the headers you want: X-Frame-Options, X-Content-Type-Options, Referrer-Policy and Permissions-Policy.
- Leave HSTS switched off, because LJPc already sends it. That way you avoid a duplicate header.
- Be careful with the CSP option: only switch it on after you have tested it, otherwise scripts or styles may drop out.
Note: a plugin and an .htaccess rule can both send the same header. So pick one method per header, to avoid duplicate values.
Setting up Content-Security-Policy without breaking your site
CSP is the header that most often breaks something, because legitimate scripts or styles suddenly get blocked. WordPress in particular uses a lot of inline scripts and styles, so caution is needed. Take it in stages:
- Start with the report-only variant. It reports violations but does not block anything yet. In .htaccess that looks like this:
Header always set Content-Security-Policy-Report-Only "default-src 'self'; img-src 'self' data:; style-src 'self' 'unsafe-inline'; script-src 'self'"
- Visit your site and keep an eye on your browser console (F12, Console tab). Every blocked source appears there as a message.
- Add the sources you genuinely need to the right directive, for example the domain of your fonts or your analytics tool.
- Once everything works without messages, change Content-Security-Policy-Report-Only into Content-Security-Policy. The policy is now enforced.
- Optionally add frame-ancestors 'self' as a modern replacement for X-Frame-Options.
A strict CSP without 'unsafe-inline' is the safest, but in practice many WordPress themes need that exception for styles. So build your policy up gradually and test again after each change.
Checking that your headers work
After setting them up, you will want to be sure the headers are actually sent. There are three ways to do this:
- Online scanners: securityheaders.com and the MDN HTTP Observatory give your site a grade and show which headers are missing.
- Browser developer tools: open F12, go to the Network tab, reload the page and click the first request. Under Response Headers you can see the headers that were sent.
- Command line: the command curl -I https://yourdomain.com requests just the headers.
Common problems
| Problem | Cause | Solution |
|---|---|---|
| Header does not appear | mod_headers is inactive or your site runs on a separate server configuration | Check that mod_headers is enabled, or contact support |
| Duplicate Strict-Transport-Security | You added HSTS yourself while LJPc already sends it | Remove your own HSTS line |
| Site or parts of it stop working | A Content-Security-Policy that is too strict blocks scripts or styles | Set CSP back to report-only and add the missing sources |
| Header missing on error pages | You used set instead of always | Use Header always set |
| Change is not visible | Caching in your browser or hosting | Clear the cache and test again, or test with curl |
Cannot work it out, or want to be sure your headers are set correctly? Feel free to contact LJPc support and we will take a look with you.
Frequently asked questions
What are HTTP security headers?
They are short instructions that your web server sends with every page, telling the browser how to handle your site safely. Think of enforcing https, blocking framing and restricting scripts. Together they form an extra layer of security on top of safe code and updates.
Which security headers matter most?
The six you want on almost every site are Strict-Transport-Security (HSTS), Content-Security-Policy, X-Frame-Options, X-Content-Type-Options, Referrer-Policy and Permissions-Policy. Together they cover the most common risks, such as downgrade attacks, XSS and clickjacking.
Do I need to set up HSTS myself at LJPc?
No. LJPc switches HSTS on automatically as soon as an SSL certificate is activated on your site, with a max-age of two years and includeSubDomains. So do not add the header again yourself, or you will get a duplicate Strict-Transport-Security header.
Why does my site stop working after setting up Content-Security-Policy?
Usually the policy is too strict, which blocks legitimate scripts or styles. Set CSP to report-only mode first, check your browser console to see which sources are blocked, and add them. Only enforce the policy once everything works without messages.
How do I check my security headers?
Use an online scanner such as securityheaders.com or the MDN HTTP Observatory for a grade and an overview. In your browser, press F12 and open the Network tab to view the Response Headers, and with curl -I https://yourdomain.com you can request them on the command line.
Is X-XSS-Protection still needed?
No, that header is outdated and discouraged. Leave it out or give it the value 0. Content-Security-Policy now offers much better protection against XSS.