Cloudflare CDN Configuration for VPS
Cloudflare acts as a reverse proxy and CDN in front of your VPS, providing DDoS protection, SSL termination, global caching, and a web application firewall without any changes to your server software. This guide covers adding your domain to Cloudflare, configuring DNS, SSL modes, caching rules, page rules, and WAF settings to improve both performance and security for VPS-hosted websites.
Prerequisites
- A domain name registered at any registrar
- A VPS with a web server running (Nginx or Apache)
- A Cloudflare account (free tier works for most configurations)
- Access to your domain registrar's nameserver settings
Adding Your Domain to Cloudflare
- Log into Cloudflare Dashboard and click Add a Site
- Enter your domain (e.g.,
example.com) and click Add Site - Select a plan (Free is sufficient for CDN and basic WAF)
- Cloudflare will scan your existing DNS records — review and confirm them
- Update your domain's nameservers at your registrar to the two Cloudflare nameservers provided:
aria.ns.cloudflare.combob.ns.cloudflare.com(these will differ per account)
Nameserver propagation takes up to 24 hours but is usually under an hour.
DNS Configuration
In the Cloudflare DNS dashboard:
| Type | Name | Content | Proxy |
|---|---|---|---|
| A | @ | YOUR_SERVER_IP | Proxied (orange cloud) |
| A | www | YOUR_SERVER_IP | Proxied (orange cloud) |
| A | mail | MAIL_SERVER_IP | DNS only (grey cloud) |
| MX | @ | mail.example.com | DNS only |
Important: Mail servers, FTP, and SSH access records should use DNS only (grey cloud) — proxying these will break them.
Proxied records hide your actual server IP from the public, providing DDoS protection.
Using the Cloudflare API to manage DNS records:
# Get your Zone ID
curl -s -X GET "https://api.cloudflare.com/client/v4/zones?name=example.com" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" | jq '.result[0].id'
# Add an A record via API
curl -s -X POST "https://api.cloudflare.com/client/v4/zones/ZONE_ID/dns_records" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
--data '{
"type": "A",
"name": "api",
"content": "YOUR_SERVER_IP",
"ttl": 1,
"proxied": true
}'
SSL/TLS Mode Selection
Navigate to SSL/TLS > Overview and choose the appropriate mode:
- Off: No SSL — avoid unless testing
- Flexible: SSL between visitor and Cloudflare; plain HTTP to your server (not recommended for production)
- Full: SSL to your server using any certificate (including self-signed)
- Full (Strict): SSL to your server with a valid certificate — recommended for production
For Full (Strict), install a free origin certificate on your VPS:
# In Cloudflare: SSL/TLS > Origin Server > Create Certificate
# Download the certificate and key, then install:
sudo mkdir -p /etc/ssl/cloudflare
sudo nano /etc/ssl/cloudflare/origin.pem # Paste the certificate
sudo nano /etc/ssl/cloudflare/origin.key # Paste the private key
# Nginx configuration
sudo nano /etc/nginx/sites-available/example.com
server {
listen 443 ssl;
server_name example.com www.example.com;
ssl_certificate /etc/ssl/cloudflare/origin.pem;
ssl_certificate_key /etc/ssl/cloudflare/origin.key;
# Only allow Cloudflare IPs (optional, for extra security)
# See: https://www.cloudflare.com/ips/
}
Enable Always Use HTTPS under SSL/TLS > Edge Certificates to redirect all HTTP visitors to HTTPS.
Caching Rules and Cache Control
Navigate to Caching > Configuration:
- Caching Level: Standard (caches based on file extension)
- Browser Cache TTL: Respect Existing Headers (recommended), or set a custom value
- Always Online: Enable to serve cached pages if your origin is down
Set proper cache headers on your Nginx server:
# Cache static assets aggressively
location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff2|svg)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}
# Don't cache dynamic content
location ~ \.php$ {
add_header Cache-Control "no-store, no-cache, must-revalidate";
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
# ... other fastcgi params
}
Create a Cloudflare Cache Rule (under Rules > Cache Rules):
- Expression:
(http.host eq "example.com" and starts_with(http.request.uri.path, "/static/")) - Cache Status: Eligible for cache
- Edge TTL: Override — 30 days
Purge the Cloudflare cache via API:
# Purge everything
curl -X POST "https://api.cloudflare.com/client/v4/zones/ZONE_ID/purge_cache" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
--data '{"purge_everything":true}'
# Purge specific files
curl -X POST "https://api.cloudflare.com/client/v4/zones/ZONE_ID/purge_cache" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
--data '{"files":["https://example.com/style.css","https://example.com/app.js"]}'
Page Rules and Transform Rules
Page Rules (under Rules > Page Rules) — up to 3 on the free plan:
| URL Pattern | Setting | Value |
|---|---|---|
example.com/admin/* | Cache Level | Bypass |
*.example.com/* | Always Use HTTPS | On |
example.com/api/* | Cache Level | Bypass |
Redirect Rules (under Rules > Redirect Rules) — for www to non-www:
- Expression:
(http.host eq "www.example.com") - Redirect to:
https://example.com${http.request.uri.path} - Status code: 301
Web Application Firewall (WAF)
Navigate to Security > WAF:
- Enable Cloudflare Managed Ruleset — blocks common web exploits (SQLi, XSS, etc.)
- Set Security Level under Security > Settings to Medium or High
- Enable Bot Fight Mode to block automated scrapers
Create a custom WAF rule to block countries:
- Expression:
(ip.geoip.country in {"CN" "RU"}) and not (ip.geoip.country eq "US") - Action: Block (or Challenge)
Rate limiting (under Security > WAF > Rate Limiting Rules):
- Expression:
(http.request.uri.path contains "/wp-login.php") - Rate: 5 requests per 10 seconds
- Action: Block for 1 hour
Performance Optimization
# Enable in Cloudflare dashboard:
# Speed > Optimization:
# - Auto Minify: HTML, CSS, JS
# - Brotli compression: On
# - HTTP/2: Enabled by default
# - HTTP/3 (QUIC): Enable
# - Rocket Loader: On (for async JS loading)
# - Polish: Lossy (compresses images)
# - Mirage: On (lazy loading for mobile)
Enable Argo Smart Routing (paid add-on) for optimized routing through Cloudflare's network.
Check performance with:
# Verify Cloudflare is handling requests (look for CF-RAY header)
curl -I https://example.com | grep -i "cf-ray\|server\|x-cache"
Troubleshooting
Error 521 (Web server is down)
# Cloudflare cannot reach your origin — check Nginx is running
systemctl status nginx
# Verify port 80/443 are open
ufw status
Error 524 (Timeout)
# Your server is too slow to respond — increase Cloudflare's timeout
# Under Network > Network > Proxy Read Timeout (max 6000s on Enterprise)
# Alternatively, optimize your application response time
Caching dynamic content
# Add Cache-Control: no-store to sensitive pages
# Or create a Page Rule to bypass cache for /admin/* and /account/*
SSL errors with origin certificate
# Ensure Full (Strict) mode is selected in Cloudflare
# Verify certificate is not expired
openssl x509 -in /etc/ssl/cloudflare/origin.pem -noout -dates
Conclusion
Cloudflare provides a powerful CDN, WAF, and DDoS protection layer for VPS-hosted websites with minimal configuration. By selecting the correct SSL mode, configuring cache rules to match your application's needs, and enabling WAF rulesets, you significantly improve both performance and security without touching your server infrastructure.


