Content Security Policy (CSP) is an HTTP response header that defines which content sources (such as scripts, stylesheets, images, and fonts) a browser is permitted to load. A properly configured CSP acts as a robust defense layer, preventing unauthorized code execution in the browser and shielding your site from Cross-Site Scripting (XSS) and clickjacking attacks (unauthorized embedding of your site inside an invisible frame).
At Seravo, all nginx servers include a baseline CSP configuration by default in /data/wordpress/nginx/security.conf:
add_header Content-Security-Policy "upgrade-insecure-requests";
This default rule instructs the browser to automatically load any insecure (HTTP) assets over an encrypted HTTPS connection. This guide explains how you can safely introduce a broader, stricter CSP policy without breaking your site’s layout or dynamic features.
Prerequisites
SSH access to the server.
An understanding of the external resources used by your site (such as Google Analytics, embedded videos, live chat widgets, or external web fonts).
Key Directives and WordPress Considerations
Before deploying rules, it is helpful to familiarize yourself with common CSP directives:
default-src: Fallback rule for resource types that do not have their own explicit directive.script-src: Permitted JavaScript sources.style-src: Permitted CSS stylesheets and styling sources.img-src: Permitted image sources.font-src: Permitted font sources (e.g., Google Fonts).frame-ancestors: Defines which domains are allowed to embed this site in an<iframe>(protects against clickjacking).
Important Note for WordPress Sites:
The WordPress core, numerous plugins, and popular page builders (such as Elementor and Divi) rely heavily on dynamically generated inline scripts and styles (inline styles / scripts). Because of this, WordPress environments almost always require the 'unsafe-inline' keyword in both script-src and style-src, and frequently 'unsafe-eval' for dynamic script evaluation. Omitting these will likely break your site's dashboard or visual layout.
Step-by-Step Safe Implementation of CSP
Because overly strict CSP policies block browsers from loading required assets, implementation should always follow a staged approach using report-only mode.
1. Configure Rules in Report-Only Mode
Start with the Content-Security-Policy-Report-Only header. In this mode, the browser does not block any assets; it only logs potential violations to the developer console.
Connect to your site via SSH and open your nginx security configuration file:
nano /data/wordpress/nginx/security.conf
Replace or update the existing CSP directive with your test policy. Here is a solid starting baseline:
add_header Content-Security-Policy-Report-Only "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://www.google-analytics.com https://www.googletagmanager.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com data:; img-src 'self' data: https:; frame-ancestors 'self';";
Save the file (in nano:
Ctrl + O,Enter, and exit withCtrl + X).
2. Test nginx Syntax and Restart
Before restarting nginx, always confirm that there are no syntax errors in the configuration files:
wp-restart-nginx --test
If the output confirms that syntax is ok, restart nginx:
wp-restart-nginx
3. Monitor and Resolve Violations in Browser Developer Tools
Open your website in a browser and open the developer tools (press F12 and select the Console tab).
Navigate across various page types (front page, contact forms, checkout/cart pages, and the WP-admin dashboard).
Look for yellow or red CSP violation warnings (e.g., "Refused to load the script...").
If a legitimate external service needed by your site (such as a YouTube embed or chat script) triggers a warning, add that service’s domain to the appropriate directive in
security.confand restart nginx.
4. Activate Protection in Production
Once you have tested the site thoroughly and no unintended warnings appear in the console, you can enforce the policy:
Open the file again:
nano /data/wordpress/nginx/security.conf
Change the header directive name from
Content-Security-Policy-Report-OnlytoContent-Security-Policy.Save the file and restart nginx:
wp-restart-nginx
Testing and Troubleshooting
How do I verify active headers from the command line?
You can inspect the headers returned by your web server using:
curl -I https://example.com
Check the output to ensure the
content-security-policyheader appears with your specified rules.Did your site layout or features break immediately after enforcement?
This usually indicates that a theme asset requires
'unsafe-inline'or an external domain is missing from the whitelist. You can quickly roll back by changing the header name back toContent-Security-Policy-Report-Onlyand runningwp-restart-nginx, restoring normal site functionality while you adjust your directives.
See Also
Content Security Policy is a powerful security mechanism, but keeping it effective requires ongoing maintenance, especially when installing new plugins or third-party tracking scripts. By taking advantage of report-only mode, you ensure your site stays protected without risking unintended downtime. If you need assistance formulating complex CSP rules, Seravo’s WordPress specialists are always ready to help at [email protected].
