Engineering
Security Headers on a Static Site When Your Host Won't Set Them
Part 4 of the thread Building this notebook
- My new static blog got an F on a header scan, because DigitalOcean's static sites can't set custom response headers.
- Two headers can live in a
<meta>tag, CSP and referrer policy, and they're the two that matter most for a blog. - For the full set, put a proxy like Cloudflare in front, or move to a host that reads a
_headersfile. - The grade is a signal, not a verdict. Know which missing header would actually hurt someone.
This site had been live for about an hour when I ran it through a security header scanner. It came back with a big red F.
Nothing was broken, and nothing was exposed. It's a static site: no login, no database, no forms, no server code for anyone to poke at. But the grade still stung. And if you work anywhere near security, people will run that scan on your personal site.
What the F actually means
The scanner checks for six HTTP response headers:
| Header | What it does | Works in a <meta> tag? |
|---|---|---|
| Strict-Transport-Security (HSTS) | Tells browsers to only ever use HTTPS | No |
| Content-Security-Policy (CSP) | Limits where scripts, styles, and images can load from | Yes, minus frame-ancestors |
| X-Frame-Options | Stops other sites from framing yours (clickjacking) | No |
| X-Content-Type-Options | Stops browsers from guessing file types | No |
| Referrer-Policy | Controls how much of your URL leaks to other sites | Yes |
| Permissions-Policy | Turns off browser features you don't use, like the camera and geolocation | No |
I had none of them. Not because I forgot, but because the host wouldn't let me set them.
The catch with DigitalOcean static sites
DigitalOcean's App Platform is a great home for a static site. It's cheap, it's fast, and it deploys on every push. But static site components don't let you define custom response headers. There's a feature request for it from 2024, and as of this writing it's still open.
So what can you actually do?
Fix 1: put the important ones in the HTML
Two of the six can live in a <meta> tag, and they happen to be the two that matter most for a blog:
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src 'self' data:; style-src 'self' 'unsafe-inline'; script-src 'self'">
<meta name="referrer" content="strict-origin-when-cross-origin">
Heads up
Know the limits, though. A meta CSP can't use
frame-ancestors, so it won't stop clickjacking. And HSTS, X-Frame-Options, and the rest only work as real headers. The scanner will still grumble, but you've covered the parts that protect your readers.
Tip
Tune the CSP to what your site actually loads. If you pull in a script from a CDN (my editor page loads one), that page needs its own rule, or it'll stop working the moment you add the policy.
Fix 2: put a proxy in front
For the full set, route your domain through a proxy that can add headers. Cloudflare's free plan does this with Transform Rules.
The trade-off is moving your DNS there, which means carefully re-creating your email records (MX, SPF, DKIM, DMARC) so mail keeps flowing.
Fix 3: pick a host that reads a headers file
Some static hosts let you drop a _headers file in your build output and apply it for you. If headers matter a lot to you, that's the least fiddly option. It just means moving hosts.
Where I landed
For a personal blog, Fix 1 gets you most of the real-world benefit in ten minutes. The grade is a signal, not a verdict. What matters is knowing which missing header would actually hurt someone, and that answer is different for a static notebook than for a web app with a login page.
- Picking a CMS for a Static Blog in 2026Resources & Recommendations
- Your Fonts Only Look Right on Your ComputerWeb Design