PERFORMANCE

Putting Cloudflare in front of your server: DNS, SSL modes and caching

By , FounderUpdated 8 min read

Step 1: Move DNS and choose what to proxy

Add your domain to Cloudflare, check that it imported your existing DNS records correctly, then change the nameservers at your domain registrar to the two Cloudflare gives you. Compare the records carefully before switching: a missing MX or TXT record means broken email or failed domain verification.

Every A, AAAA and CNAME record then has a proxy status:

  • Proxied (orange cloud): the hostname resolves to Cloudflare's IPs. Visitors connect to Cloudflare, which forwards the request to your server. You get caching, DDoS protection and Cloudflare's certificate at the edge, and your server's IP stays out of public DNS.
  • DNS only (grey cloud): the hostname resolves straight to your server. Cloudflare is just answering DNS.

The proxy handles HTTP and HTTPS on a fixed set of ports. Anything else must stay grey, or it stops working:

  • Mail hostnames such as mail.example.com that your MX records point to. MX records themselves can't be proxied, and SMTP, IMAP and POP3 don't go through the proxy.
  • SSH hostnames such as ssh.example.com, or simply connect by IP.
  • FTP, database ports, game servers and any other non-HTTP service.

A grey-cloud record that points at the same server as your website publishes that server's IP to anyone who looks it up. If you are hiding the origin, keep mail and other services on a different IP, or accept that the IP is known and rely on the firewall in step 6.

Step 2: Pick the right SSL/TLS mode

With a proxied record there are two connections: visitor to Cloudflare, and Cloudflare to your server (the origin). Cloudflare always handles the first with its own certificate. The mode under SSL/TLS → Overview controls the second.

ModeCloudflare to your serverUse it?
OffNo HTTPS anywhereNo
FlexiblePlain HTTPNo
FullHTTPS, but any certificate is accepted, even self-signed or expiredOnly as a short stepping stone
Full (strict)HTTPS with a valid certificate for your hostnameYes

Flexible is the one that causes trouble. The visitor sees a padlock, but the second half of the trip is unencrypted, so the padlock is misleading. It also causes redirect loops: your server (or WordPress, or your app) redirects HTTP to HTTPS, Cloudflare fetches the HTTPS URL from your server over HTTP again, your server redirects again, and the browser eventually gives up with "too many redirects". The fix is not to remove your redirect. Install a certificate on the server and switch to Full (strict).

Newer zones may show an automatic SSL/TLS setting that picks a mode for you. Once your server has a valid certificate, choose the custom option and set Full (strict) explicitly so the mode can't drift. Then turn on Always Use HTTPS under SSL/TLS → Edge Certificates. Cloudflare's SSL mode documentation has the full details of each mode.

Step 3: Put a valid certificate on the server

Full (strict) needs a certificate Cloudflare trusts. You have two good options:

Cloudflare Origin CALet's Encrypt
Trusted byCloudflare onlyBrowsers and Cloudflare
ValidityYou choose, up to 15 yearsShort-lived; renewed automatically
Renewal workRarely anyCertbot timer must keep working
If you turn the proxy offBrowsers show a certificate errorKeeps working

For an Origin CA certificate, go to SSL/TLS → Origin Server → Create Certificate. By default it covers example.com and *.example.com. Save the private key immediately, because Cloudflare shows it only once. Then point Nginx at the files:

/etc/nginx/sites-available/example.com
server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name example.com www.example.com;

    ssl_certificate     /etc/ssl/cloudflare/example.com.pem;
    ssl_certificate_key /etc/ssl/cloudflare/example.com.key;

    # ... your root or proxy_pass configuration
}

Make the key readable by root only (sudo chmod 600 on the .key file), run sudo nginx -t, then sudo systemctl reload nginx.

Let's Encrypt through Certbot also works behind the proxy, because the validation request reaches your server through Cloudflare. Choose it if you might switch the proxy off later or if some hostnames on the server are grey-cloud. The Node.js deployment guide walks through the Nginx and Certbot setup.

Step 4: Cache static files, and be careful with HTML

Out of the box, Cloudflare caches common static file types such as images, CSS, JavaScript and fonts, and does not cache HTML. That default is safe. To get more from it:

  • Send long Cache-Control headers from your server for files with a hash in the name, for example public, max-age=31536000, immutable. Build tools like Next.js and Vite already fingerprint these files, so a new deploy uses new URLs.
  • Use Caching → Cache Rules to adjust behaviour per path, for example a longer edge TTL for /assets/ or /wp-content/uploads/.
  • Purge the cache after a deploy that changes un-fingerprinted files, from Caching → Configuration.

Caching HTML is where people get burned. A rule that marks every page as eligible for cache will happily serve one user's logged-in dashboard, cart or admin bar to the next visitor. If you do cache HTML, add a bypass rule first, for example an expression like:

Cache Rule expression (bypass cache)
(starts_with(http.request.uri.path, "/wp-admin"))
or (http.request.uri.path eq "/wp-login.php")
or (http.cookie contains "wordpress_logged_in")
or (http.cookie contains "woocommerce_items_in_cart")

Test logged out and logged in, in two different browsers, before relying on it. For WordPress specifically, our guide to fixing a slow WordPress site covers page caching on the server side too.

Step 5: Restore real visitor IPs

Behind the proxy, every request arrives from a Cloudflare IP. Your access logs, rate limits, fail2ban and any app that records IPs will see Cloudflare instead of the visitor. Cloudflare sends the real address in the CF-Connecting-IP header, and Nginx's realip module can use it, but only for requests that genuinely come from Cloudflare. Otherwise anyone could fake the header by hitting your server directly.

The ranges change from time to time, so generate the config from Cloudflare's published lists rather than pasting them by hand:

/usr/local/sbin/update-cloudflare-realip (run with sudo)
#!/usr/bin/env bash
set -euo pipefail
v4=$(curl -fsSL https://www.cloudflare.com/ips-v4)
v6=$(curl -fsSL https://www.cloudflare.com/ips-v6)
out=/etc/nginx/conf.d/cloudflare-realip.conf
{
  echo "# Generated from https://www.cloudflare.com/ips/ on $(date -u +%F)"
  for range in $v4 $v6; do
    echo "set_real_ip_from $range;"
  done
  echo "real_ip_header CF-Connecting-IP;"
} > "$out"
nginx -t && systemctl reload nginx

Files in /etc/nginx/conf.d/ are loaded inside the http block on Ubuntu, so this applies to every site. After a reload, $remote_addr holds the visitor's IP. If you proxy to a Node.js or Python app, pass it on with proxy_set_header X-Real-IP $remote_addr; and read that header in the app.

Step 6: Lock the server to Cloudflare

If ports 80 and 443 accept connections from anywhere, an attacker who learns your server's IP can skip Cloudflare entirely, along with its caching and DDoS protection. Allow web traffic only from the ranges published at cloudflare.com/ips, and keep SSH open as before:

terminal
for range in $(curl -fsSL https://www.cloudflare.com/ips-v4) $(curl -fsSL https://www.cloudflare.com/ips-v6); do
  sudo ufw allow proto tcp from "$range" to any port 80,443 comment 'Cloudflare'
done

# Remove the old "allow from anywhere" web rules (use whichever you created)
sudo ufw delete allow 80/tcp
sudo ufw delete allow 443/tcp
sudo ufw status numbered

Check that OpenSSH is still in the list before you log out. Then confirm that curl -I http://SERVER_IP from another machine times out, while the site still loads through its domain.

Cloudflare's ranges are not fixed forever. If they add a range and your firewall doesn't, requests from that part of their network can't reach you, and visitors may see 522 errors. Check the published list every few months and after any unexplained 52x errors, and update both the firewall and the realip config. Also remember that ports published by Docker bypass ufw; see our Linux server security checklist.

Where NevaraCloud fits

Every NevaraCloud plan includes the Cloudflare CDN and free SSL, so on our managed hosting you don't choose SSL modes, install origin certificates or maintain firewall rules yourself. If you just want your site fast and secure, that is the simpler route.

If you run your own server and want Cloudflare in front of it done properly, or you are stuck in a redirect loop or a wall of 52x errors, we can set it up or fix it for you, quoted after we look at your setup.

Rather we handled it?

Managed hosting billed in LKR, Docker hosting, or hands-on deployment help. Tell us what you're working on.

Ask us on WhatsApp