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
1.9 KiB
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.
nginx (recommended — covers frontend + backend uniformly)
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
- Open Chrome DevTools
- Go to Network tab
- Click on any request to your site
- Check Response Headers section
- 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