Content Security Policy (CSP) Issues
If you're using nginx to serve your Docusaurus site and encountering Content Security Policy (CSP) errors, this guide will help you fix them.
Common CSP Errors
You might see errors like these in your browser console:
Content-Security-Policy: The page's settings blocked a script (script-src-elem)
Content-Security-Policy: The page's settings blocked the loading of a resource (img-src)
Content-Security-Policy: The page's settings blocked the loading of a resource (connect-src)
Understanding CSP
Content Security Policy is a security feature that helps prevent XSS attacks by controlling which resources can be loaded. However, it can also block legitimate external services used by your Docusaurus site.
Common External Services
Modern Docusaurus sites often use:
- Analytics services for tracking
- Widget services for donations/support
- Search services for AI-powered search
- Comment systems like Giscus for GitHub-based comments
- SVG Data URIs for icons and graphics
Docusaurus CSP Configuration (GitHub Pages)
If you're deploying to GitHub Pages, you may encounter CSP issues because GitHub Pages sets strict CSP headers by default. You can configure CSP directly in your docusaurus.config.ts
file:
Basic Giscus Comments Configuration
const config: Config = {
title: 'Your Site Title',
// ... other config
// Content Security Policy configuration to allow Giscus comments
headTags: [
{
tagName: 'meta',
attributes: {
'http-equiv': 'Content-Security-Policy',
content: "default-src 'self'; frame-src 'self' https://giscus.app; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://giscus.app; style-src 'self' 'unsafe-inline' https://giscus.app; img-src 'self' data: https:; connect-src 'self' https://giscus.app https://api.github.com; font-src 'self' data:;",
},
},
],
// ... rest of your config
};
With Additional Services
headTags: [
{
tagName: 'meta',
attributes: {
'http-equiv': 'Content-Security-Policy',
content: "default-src 'self'; frame-src 'self' https://giscus.app; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://giscus.app https://cdnjs.buymeacoffee.com https://widget.buymeacoffee.com https://us-assets.i.posthog.com; style-src 'self' 'unsafe-inline' https://giscus.app; img-src 'self' data: https:; connect-src 'self' https://giscus.app https://api.github.com https://api.mendable.ai https://us.i.posthog.com; font-src 'self' data:;",
},
},
],
Common Giscus CSP Errors
If you see these errors for Giscus comments:
Content-Security-Policy: The page's settings blocked the loading of a resource (frame-src) at https://giscus.app/
Add these domains to your CSP:
- frame-src:
https://giscus.app
(for the comment iframe) - script-src:
https://giscus.app
(for Giscus JavaScript) - style-src:
https://giscus.app
(for Giscus CSS) - connect-src:
https://giscus.app https://api.github.com
(for API calls)
Nginx CSP Configuration
Add these CSP headers to your nginx configuration to allow required external resources:
⚠️ Important: Use Single-Line Format
Multi-line CSP headers can cause 502 Bad Gateway errors. Always use single-line format:
server {
listen 443 ssl;
http2 on;
server_name your-domain.com;
# Your existing SSL and other configurations...
# Content Security Policy - SINGLE LINE FORMAT
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://external-analytics-assets.com https://widget-service.com; img-src 'self' https://external-analytics.com data:; connect-src 'self' https://search-service.com https://analytics-api.com https://analytics-app.com; style-src 'self' 'unsafe-inline'; font-src 'self' data:; frame-src 'self'; object-src 'none'; base-uri 'self'; form-action 'self';" always;
# Your existing location blocks...
location / {
# Your proxy configuration
}
}
Real-World Examples
PostHog Analytics Only
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://us-assets.i.posthog.com https://cdnjs.buymeacoffee.com; img-src 'self' data:; connect-src 'self' https://api.mendable.ai https://us.i.posthog.com https://app.posthog.com; style-src 'self' 'unsafe-inline';" always;
With Google Fonts
If your site uses Google Fonts, add these domains:
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://us-assets.i.posthog.com https://cdnjs.buymeacoffee.com; img-src 'self' data:; connect-src 'self' https://api.mendable.ai https://us.i.posthog.com https://app.posthog.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com data:;" always;
Google Fonts requires two domains:
fonts.googleapis.com
→ CSS stylesheets (add tostyle-src
)fonts.gstatic.com
→ Font files (add tofont-src
)
Minimal CSP Configuration
For basic testing, use this minimal configuration:
# Add to your nginx server block
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://your-analytics-domain.com https://your-widget-domain.com; img-src 'self' data:; connect-src 'self' https://your-api-domain.com; style-src 'self' 'unsafe-inline';" always;
Directive Explanations
script-src
Controls which scripts can be executed:
'self'
: Scripts from your own domain'unsafe-inline'
: Inline scripts (required by Docusaurus)'unsafe-eval'
: Dynamic code evaluation (required by some components)- External domains for analytics and widgets
img-src
Controls which images can be loaded:
'self'
: Images from your own domaindata:
: Data URIs for SVG icons and graphics
connect-src
Controls which URLs can be loaded using AJAX, WebSockets, etc.:
'self'
: Your own domain- External services and analytics
Implementation Steps
- Identify your external services by checking browser console errors
- Update your nginx configuration with the appropriate domains
- Test the configuration:
sudo nginx -t
sudo systemctl reload nginx - Verify functionality works as expected
Troubleshooting Tips
Configuration Not Working?
-
Check nginx syntax:
sudo nginx -t
-
Verify headers are being sent:
curl -I https://your-domain.com
-
Check nginx error logs:
sudo tail -f /var/log/nginx/error.log
Still Getting Errors?
If you're still seeing CSP errors after applying the configuration:
- Check for multiple CSP headers - only one should be present
- Ensure no conflicting CSP in your application
- Verify the domain names match exactly (check browser console for exact URLs)
502 Bad Gateway / Cloudflare Errors
If you get a white page with "Bad Gateway" or Cloudflare errors after adding CSP:
-
Check nginx syntax:
sudo nginx -t
-
Use single-line CSP format (multi-line can cause HTTP protocol errors):
# ❌ DON'T - Multi-line format
add_header Content-Security-Policy "
default-src 'self';
script-src 'self';
" always;
# ✅ DO - Single-line format
add_header Content-Security-Policy "default-src 'self'; script-src 'self';" always; -
Temporarily remove CSP to confirm nginx works:
# Comment out CSP line and test
sudo nginx -t && sudo systemctl reload nginx -
Start with minimal CSP and add domains gradually:
add_header Content-Security-Policy "default-src 'self' 'unsafe-inline' data: https:;" always;
Multiple Domains for Same Service
Some services (like PostHog) use multiple domains:
- Assets domain:
us-assets.i.posthog.com
(for scripts) - API domain:
us.i.posthog.com
(for data collection) - App domain:
app.posthog.com
(for events/tracking)
Add all required domains to avoid partial functionality.
Adding New External Services
When adding new external services to your Docusaurus site:
- Check browser console for CSP errors
- Identify the blocked domain from the error message
- Add the domain to the appropriate CSP directive
- Test thoroughly after making changes
Security Considerations
- Use specific domains instead of wildcards when possible
- Avoid 'unsafe-eval' if your site doesn't require it
- Regularly review your CSP policy as you add new features
- Test in multiple browsers to ensure compatibility
- Monitor for new CSP violations in production
Common Domain Patterns
Replace the example domains in the configuration with your actual service domains:
- Analytics: Usually have domains ending in analytics-related TLDs
- CDN Services: Often use CDN-specific domain patterns
- Widget Services: Typically have widget or button-related domains
- Search Services: Usually have search or AI-related domain names