Zum Inhalt springen

Qlyne for Cloudflare

Dieser Inhalt ist noch nicht in deiner Sprache verfügbar.

A connector that sits in front of your site, inside your own Cloudflare account, and applies the rules you set in the Qlyne dashboard:

  • a waiting room on the pages you pick (/tickets/*, /checkout);
  • a cap on how many people are on the site at once: visitors go straight in while there is room and wait in line when it is full;
  • its own challenge (invisible proof-of-work, no Google or Cloudflare Turnstile) on the pages you pick, plus an “under attack” mode that challenges every page view;
  • rate limits per page, counted per IP (IPv6 by its /64) or per API key, token or session;
  • blocked and trusted IP addresses, and a rule for Tor exit nodes (challenge or block);
  • AI crawlers blocked by category (training, AI search, assistants), in your robots.txt too;
  • form protection with no captcha: an invisible trap field and a minimum fill time;
  • browsers driven by automation tools (Selenium, Puppeteer, Playwright) refused at the challenge;
  • an “observe only” mode that records what would be blocked without blocking anyone;
  • counters in the dashboard for each of these.

The connector does not call Qlyne on every request. It keeps your rules in memory for 60 seconds, and the waiting room pass and the challenge clearance are signed with a secret that only your connector and Qlyne know, so it checks them on its own. With a cap on people at once, it also asks Qlyne for a slot when someone without a pass arrives. If Qlyne goes down, the connector lets traffic through: protection may fail, your site does not.

This is HTTP-layer (L7) protection. Volumetric network attacks are Cloudflare’s job.

  • The Qlyne free plan covers observe mode, IP addresses, AI crawlers and rate limits. The waiting room, the cap on people at once, the challenge, under attack mode, forms and Tor need the Pro plan.
  • Your site must go through Cloudflare (DNS record proxied, orange cloud).
  • The connector is a Cloudflare Worker. The Workers free plan allows 100,000 requests a day and bursts of up to 1,000 a minute, and every request on the Worker’s routes counts. Route only the pages that need protection, not images or scripts. Busier sites need the Workers paid plan. When the daily limit runs out, each route does what you set for it in Cloudflare: go to your site without the Worker (fail open) or return error 1027 (fail closed).
  1. Open the signup page and pick an account ID, your site’s name and your e-mail.
  2. Open the confirmation link from your e-mail and click “Activate and generate my key”. Save the API key: it is shown only once.
  3. On the same page, click “Set my password” and choose your dashboard password. The link lasts 60 minutes; after that, use “Forgot your password?” on the login page.

Log in and open your site. Each item below is in the site menu:

  1. In Connector › Configuration, click “Generate secret” and save it. It is shown only once.
  2. Add the pages. * matches anything: /checkout* covers /checkout and /checkout/pay.
    • Bot Management › Configuration, “Challenged routes”: pages bots go after, such as login and checkout.
    • Waiting Room › Configuration, “Routes on your site”: the page and the queue it sends people to. Queues, the cap on people at once and the pass are on their own page: Waiting Room.
    • WAF & Firewall › Configuration, “Rate limits”: Strict (10 per minute), Normal (60) or Loose (300), counted per IP by default. On an API, or anywhere many people share one address (mobile carriers, offices), count per header (Authorization, X-API-Key) or per session cookie instead. Requests without that header or cookie are counted per IP, and one IP never goes above 10 times the limit, so making up a new key on every request does not get around it.
    • Account Protection › Configuration, protected forms: the page with the form and the address it posts to. Use it on forms people type into, such as contact, signup and comments; a one-click form (add to cart) is often sent within 2 seconds and would be refused.
  3. Optionally, list blocked and trusted IP addresses (WAF & Firewall › IP rules), pick a rule for Tor exit nodes (WAF & Firewall › Configuration) and the AI crawler categories to block (Bot Management › Configuration). Trusted addresses (your office, uptime monitors, partners calling your API) skip every rule.
  4. Leave the mode in Connector › Configuration on “Observe only” for now.

Under Connector › Configuration, “Install on Cloudflare”, click Download connector. The file already carries your account ID and the Qlyne server address.

From the Cloudflare dashboard, no terminal:

  1. Workers & Pages, Create, Worker: deploy the “Hello World” example.
  2. Edit code, replace everything with the downloaded connector, Deploy.
  3. Settings, Variables and Secrets: add a Secret named QLYNE_SECRET with your connector secret.
  4. Settings, Domains & Routes: add a route for each page to protect, for example shop.example.com/checkout*.

This covers the waiting room, the challenge and under attack mode. Rate limits need Wrangler, because Cloudflare does not let you add them in the dashboard (download wrangler.toml again after updating the connector: version 0.6.0 adds the per-IP ceiling for limits counted per header or cookie):

  1. Also click Download wrangler.toml and put both files in one folder.
  2. Set your routes in wrangler.toml.
  3. Run:
Terminal window
npx wrangler login
npx wrangler secret put QLYNE_SECRET
npx wrangler deploy

Visit a protected page, then check the last 24 hours in the site Overview. Many “Would challenge” on ordinary pages usually means a route is too broad; many “Would rate limit” calls for a looser tier. When the numbers make sense, switch the mode to “Enforce” in Connector › Configuration.

During an attack, the “Under attack” button challenges every page view without a clearance cookie (the connector picks it up within a minute). API calls are not challenged, so apps and integrations keep working.

The queue by rate, the cap on how many people are on the site at once and the pass are set the same way on every connector: see Waiting Room.

For each request on the connector’s routes, in this order:

  1. Someone coming back from the waiting room with ?qlyne_pass=: the connector checks the pass, keeps it in a cookie for that event and redirects to the same address without the parameter. An invalid pass shows an error page instead of sending the person back to the queue, so a wrong secret never turns into a redirect loop.
  2. Trusted IP address: goes to your site with no rule applied.
  3. Path behind an access gate (Pro), without a gate session: the “Restricted access” page, or 401 with {"code": "GATE_REQUIRED"} for API calls. The gate holds in observe mode too. See Access.
  4. Address the scanner trap caught, on this connector or another one of the site: 403 on every route for a while (an “Access blocked” page, or {"code": "ACCESS_BLOCKED"} for API calls).
  5. Blocked IP address, or Tor exit node with the “block” rule: 403, with the same page or {"code": "ACCESS_BLOCKED"}.
  6. Address on the shared reputation list, with “Block” (Pro): 403, with the same page or {"code": "ACCESS_BLOCKED"}. With “Challenge”, its page views get the challenge in step 13.
  7. A scanner trap path: 404, and the address is blocked as in step 4. Googlebot and Bingbot from their published ranges are not caught. See Bot Management.
  8. Your rules (Pro), in order: “Block” gets 403; “Let through” goes to your site with no other rule applied; “Challenge” gets the challenge in step 13; “Only log it” is counted and the request goes on.
  9. Request matching a managed rule (WAF) in “Block” mode: 403, with the same “Access blocked” page or {"code": "ACCESS_BLOCKED"}. In “Observe only” it goes on and is counted.
  10. With the bot score on, a medium or high score gets the action you chose for it (Pro): slowed down, challenged, 403 or the decoy page. A form or API call to a route that needs the score (Pro), from a browser that has not run the script, gets 403 with {"code": "SENSOR_REQUIRED"}.
  11. AI crawler from a blocked category, by user agent: 403. Your /robots.txt is served with a Disallow: / group for those crawlers added at the end.
  12. Page with a rate limit, over the limit: 429.
  13. Challenged page (or a rule with “Challenge”, under attack mode, a Tor exit node with the “challenge” rule or a reputation-listed address with “Challenge”; the last three on page views only), no clearance cookie: the challenge page. API calls get 403 with {"code": "CHALLENGE_REQUIRED"}. Googlebot and Bingbot pass when their IP is in the ranges Google and Bing publish. A browser controlled by automation software does not get the clearance. The challenge comes before the waiting room, so a bot that fails it never takes a place in line or a slot on the site.
  14. Protected form: a submission with the decoy field filled, or sent less than 2 seconds after the page loaded, gets 403 (a “Form not sent” page, or {"code": "FORM_REJECTED"}). See Account Protection.
  15. Login address (Pro): over the tries per account, 429; a leaked password goes on to your app with Qlyne-Leaked-Password: 1. See Account Protection.
  16. Page with a waiting room, event active and not over, no valid pass: redirect to the waiting room. API calls (not asking for HTML) get 403 with {"code": "QUEUE_REQUIRED", "waiting_room_url": ...}. With a cap on people at once, the connector first asks Qlyne for a slot; with one, the request goes to your site and the pass is set right away.
  17. Everything else goes to your site.

Static files (scripts, styles, images, fonts) get neither the waiting room, the challenge, the form check nor the login check; blocked addresses, AI crawlers and rate limits still apply.

To block AI crawlers, the connector has to run on your whole site (a route like example.com/*), robots.txt included: crawlers fetch every page. On the Workers free plan that uses more of the daily allowance.

Cookies, all HttpOnly; Secure; SameSite=Lax:

CookieWhatLifetime
qlyne_pass_<event>waiting room pass, signed by Qlynethe event’s access token TTL (“Free a slot after” when the queue caps people at once), renewed while the person keeps browsing, up to 2 hours after it was issued
qlyne_clrchallenge clearance, tied to the IP (the /64 for IPv6) and the browser“Clearance” in the dashboard (30 minutes by default)
qlyne_bsbot score, signed by the connector and tied to the IP and the browser (with the bot score on)30 minutes

A password or a sign-in link by e-mail in front of a path such as /admin* has its own page: Access.

Leaked passwords, tries per account and forms that refuse robots are on their own page: Account Protection.

Managed rules, IP lists and rate limits are set the same way on every connector: see WAF & Firewall. On the Worker, the managed rules read form and JSON bodies up to 16 KB, only with a declared size.

The bot score and what each score band gets, the challenge settings, verified bots, AI crawlers, the scanner trap, Tor and shared reputation are on Bot Management. On this connector, everything there works except impostor detection and the challenge for browsers that never ran the script.

Your own rules (block, challenge, let through or only log, by path, country, network, IP and more) are in WAF & Firewall. On the Worker, country and network come from Cloudflare.

Security headers and their grade, the Content Security Policy with its violation list and the consent banner are on Page Shield. On this connector, violations are reported through report-uri only, the banner holds scripts but not image pixels or iframes, and there is no page cache.

Requests that reach your site carry headers your code can use (turn them off in Connector › Configuration, “Signals to your app”):

HeaderValue
Qlyne-CountryTwo-letter country code
Qlyne-ASNThe visitor’s network number
Qlyne-Verified-Botgooglebot or bingbot, confirmed by IP
Qlyne-Challenge-Passed1 when the visitor solved the challenge, on any page
Qlyne-Trusted-IP1 for an address in your trusted list
Qlyne-RuleIn observe mode, what would have happened, like would_challenge=/checkout*, would_rate_limit=/api/*
Qlyne-Leaked-Password1 on a login whose password is in a known breach (login protection, sent even with the other signals off)
Qlyne-Gate-UserThe e-mail of who signed in at an access gate (sent even with the other signals off)
Qlyne-Bot-ScoreWith the bot score on, the visitor’s score from 0 to 100
Qlyne-Bot-ReasonsWhat raised the score, like automation,no_interaction
Qlyne-Reputation1 for an address other Qlyne accounts saw attacking (shared reputation)
Qlyne-JA4The TLS fingerprint, only on Cloudflare plans with Bot Management (Enterprise)

Headers with these names sent by the visitor are always removed. Trust them only if your origin accepts only Cloudflare’s IP ranges; otherwise someone can reach the origin directly and send the headers themselves.

Every rule of a site is also a YAML (or JSON) file you can keep in git, authenticated with the account API key from Plan and API key (one key for every site of the account; the site goes in X-Tenant-ID):

Terminal window
# download
curl -H "Authorization: Bearer $QLYNE_API_KEY" -H "X-Tenant-ID: your-account" \
"https://app.qlyne.com/api/protection?format=yaml" > qlyne.yaml
# check without saving, then apply (drop ?dry_run=1)
curl -X PUT -H "Authorization: Bearer $QLYNE_API_KEY" -H "X-Tenant-ID: your-account" \
-H "Content-Type: application/yaml" --data-binary @qlyne.yaml \
"https://app.qlyne.com/api/protection?dry_run=1"

PUT replaces the rules: a section missing from the file goes back to its default, and a list in the file replaces the whole list. Errors come back as 422 with the field that failed (challenge.routes, rules.0.conditions.1.values), and an unknown setting is an error too, so a typo does not pass silently. In a CI, run the ?dry_run=1 call on pull requests and the real one on merge.

GET /api/metrics, with the same key, returns the Prometheus metrics of your account only (decisions by action, queue sizes and the rest), for your own Grafana. The scrape config is under Connector › Configuration, “Rules as code”.

  • The limits of the challenge, the bot score and AI crawler detection are on Bot Management.
  • The pass is not tied to the browser: a copied pass cookie works elsewhere until it expires (at most 2 hours after it was issued). With a cap on people at once, everyone using the copy counts as one person.
  • The cap on people at once can be filled by someone with many IP addresses. A challenge on the same pages makes each slot cost a proof-of-work.
  • Form protection has limits, such as a bot that waits and leaves the decoy empty: see Account Protection.
MessageMeaning
the config is not signed by the Qlyne serverThe connector file or QLYNE_CORE_URL does not match the Qlyne server. Download the connector again; nothing is blocked meanwhile.
the Qlyne server refused the config (401)QLYNE_SECRET is not the current connector secret. Nothing is blocked until you fix it.
QLYNE_SECRET is not set, or this is not the connector file downloaded from the dashboardAdd the secret, or download the connector again. Nothing is blocked.
waiting room pass refusedSomeone came back with an invalid or expired pass. If it happens to everyone, check the secret.
could not reach the Qlyne serverThe connector keeps the last rules it had; with none, it lets traffic through.
could not reach the Qlyne server for an admission, the Qlyne server answered ... to an admission requestQlyne did not give a slot in time. The connector lets visitors in and asks again 10 seconds later.