/ Security Audit Fixes / Ghost

How to Fix Security Headers in Ghost

Ghost CMS runs as a Node.js application typically fronted by nginx (or Caddy). Security headers belong at the nginx layer, not in Ghost itself — Ghost doesn't have built-in header management. This guide covers every fix our Security Audit raises on Ghost: HTTP security headers in the nginx reverse proxy, Ghost's session and cookie configuration, and publishing security.txt. Tested against Ghost 5.95 on Node 20 and nginx 1.24. For nginx (Ghost's typical reverse proxy), see the nginx variant; for the full finding catalogue, see Security Audit Fixes.

1. Locate Ghost's nginx config

Ghost-CLI installs typically create a vhost at /etc/nginx/sites-available/yourdomain.com-ssl.conf.

Step 1
Find the file
ls /etc/nginx/sites-available/
Open the file matching your domain with -ssl suffix:
sudo nano /etc/nginx/sites-available/yourdomain.com-ssl.conf

2. Add the six security headers

Step 1
Add directives inside the server block
Inside server { listen 443 ssl http2; ... }, before the location / block:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; frame-ancestors 'self'; connect-src 'self'" always;
⚠️ Ghost themes commonly use inline scripts and styles. The CSP above includes 'unsafe-inline' for both — restrict only after auditing your specific theme.
💡 If you use Ghost Members + Stripe, you'll need to add js.stripe.com and api.stripe.com to script-src and connect-src respectively.

3. Test and reload nginx

Step 1
Validate config
sudo nginx -t
sudo nginx -s reload
If nginx -t reports any error, fix before reloading.

4. Harden Ghost session and cookies

Ghost's session cookies inherit settings from the Node.js cookie library. The defaults are reasonable; the only common hardening is forcing HTTPS-only cookies.

Step 1
Force HTTPS in Ghost config
In config.production.json at your Ghost install root:
{
  "url": "https://yourdomain.com",
  ...
}
When url uses https://, Ghost automatically sets the Secure flag on session cookies.
Step 2
Restart Ghost
cd /var/www/ghost
ghost restart

5. Publish security.txt

Step 1
Serve via nginx location block
In the SSL server block:
location = /.well-known/security.txt {
    default_type text/plain;
    return 200 "Contact: mailto:security@yourdomain.com\nExpires: 2027-05-18T00:00:00.000Z\nPreferred-Languages: en\nCanonical: https://yourdomain.com/.well-known/security.txt\n";
}
Reload nginx. This serves the file directly without disk I/O.

6. Verify

Step 1
Curl test
curl -sI https://yourdomain.com/ | grep -iE "strict-transport|x-frame|x-content|referrer|permissions|content-security"
Re-run the Security Audit.

🛡 Re-run the audit

Verify every header, TLS protocol and security.txt with a fresh scan.

Run Security Audit →
Related Guides: Security Audit Fixes  ·  Fix in nginx  ·  Fix via Cloudflare  ·  Security Audit Guide
💬 Got a problem?