Start with Content-Security-Policy-Report-Only to monitor violations without blocking resources. Add the add_header directive to your server block:
server {
listen 443 ssl;
server_name yourdomain.com;
# CSP Report-Only - monitors without blocking
add_header Content-Security-Policy-Report-Only "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; report-uri https://cspwarden.com/api/v1/csp-report/YOUR-DOMAIN-TOKEN/; report-to csp-endpoint" always;
# Companion header: maps the "csp-endpoint" group named by report-to to your report URL
add_header Reporting-Endpoints 'csp-endpoint="https://cspwarden.com/api/v1/csp-report/YOUR-DOMAIN-TOKEN/"' always;
# ... your existing server config ...
}Important: The always parameter ensures the header is added for all response codes, including errors.
Ship both headers together: report-to names a reporting group (csp-endpoint), and the Reporting-Endpoints header maps that name to the actual HTTPS URL. The legacy report-uri keeps older browsers working.
NGINX's add_header directives in a location block override all add_header directives from the parent server block. If you use add_header in a location block, you must also include the CSP header there:
server {
# These headers apply to the whole server
add_header Content-Security-Policy-Report-Only "default-src 'self'; report-uri https://cspwarden.com/api/v1/csp-report/YOUR-DOMAIN-TOKEN/; report-to csp-endpoint" always;
add_header Reporting-Endpoints 'csp-endpoint="https://cspwarden.com/api/v1/csp-report/YOUR-DOMAIN-TOKEN/"' always;
location /api/ {
# If you add ANY header here, you must repeat BOTH CSP headers
add_header Content-Security-Policy-Report-Only "default-src 'self'; report-uri https://cspwarden.com/api/v1/csp-report/YOUR-DOMAIN-TOKEN/; report-to csp-endpoint" always;
add_header Reporting-Endpoints 'csp-endpoint="https://cspwarden.com/api/v1/csp-report/YOUR-DOMAIN-TOKEN/"' always;
add_header X-Custom-Header "value";
proxy_pass http://backend;
}
}After reviewing violations in your CSP Warden dashboard, replaceContent-Security-Policy-Report-Only withContent-Security-Policy:
# Enforce CSP - blocks violating resources and reports
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; report-uri https://cspwarden.com/api/v1/csp-report/YOUR-DOMAIN-TOKEN/; report-to csp-endpoint" always;
add_header Reporting-Endpoints 'csp-endpoint="https://cspwarden.com/api/v1/csp-report/YOUR-DOMAIN-TOKEN/"' always;Validate your configuration and reload NGINX:
sudo nginx -t
sudo systemctl reload nginxlocation block is overriding your server-level headers.curl -I yourdomain.com to check response headers. If you see duplicates, your application may also be setting CSP headers.report-uri is accessible from your server and matches your domain token exactly.