Insights / Technical notes
Achieving Secure Static Site Delivery with Cloudflare Pages
A practical guide to static site deployment on Cloudflare Pages and security header/CSP configuration using _headers. Also covers why we switched back from Workers to Pages.

Table of contents
Cloudflare Pages is an excellent platform for hosting static sites. This article covers our actual deployment setup and security configuration using the _headers file.
Deployment Architecture: Why We Left Workers and Returned to Pages
Initially, we planned to use Cloudflare Workers for backend processing of the contact form. Workers allow server-side email sending and validation.
However, we encountered the following challenges during implementation:
- Build complexity: Serving Astro’s build output through Workers required additional configuration
- Debugging overhead: Behavioral differences between local
wrangler devand production - Cache control: Pages integrates more naturally with Cloudflare’s CDN
Ultimately, we adopted ssgform.com as an external service for the contact form, completely eliminating server-side processing. This removed the need for Workers, allowing us to deploy as a pure static site on Pages.
Security Configuration with _headers
On Cloudflare Pages, you can specify HTTP response headers in the public/_headers file. Below is an excerpt of the configuration we actually use.
Content-Security-Policy (CSP)
CSP is a critical header for preventing cross-site scripting (XSS) attacks. It specifies allowed resource origins using a whitelist approach.
Content-Security-Policy: default-src 'self';
script-src 'self' 'unsafe-inline' https://challenges.cloudflare.com https://pagead2.googlesyndication.com;
style-src 'self' 'unsafe-inline';
img-src 'self' https://acecore.net data:;
connect-src 'self' https://challenges.cloudflare.com https://pagead2.googlesyndication.com;
frame-src https://challenges.cloudflare.com https://googleads.g.doubleclick.net;
form-action https://ssgform.com;
Key points:
- script-src: Allow Cloudflare Turnstile (
challenges.cloudflare.com) and AdSense - img-src: Allow the same-origin Cloudflare Images endpoint and Unsplash
- form-action: Restrict form submissions to ssgform.com only
- frame-src: Allow Turnstile iframes and AdSense ad frames
Other Security Headers
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=()
- X-Content-Type-Options: Prevent MIME sniffing
- X-Frame-Options: Prevent iframe embedding as a clickjacking countermeasure
- Referrer-Policy: Send only the origin for cross-origin requests
- Permissions-Policy: Disable unnecessary browser APIs (camera, microphone, geolocation)
Cache Control
We set long-term caching for static assets and shorter caching for HTML.
/_astro/*
Cache-Control: public, max-age=31536000, immutable
/*.html
Cache-Control: public, max-age=3600
Files in the _astro/ directory output by Astro include content hashes, making it safe to cache them for one year with immutable. HTML has a moderate update frequency, so we limit it to a one-hour cache.
Pages Deployment Configuration
Cloudflare Pages project settings are simple:
| Setting | Value |
|---|---|
| Build command | npx astro build |
| Output directory | dist |
| Node.js version | 22 |
Once you connect a GitHub repository, pushes to the main branch trigger automatic deploys. Preview deployments are also auto-generated per PR, making reviews smoother.
Summary
The key is asking yourself: “Do I really need server-side processing?” By leveraging external services to eliminate Workers, both deployment and security management became simpler. CSP configuration via _headers takes some initial effort, but once written, it applies to all pages — making it a highly cost-effective security measure.
Deployment Architecture Evolution
Initial Setup
Delivered the static site on Cloudflare Pages.
Worker Migration
Migrated to Workers for contact form processing.
Return to Pages
Switched back to static delivery by adopting an external form service.
Security Hardening
Configured CSP and security headers via _headers.
Frequently Asked Questions
Should I choose Cloudflare Pages or Workers?
For static sites that don't require server-side processing, Pages is optimal. CDN integration is seamless and deployment is straightforward. Form processing can be handled by external services.
What security headers should be set in the _headers file?
Content-Security-Policy, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, and Permissions-Policy are the essentials. Adjust CSP according to the external resources your site uses.
How do I allow AdSense and Analytics in CSP settings?
Add googletagmanager.com and googlesyndication.com domains to script-src. You may also need to allow related domains in img-src and connect-src.