When you run your own infrastructure — whether it is a single reverse proxy in a colocation facility or a fleet of servers across multiple sites — you face a fundamental problem: your public-facing IP addresses are exposed to the entire internet. Every port scan, every credential-stuffing bot, every script kiddie with a copy of Nuclei is pointed at your front door. Cloudflare, used correctly, acts as a security perimeter that absorbs the vast majority of that abuse before it ever touches your infrastructure.
This guide walks through a practical, layered deployment of Cloudflare in front of self-hosted infrastructure. We assume you have a bastion/reverse-proxy server (Apache or nginx) accepting traffic from the internet and forwarding it to internal services. The goal is to make Cloudflare the only path to your public services.
DNS Management: The Foundation
Everything starts with DNS. Move your authoritative nameservers to Cloudflare, then configure your records with the proxy enabled (the orange cloud icon in the dashboard).
A proxied record means Cloudflare’s edge network answers DNS queries with Cloudflare’s own IPs, not yours. Your origin IP is hidden. An unproxied (grey cloud) record exposes your real IP and bypasses all Cloudflare protections.
Practical rules:
- Proxy everything public. Web apps, APIs, documentation portals — all orange cloud.
- Grey-cloud SSH and internal services. You cannot proxy arbitrary TCP through Cloudflare’s free/pro tiers. For SSH, use a dedicated hostname like
bastion.example-corp.comwith a grey-cloud A record, and restrict inbound SSH at your firewall to known IPs. - Use AAAA records for IPv6. If your origin supports dual-stack, add both A and AAAA records. Cloudflare handles the v4/v6 translation at its edge, so even if your origin is v4-only, Cloudflare can serve v6 clients.
# Example DNS records (Cloudflare dashboard or API)
# Type Name Content Proxy
A example-corp.com 203.0.113.10 Proxied
AAAA example-corp.com 2001:db8::10 Proxied
A api 203.0.113.10 Proxied
CNAME docs example-corp.com Proxied
A bastion 203.0.113.10 DNS Only
API-Driven DNS Management
For automation (CI/CD pipelines, dynamic DNS, infrastructure-as-code), use the Cloudflare API:
# Create a proxied A record
curl -X POST "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/dns_records"
-H "Authorization: Bearer ${CF_API_TOKEN}"
-H "Content-Type: application/json"
--data '{
"type": "A",
"name": "app.example-corp.com",
"content": "203.0.113.10",
"ttl": 1,
"proxied": true
}'
# List all records for audit
curl -s "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/dns_records"
-H "Authorization: Bearer ${CF_API_TOKEN}" | jq '.result[] | {name, type, content, proxied}'
Create API tokens with the minimum required permissions. A token for DNS automation needs only Zone:DNS:Edit on the specific zone — never use your Global API Key for automation.
SSL/TLS: Full (Strict) or Nothing
Cloudflare’s SSL/TLS mode controls how it connects to your origin. The options matter enormously:
- Flexible: Cloudflare terminates TLS at its edge and connects to your origin over plain HTTP. This is insecure — traffic between Cloudflare and your server is unencrypted. Never use this in production.
- Full: Cloudflare connects to your origin over HTTPS but does not validate the certificate. This protects against passive eavesdropping but not active MITM on your network path.
- Full (Strict): Cloudflare connects over HTTPS and validates that your origin certificate is trusted — either a public CA cert or a Cloudflare Origin CA certificate. This is the correct setting.
Generate a Cloudflare Origin CA certificate (valid for up to 15 years, trusted only by Cloudflare’s edge) and install it on your reverse proxy:
# Apache vhost on proxy01
<VirtualHost :443>
ServerName app.example-corp.com
SSLEngine on
SSLCertificateFile /etc/ssl/cloudflare/origin.pem
SSLCertificateKeyFile /etc/ssl/cloudflare/origin-key.pem
ProxyPass / http://10.0.70.20:8080/
ProxyPassReverse / http://10.0.70.20:8080/
</VirtualHost>
With Full (Strict) and an Origin CA cert, you get end-to-end encryption without paying for or managing public CA certificates for every internal service.
WAF Rules: Blocking Common Attacks
Cloudflare’s Web Application Firewall provides managed rulesets (OWASP Core Rule Set, Cloudflare Managed Rules) plus custom firewall rules you write yourself.
Enable the managed rulesets first — they catch SQLi, XSS, RCE, and path traversal with minimal false positives. Then add custom rules for your specific environment:
# Block path traversal attempts on API endpoints
# Cloudflare Firewall Rule (wirefilter syntax)
(http.request.uri.path contains "../" and http.host eq "api.example-corp.com")
Action: Block
# Block requests with suspicious user agents
(http.user_agent contains "sqlmap" or http.user_agent contains "nikto" or http.user_agent contains "masscan")
Action: Block
# Restrict admin panels to known IP ranges
(http.request.uri.path matches "^/admin" and not ip.src in {198.51.100.0/24 2001:db8:1::/48})
Action: Block
# Challenge requests from high-risk countries to sensitive endpoints
(http.request.uri.path matches "^/api/v1/auth" and ip.geoip.country in {"CN" "RU" "KP"})
Action: Managed Challenge
Rate Limiting
Rate limiting prevents credential stuffing and API abuse. Configure it on authentication endpoints and expensive API calls:
# Rate limit: 5 login attempts per minute per IP
URL pattern: api.example-corp.com/v1/auth/login
Threshold: 5 requests per 60 seconds
Mitigation: Block for 600 seconds
Counting: Per IP
# Rate limit: 100 API requests per minute per IP
URL pattern: api.example-corp.com/v1/
Threshold: 100 requests per 60 seconds
Mitigation: Block for 60 seconds
DDoS Protection
Cloudflare provides automatic L3/L4 DDoS mitigation on all plans. For L7 (application layer) attacks, you get more granular control:
- Bot Fight Mode: Blocks known bad bots. Enable in Security > Bots.
- Under Attack Mode: Presents a JavaScript challenge to all visitors. Use this only during active attacks — it degrades user experience.
- Custom DDoS rules: Override default sensitivity for specific endpoints.
For self-hosted infrastructure, the most important thing is ensuring your origin IP is never exposed. If attackers discover your real IP, they bypass Cloudflare entirely. Audit your DNS history (tools like SecurityTrails archive old records), check that your origin firewall only accepts traffic from Cloudflare’s published IP ranges, and never leak your IP in email headers or debug responses.
# iptables rules on proxy01 — only accept HTTPS from Cloudflare
# Cloudflare IPv4 ranges (check https://www.cloudflare.com/ips-v4 for current list)
for ip in 173.245.48.0/20 103.21.244.0/22 103.22.200.0/22 103.31.4.0/22
141.101.64.0/18 108.162.192.0/18 190.93.240.0/20 188.114.96.0/20
197.234.240.0/22 198.41.128.0/17 162.158.0.0/15 104.16.0.0/13
104.24.0.0/14 172.64.0.0/13 131.0.72.0/22; do
iptables -A INPUT -p tcp --dport 443 -s $ip -j ACCEPT
done
iptables -A INPUT -p tcp --dport 443 -j DROP
Security Headers via Transform Rules
Rather than configuring security headers on every origin server, use Cloudflare Transform Rules to inject them at the edge:
# HTTP Response Header Modification Rule
# Match: All requests
# Action: Set headers
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=()
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'
This guarantees consistent headers across all services regardless of how the backend is configured.
Cloudflare Access: Zero Trust for Admin Panels
Cloudflare Access puts an authentication layer in front of any proxied hostname or path. Instead of exposing admin panels to the internet and relying solely on application-level authentication, you require identity verification at the edge.
Configure an Access Application:
- Define the application domain:
admin.example-corp.comorexample-corp.com/admin/ - Create an Access Policy: Allow only users from your identity provider (Okta, Azure AD, GitHub, or one-time PIN via email)
- Optionally require device posture checks (Warp client installed, OS version, disk encryption)
Users who are not authenticated see a Cloudflare login page. They never reach your origin. This is defense in depth — even if your admin panel has a zero-day, unauthenticated attackers cannot reach it.
Page Rules for Caching Strategy
Separate your caching strategy for static and dynamic content:
# Cache static assets aggressively
URL: example-corp.com/static/
Cache Level: Cache Everything
Edge Cache TTL: 1 month
Browser Cache TTL: 1 week
# Bypass cache for API and authenticated content
URL: api.example-corp.com/
Cache Level: Bypass
# Bypass cache for admin panels
URL: example-corp.com/admin/*
Cache Level: Bypass
Security Level: High
Putting It All Together
The architecture looks like this: Internet traffic hits Cloudflare’s edge, where DNS resolves to Cloudflare IPs. The WAF inspects the request. Rate limiting checks are applied. DDoS mitigation runs. If the request passes all checks, Cloudflare connects to your origin over TLS (Full Strict), injecting security headers on the response. Your origin firewall only accepts connections from Cloudflare’s IP ranges.
This gives you enterprise-grade perimeter security for self-hosted infrastructure at a fraction of the cost and complexity of running your own WAF, DDoS scrubbing center, and CDN. The key is using every layer — do not just orange-cloud your DNS and call it done.
