Files
talktime/docs/production/security-headers.md
T
patrickandClaude Sonnet 5 4a19335a1e feat: rework starter kit for self-hosted deploy (Vite/React + Fastify/Drizzle/Postgres)
Replace Next.js/Supabase/Vercel stack with a self-hostable setup: Vite+React
frontend, Fastify+Drizzle+PostgreSQL backend with own JWT auth, deploy via
git pull + rsync + systemd (checkout/service separated, updates pulled from
Gitea). Adds a reference auth route (register/login/me) as the canonical
pattern for new routes. Updates all skills/rules/agents/docs to match.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BMdBJfD9TT6XUU2NqGG1PN
2026-09-08 11:42:47 +02:00

1.9 KiB

Security Headers Configuration

Protect against XSS, Clickjacking, MIME sniffing, and other common web attacks.

Setup

Set security headers via the reverse proxy (nginx) in front of both frontend static files and the backend, or via @fastify/helmet on the backend directly. nginx is the simpler single place to cover everything.

add_header X-Frame-Options "DENY" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "origin-when-cross-origin" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

Add these inside the server { } block for the site.

Alternative: @fastify/helmet on the backend

cd backend && npm install @fastify/helmet
// backend/src/server.ts
import helmet from "@fastify/helmet";

await app.register(helmet);

Covers only API responses — still set the same headers in nginx for the static frontend files.

What Each Header Does

Header Protection
X-Frame-Options: DENY Prevents your site from being embedded in iframes (clickjacking)
X-Content-Type-Options: nosniff Prevents browsers from guessing content types (MIME sniffing)
Referrer-Policy Controls how much URL info is sent to other sites
Strict-Transport-Security Forces HTTPS connections

Verify After Deployment

  1. Open Chrome DevTools
  2. Go to Network tab
  3. Click on any request to your site
  4. Check Response Headers section
  5. Verify all 4 headers are present

Advanced (Optional)

Content-Security-Policy (CSP) - The most powerful header, but can break your app if misconfigured. Only add after thorough testing:

Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'

Start with report-only mode first: Content-Security-Policy-Report-Only