Deploying Behind Cloudflare
This is not about the docs site
This page covers putting your self-hosted Ragz instance behind
Cloudflare. Ragz is a Docker Compose stack (FastAPI + Celery + Postgres +
Qdrant + Redis + MinIO) that you run on your own infrastructure — it does
not run on Cloudflare Workers. (This documentation site,
ragz-portal, is a separate Next.js app that happens to deploy to Workers
— that's an unrelated piece of the project.)
Cloudflare sits in front of your Ragz deployment the same way it would sit in front of any self-hosted web app: as a reverse proxy at the edge. You still run the production Docker Compose stack yourself; Cloudflare gives you TLS, DDoS protection, WAF, and edge rate limiting without opening inbound ports on your host.
Option A — Cloudflare Tunnel (recommended for most self-hosted setups)
cloudflared runs alongside your Ragz stack and makes an outbound
connection to Cloudflare's network. You never open an inbound port on your
firewall — there's nothing for an attacker to scan for.
# One-time: authenticate and create a tunnel
cloudflared tunnel login
cloudflared tunnel create ragz
# Route your hostname to the tunnel
cloudflared tunnel route dns ragz ragz.yourdomain.comPoint the tunnel at your reverse proxy (the same one described in Production — nginx/Caddy/Traefik in front of the FastAPI backend), not at the backend port directly:
# ~/.cloudflared/config.yml
tunnel: ragz
credentials-file: /root/.cloudflared/<tunnel-id>.json
ingress:
- hostname: ragz.yourdomain.com
service: http://127.0.0.1:443 # your reverse proxy, terminating TLS
- service: http_status:404cloudflared tunnel run ragzAdd cloudflared as another service in deploy/compose.yaml (or run it as a
systemd unit alongside Docker) so it starts with the rest of the stack.
Option B — DNS + proxied (orange-cloud)
If you'd rather keep a public IP and let Cloudflare proxy in front of it conventionally:
- Point an
A/AAAArecord at your host's public IP. - Enable the proxy (orange cloud) on that record.
- Set the Cloudflare SSL/TLS mode to Full (strict) — Cloudflare terminates TLS to the visitor, and re-encrypts to your reverse proxy, which must present a valid certificate (Let's Encrypt is fine).
- Firewall your host so only Cloudflare's IP ranges can reach ports 80/443.
This gets you the same edge protection as the tunnel, but you're still managing an open inbound port and keeping Cloudflare's IP list current in your firewall rules — the tunnel avoids both.
Real client IP, again
Rate limiting on the Ragz auth and chat endpoints depends on seeing the
actual client IP, not Cloudflare's edge IP. Cloudflare forwards the original
visitor IP in the CF-Connecting-IP header (and populates
X-Forwarded-For); make sure your reverse proxy passes that through to the
backend rather than overwriting it with its own address. This is the same
concern as in Production — Cloudflare just adds
one more hop for it to survive.
WAF and edge rate limiting
Once you're proxied through Cloudflare, you get a second, independent layer of protection in front of your own:
- WAF managed rules to block common exploit patterns before they reach your host.
- Rate limiting rules at the edge — a coarse first line of defense on
/api/auth/*and/api/chat/*paths, complementing (not replacing) the application-level rate limiting already built into the Ragz backend. - Bot Fight Mode / Super Bot Fight Mode if you're exposing sign-up flows publicly.
Tunnel vs. DNS-proxied
Prefer the Tunnel for anything you can (no exposed port, no firewall list to maintain). Fall back to DNS + proxied only when something in your setup genuinely needs a routable public IP.