How I harden a small website on Cloudflare’s free plan
You don’t need an enterprise budget to make a small site hard to attack. I run a few personal sites on Cloudflare’s free plan, and this is the checklist I go through for each one. None of it costs money; most of it takes a few minutes.
1. Encrypt the whole path, not just the visitor’s half
Cloudflare sits between the visitor and your origin server. “Flexible” SSL only encrypts the first half of that trip. I set the SSL/TLS mode to Full (strict), which means Cloudflare also talks to the origin over TLS and checks that the origin’s certificate is valid. A free Cloudflare Origin CA certificate or a Let’s Encrypt certificate on the origin both work.
- Turn on Always Use HTTPS so plain HTTP requests get redirected.
- Set the minimum TLS version to 1.2.
2. Tell browsers to never use plain HTTP again (HSTS)
A redirect still leaves the very first request exposed. HTTP Strict Transport Security tells the browser to go straight to HTTPS for a set period. I start with a short max-age, confirm nothing breaks, then raise it to a year. Only add includeSubDomains once every subdomain serves HTTPS, and treat preload as a one-way door.
3. Turn on the free WAF protections
The free plan includes Cloudflare’s free managed ruleset, which is on by default, and Bot Fight Mode, which handles a lot of automated noise. On this site the app only answers the paths it knows, so probes for /wp-login.php or /.env just get a 404. If you need to block something specific, the free plan also gives you a handful of custom rules.
4. Sign the DNS (DNSSEC)
DNSSEC lets resolvers verify that DNS answers for your domain really came from your zone. In Cloudflare it’s one click, plus adding the DS record at your registrar. Until the registrar step is done, it isn’t actually protecting anything, so I always go back and confirm it shows as active.
5. Lock down email, even if the domain never sends mail
Attackers love spoofing domains that have no email policy. Three DNS records fix that:
- SPF lists who may send mail for the domain. A domain that never sends mail can publish
v=spf1 -all. - DMARC tells receivers what to do with mail that fails checks. I aim for
p=reject. - CAA limits which certificate authorities may issue certificates for the domain.
6. Send real security headers
Headers cost nothing and close whole classes of bugs. This site sends, among others:
Content-Security-Policy: default-src 'none'; script-src 'self' https://static.cloudflareinsights.com; style-src 'self'; img-src 'self' data:; ...
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=()
Cross-Origin-Opener-Policy: same-origin
A strict Content Security Policy is the big one. It stops the browser from running scripts I didn’t ship myself, which takes most cross-site scripting off the table. Writing the site without inline scripts or third-party trackers makes a strict policy easy.
7. Review it on a schedule
Settings drift. A new subdomain appears, a test DNS record gets left behind, a certificate is about to expire. I re-check each site on a recurring schedule: DNS records, SSL mode, WAF events, headers and DNSSEC status. Security is a habit, not a one-time setup.
Takeaway: Full (strict) TLS, HSTS, the free WAF, DNSSEC, SPF/DMARC/CAA and a strict CSP get a small site most of the way there, for $0.