When we harden customer websites at dchost.com, HTTP security headers are always among the first things we check. They are small pieces of text added to HTTP responses, but they dramatically change how browsers treat your site. With a few correctly configured headers, you reduce the impact of XSS attacks, prevent clickjacking, avoid leaking sensitive URLs in the referrer and make sure visitors always use HTTPS. In this guide, we will focus on four of the most important headers: HSTS, CSP, X-Frame-Options and Referrer-Policy. We will walk through what each one does, when to enable it, common pitfalls, and how to configure them on Apache, Nginx and typical shared hosting environments. Whether you run a small business site on shared hosting or manage multiple VPS and dedicated servers, you can implement these headers in a structured, low-risk way and make your security posture much stronger.
İçindekiler
- 1 What Are HTTP Security Headers and Why They Matter
- 2 The Four Headers We Will Configure
- 3 HSTS: Strict-Transport-Security
- 4 CSP: Content-Security-Policy
- 5 X-Frame-Options: Protecting Against Clickjacking
- 6 Referrer-Policy: Controlling What Your Users Leak
- 7 Implementing These Headers on Shared Hosting, VPS and Dedicated Servers
- 8 Testing, Monitoring and Avoiding Surprises
- 9 How We See Customers Apply This on dchost.com
- 10 Next Steps: Turn Security Headers into a Habit
What Are HTTP Security Headers and Why They Matter
HTTP security headers are instructions your server sends to the browser along with every page. Instead of changing your HTML, CSS or JavaScript, you are changing the rules the browser must follow while rendering your site.
They help with:
- Enforcing HTTPS and preventing insecure HTTP access
- Limiting where content can be loaded from (scripts, images, fonts, iframes)
- Blocking clickjacking attacks where your site is framed inside a malicious page
- Reducing how much data is leaked via the
Refererheader when users follow links
Headers are one layer in a broader security stack. They complement TLS/SSL, WAF rules, secure cookies, and DNS protections such as DNSSEC. If you are new to HTTPS configuration itself, you may want to review our articles on keeping SSL/TLS security settings up to date on your servers and what an SSL certificate is and how it secures your website before you commit to strict HSTS.
The Four Headers We Will Configure
In this guide we will focus on four key headers that we use widely across dchost.com hosting environments:
- Strict-Transport-Security (HSTS) – tells browsers to always use HTTPS for your domain.
- Content-Security-Policy (CSP) – defines which sources of scripts, styles, images, iframes, etc. are allowed.
- X-Frame-Options – controls whether your pages may be embedded in an iframe.
- Referrer-Policy – controls how much referrer information your users’ browsers send to other sites.
For a broader overview of related headers like X-Content-Type-Options and Permissions-Policy, you can later dive into our more advanced article about HTTP security headers configuration best practices. Here, we will stay focused on getting these four high-impact headers right, with realistic examples.
HSTS: Strict-Transport-Security
What HSTS Does
HSTS (HTTP Strict Transport Security) tells browsers: “From now on, only connect to this site over HTTPS. Never over plain HTTP.” After a browser sees a valid HSTS header once, it will automatically upgrade any future http:// requests to https:// before sending them. This helps prevent downgrade attacks and cookie theft on insecure connections.
A typical HSTS header looks like this:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
- max-age: How long (in seconds) the browser should remember to enforce HTTPS. One year is
31536000seconds. - includeSubDomains: Apply HSTS to all subdomains as well (e.g.
www.,cdn.,api.). - preload: Indicates you want to be added to browser HSTS preload lists (requires an extra submission step).
Preconditions Before Enabling HSTS
Before we enable a strong HSTS policy for any customer, we always double-check:
- HTTPS is fully working on the main domain and all relevant subdomains.
- HTTP to HTTPS redirects are in place (301 redirects, not 302).
- No mixed content remains (HTTP images, scripts or CSS on HTTPS pages).
- Any legacy systems or subdomains that still require HTTP are separated.
Once HSTS with includeSubDomains and preload is deployed, you cannot go back to HTTP easily. That’s why we often combine this step with a full HTTPS migration plan. If you are planning a protocol migration, our article on moving from HTTP to HTTPS with 301 redirects and HSTS while preserving SEO is a good companion read.
Enabling HSTS on Nginx
On Nginx, add the header inside the server block that serves HTTPS:
server {
listen 443 ssl http2;
server_name example.com www.example.com;
# Your SSL configuration here
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
...
}
The always keyword ensures the header is added even on error pages (4xx/5xx), which is recommended.
Enabling HSTS on Apache (Including .htaccess)
On Apache 2.4+, you can use:
<IfModule mod_headers.c>
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
</IfModule>
You may place this in the main virtual host configuration or in .htaccess if you are on a shared hosting plan that allows it. On many dchost.com shared hosting accounts, customers manage headers via .htaccess, while VPS and dedicated server users typically configure them directly in the virtual host file for better performance and centralised control.
HSTS Preload Considerations
HSTS Preload is a browser-maintained list of domains that must always use HTTPS, even on first visit. To be eligible you must:
- Serve a valid certificate for your domain.
- Redirect all HTTP traffic to HTTPS.
- Serve an HSTS header with
max-age >= 31536000,includeSubDomainsandpreloadtokens.
Preload is powerful but sticky. If you later decide to remove HTTPS from a subdomain, you must first remove includeSubDomains and preload, wait for HSTS to expire in clients, and then request removal from the preload list. For most small and medium sites, we recommend starting without preload, then enabling it when you are confident your HTTPS setup and renewal automation are stable.
CSP: Content-Security-Policy
What CSP Does
Content-Security-Policy (CSP) is one of the most powerful web security headers you can deploy. It tells the browser exactly which sources are allowed for scripts, styles, images, fonts, frames, AJAX calls and more. If an attacker manages to inject malicious JavaScript into your page, a properly configured CSP can prevent that script from running.
A very simple CSP example:
Content-Security-Policy: default-src 'self'; img-src 'self' https://images.examplecdn.com; script-src 'self'; style-src 'self' 'unsafe-inline';
This policy means:
- By default (
default-src), only load resources from the same origin. - Images may also load from
images.examplecdn.com. - Scripts must come from the same origin only.
- Styles may come from the same origin, and inline styles are temporarily allowed (
'unsafe-inline').
Key CSP Concepts
- default-src: Fallback source list for directives you do not explicitly set.
- script-src / style-src / img-src / font-src / connect-src: Finer-grained directives for each resource type.
- ‘self’: Allows content from the same origin (same scheme, host and port).
- ‘none’: Disallow all sources.
- ‘unsafe-inline’: Allows inline scripts or styles; convenient but unsafe for scripts.
- ‘nonce-…’: A random token you attach to allowed inline scripts/styles per request.
The most robust CSP setups use nonces or hashes instead of 'unsafe-inline'. For advanced nonce/hash-based CSP patterns on frameworks like WordPress and Laravel, we have a dedicated article: how to implement CSP correctly using nonces, hashes and reporting.
Rolling Out CSP Safely with Report-Only
CSP can easily break your site if you are too strict on day one. The recommended rollout process is:
- Start with a Report-Only policy.
UseContent-Security-Policy-Report-Onlyinstead ofContent-Security-Policy. Browsers will log violations but will not block anything. - Review violation reports and browser console.
Open the browser dev tools (Console and Network tabs) and note which domains are being blocked in theory. - Adjust your policy iteratively.
Add legitimate domains (CDNs, analytics, payment gateways) to the appropriate directives. - Switch to enforcing CSP.
Once you are confident, change the header name toContent-Security-Policyand keep monitoring.
Example CSP for a Typical Site
Here is a moderate CSP example that works for many sites using a CDN and an analytics provider:
Content-Security-Policy:
default-src 'self';
script-src 'self' https://cdn.examplecdn.com https://analytics.example-analytics.com;
style-src 'self' 'unsafe-inline' https://cdn.examplecdn.com;
img-src 'self' data: https://cdn.examplecdn.com;
font-src 'self' https://cdn.examplecdn.com;
connect-src 'self' https://analytics.example-analytics.com;
frame-ancestors 'self';
Notes:
- data: is allowed for
img-srcin case you use small inline data URLs. - frame-ancestors controls who can embed your site; this overlaps with
X-Frame-Options(see below). - We still allow
'unsafe-inline'for styles as a transitional compromise; for scripts we avoid it.
Configuring CSP on Nginx
add_header Content-Security-Policy
"default-src 'self';
script-src 'self' https://cdn.examplecdn.com;
style-src 'self' 'unsafe-inline';
img-src 'self' data:;
frame-ancestors 'self'" always;
For readability, you can keep the policy in a separate file and include it in your server block, or use a single-line version if your Nginx version complains about line breaks.
Configuring CSP on Apache
<IfModule mod_headers.c>
Header always set Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; frame-ancestors 'self'"
</IfModule>
If you are testing a policy, simply change Content-Security-Policy to Content-Security-Policy-Report-Only during the trial period.
X-Frame-Options: Protecting Against Clickjacking
What X-Frame-Options Does
X-Frame-Options tells the browser whether your page is allowed to be displayed inside an iframe or frame. This is important because of clickjacking attacks, where an attacker loads your site in a transparent frame on top of their own page and tricks the user into clicking on hidden buttons (for example, “Buy now” or “Delete account”).
The main values are:
- DENY – Never allow your site to be framed.
- SAMEORIGIN – Allow framing only from the same origin as your site.
- ALLOW-FROM uri – Allow only specific origins (obsolete and poorly supported).
For most sites, SAMEORIGIN is a safe default. If your site is never legitimately framed at all, you can use DENY.
X-Frame-Options vs CSP frame-ancestors
Modern CSP provides frame-ancestors, which is a more flexible and standardised way to control framing. For example:
Content-Security-Policy: frame-ancestors 'self' https://partner.example.com;
Because some older browsers still honour X-Frame-Options but not CSP, the common pattern is:
- Use CSP frame-ancestors as the primary control.
- Also set X-Frame-Options for backwards compatibility.
Configuring X-Frame-Options on Nginx
add_header X-Frame-Options "SAMEORIGIN" always;
Configuring X-Frame-Options on Apache
<IfModule mod_headers.c>
Header always set X-Frame-Options "SAMEORIGIN"
</IfModule>
Remember to adjust this if you intentionally embed certain pages in iframes on other domains (for example, a white-label widget). In that case, you will likely move toward a CSP frame-ancestors-only model and drop X-Frame-Options.
Referrer-Policy: Controlling What Your Users Leak
What the Referrer Header Is
When a user clicks a link from site A to site B, browsers typically send a Referer header (yes, misspelled historically) that contains the URL of the page they came from. This can unintentionally leak sensitive data:
- Internal paths or query parameters revealing structure of your app.
- Session tokens or one-time URLs if they are included in the query string (which they should not be).
- Campaign tags and internal tracking parameters.
Referrer-Policy lets you control how much of that information is sent.
Common Referrer-Policy Values
- no-referrer: Never send a referrer header.
- no-referrer-when-downgrade: Send full URL to HTTPS sites, but not when going from HTTPS to HTTP (older default behaviour).
- origin: Send only the scheme + host + port (e.g.
https://example.com), without path or query. - strict-origin-when-cross-origin: Full URL on same-origin requests; only origin for cross-origin requests; nothing when downgrading from HTTPS to HTTP. This is an excellent privacy-conscious default.
- same-origin: Full referrer for same-origin, no referrer for cross-origin.
For most modern websites we host, we recommend:
Referrer-Policy: strict-origin-when-cross-origin
This still gives you useful analytics for internal navigation, while limiting how much information is leaked externally.
Configuring Referrer-Policy on Nginx
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
Configuring Referrer-Policy on Apache
<IfModule mod_headers.c>
Header always set Referrer-Policy "strict-origin-when-cross-origin"
</IfModule>
Where to Configure Headers
Where you add these headers depends on your hosting architecture:
- Shared hosting with cPanel/DirectAdmin: Typically via
.htaccess(Apache) or via a control panel UI if provided. - VPS / Dedicated servers: Directly in your Nginx/Apache virtual host configuration for better performance and consistency.
- Reverse proxy setups: On the edge server (e.g. Nginx in front of Apache or PHP-FPM) so headers are applied to all backends.
If you are currently on shared hosting and planning to move to a VPS to gain more control over server-level security, our guide on migrating from shared hosting to a VPS without downtime walks through the typical transition path we see with growing projects.
Combined Example for Apache (.htaccess-Friendly)
Here is a minimal but strong header set you can drop into .htaccess (if allowed) or into your Apache virtual host config:
<IfModule mod_headers.c>
# HSTS (only on HTTPS vhost)
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains" env=HTTPS
# Clickjacking protection
Header always set X-Frame-Options "SAMEORIGIN"
# Basic CSP (adjust for your site)
Header always set Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; frame-ancestors 'self'"
# Referrer control
Header always set Referrer-Policy "strict-origin-when-cross-origin"
</IfModule>
Make sure you place this on your HTTPS virtual host only for HSTS. Some configurations use an environment variable like HTTPS=on to avoid accidentally sending HSTS over HTTP.
Combined Example for Nginx
In your TLS server block:
server {
listen 443 ssl http2;
server_name example.com www.example.com;
# ... SSL/TLS config ...
# HSTS
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# Clickjacking protection
add_header X-Frame-Options "SAMEORIGIN" always;
# CSP (start simple and tighten later)
add_header Content-Security-Policy
"default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; frame-ancestors 'self'" always;
# Referrer control
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# ... rest of config ...
}
After reloading Nginx, verify the headers using curl -I https://example.com/ or the Network tab in your browser’s developer tools.
Testing, Monitoring and Avoiding Surprises
How to Test Your Headers
After configuring your headers:
- Use curl:
curl -I https://example.com/and check that each header is present once (no duplicates with different values). - Use browser dev tools: Open the Network tab, click a request, and inspect the Response Headers section.
- Use online scanners: Tools like security header checkers can help spot missing or misconfigured headers. They are a complement to your own tests, not a replacement.
Whenever we roll out new headers for customers, we also keep an eye on access and error logs. If you are new to log analysis, our guide on reading web server logs to diagnose 4xx–5xx errors on Apache and Nginx is a practical reference.
Common Pitfalls
- Overly strict CSP on day one: Blocking legitimate scripts from CDNs, analytics or payment gateways. Roll out using Report-Only first.
- HSTS on domains without stable HTTPS: If certificates expire or a subdomain is misconfigured, users may be locked out.
- Multiple conflicting header values: For example, a CMS plugin adding one CSP and the server adding another. Consolidate into a single, well-managed policy.
- Different headers on different paths: Inconsistent policies between the main site and admin areas can create confusing behaviour and troubleshooting difficulties.
Deployment Strategy We Like in Real Projects
In many real-world deployments, we follow this sequence:
- Enable X-Frame-Options and Referrer-Policy – these are usually low-risk and easy wins.
- Confirm HTTPS is solid (valid certificates, redirects, no mixed content), then enable HSTS without preload.
- Introduce CSP in Report-Only mode, tune policies, then switch to enforcing mode when stable.
- After a few weeks of smooth operation, consider adding includeSubDomains and preload to HSTS for long-lived domains you fully control.
We treat HTTP security headers as part of a broader hardening checklist together with firewall rules, secure cookies and application-level security. If you want a bigger picture of hosting-side protections to configure when launching a new website, check our security checklist for new sites with 20 essential hosting settings.
How We See Customers Apply This on dchost.com
Across shared hosting, VPS, dedicated servers and colocation environments, we see a similar pattern: once teams grasp how HSTS, CSP, X-Frame-Options and Referrer-Policy work, they begin treating headers as versioned configuration rather than one-off tweaks. On simpler shared hosting setups, that may mean a carefully maintained .htaccess snippet committed to their project repo. On VPS and dedicated servers, it usually becomes a part of Ansible playbooks or Nginx/Apache include files, deployed consistently across staging and production.
From our side as a hosting provider, the important part is that your platform does not get in the way. Whether you run a single corporate site, a WooCommerce store, or a fleet of custom apps, you should be able to define your security headers once and trust that your web server serves them reliably. Combined with modern TLS settings, DNS hardening and good backup discipline, these headers close many of the common gaps we still see on otherwise well-built sites.
If you ever feel unsure where to start, you can begin with the conservative examples in this article, test them in a staging environment, and gradually evolve your policies as you gain more confidence and visibility.
Next Steps: Turn Security Headers into a Habit
HSTS, CSP, X-Frame-Options and Referrer-Policy are not magic bullets, but together they remove entire classes of attacks or at least make them significantly harder to exploit. The key is to treat them as living configuration: start with safer defaults, test carefully, monitor logs and reports, and iterate as your site and third-party integrations evolve. When you move to a new server, change a CDN, or redesign your front-end, reviewing your headers should be part of the release checklist, just like reviewing redirects or cache settings.
If your current hosting environment makes it difficult to control headers at the server level, that can be a signal it is time to move to a more flexible setup where you own the web server configuration. At dchost.com, we see customers get the best results when security headers are managed alongside TLS, WAF rules and application configs, not as isolated one-off changes. Take the example configurations in this article, adapt them to your stack, and add them to your next deployment plan. In a few iterations, you will have a clean, repeatable security header setup that quietly protects every visitor, every day.
