Receitas de integração
Ache a sua infraestrutura abaixo e cole a receita. Se ainda está escolhendo o caminho, comece por Escolha a integração que combina com a sua infraestrutura.
Escolha a sua
Seção intitulada “Escolha a sua”| Integração | Como conecta | Situação |
|---|---|---|
| NGINX | auth_request no server {} que você já tem | Disponível |
| OpenResty | A receita do NGINX, sem mudança | Disponível |
| Nginx Proxy Manager | A receita do NGINX em “Custom Nginx Configuration” | Disponível |
| ingress-nginx | Quatro annotations no seu Ingress | Disponível |
| Traefik | Middleware forwardAuth, num arquivo YAML ou em labels Docker | Disponível |
| Dokploy | A receita do Traefik no editor de Traefik do app | Disponível |
| Coolify | As labels do Traefik no seu recurso | Disponível |
| Caddy | forward_auth dentro de um bloco route | Disponível |
| Envoy | ext_authz | Em breve |
| Worker da Cloudflare | Um Worker nas rotas do seu domínio | Disponível |
| Next.js | Middleware no seu app | Disponível |
| Hospedado pelo Qlyne | O seu DNS aponta para o Qlyne | Disponível |
| Proxy do Qlyne | Um container entre o seu servidor web e o seu app | Disponível |
| Tag JavaScript | Uma linha de script nas suas páginas | Em breve |
Quando o seu servidor web pergunta ao Qlyne
Seção intitulada “Quando o seu servidor web pergunta ao Qlyne”Use quando o NGINX, o Traefik ou o Caddy já cuida do site: HTTPS, domínios, rotas. Você mantém tudo isso. O proxy do Qlyne roda ao lado em modo decisão, e o seu servidor web pergunta a ele sobre cada pedido, por sub-requisição a /__qlyne/decide.
O Qlyne responde com o veredito das suas regras. Um 200 quer dizer “segue”: o seu servidor web repassa o pedido ao app com os cabeçalhos Qlyne-*. Qualquer outra resposta (a página de desafio, um bloqueio, o redirecionamento para a sala de espera, um limite) vai ao visitante como o Qlyne mandou. Nesse modo o proxy nunca repassa nada ao seu app.
O que funciona nesse modo, e o que não
Seção intitulada “O que funciona nesse modo, e o que não”A sub-requisição não leva o corpo do pedido nem a resposta do seu app. É isso que decide o que vale:
| Funciona | Precisa do proxy do Qlyne na frente |
|---|---|
| Endereços IP bloqueados e confiáveis, países, Tor, reputação compartilhada | WAF no corpo do pedido (caminho e query continuam inspecionados) |
| Robôs de IA, robôs verificados e impostores, caminhos de armadilha | Carimbo e isca de formulário |
| Limite de requisições, sala de espera (redirecionamento), trancar um caminho num portão de acesso, as suas regras | Conferência de login e de senha vazada enviados por POST, e abrir um portão de acesso pela senha ou pelo e-mail |
| O desafio, em dois passos no NGINX (a página, depois a solução direto ao proxy) | O sensor injetado no HTML, então a nota de robô só vem de um cookie que já esteja lá |
Cabeçalhos Qlyne-* para o app, com as cópias forjadas pelo visitante removidas | O banner de consentimento, os cabeçalhos de segurança na resposta, o cache de página e o de estáticos |
A coluna da direita não quebra o seu site: essas proteções não rodam. Cada regra continua seguindo o seu plano: veja Planos.
Suba o proxy em modo decisão
Seção intitulada “Suba o proxy em modo decisão”Suba o proxy como no passo 1 de Proxy do Qlyne, com o docker-compose.yml de Conector › Configuração. Pule o passo 2 daquela página: aqui o seu servidor web pergunta ao proxy em vez de repassar a ele. Defina estas variáveis:
| Variável | Valor |
|---|---|
QLYNE_TENANT, QLYNE_CORE_URL | Já vêm no arquivo que você baixou |
QLYNE_SECRET | O segredo do conector, no .env |
QLYNE_UPSTREAM | O endereço do seu app. Continua obrigatório, mesmo sem repasse |
QLYNE_DECIDE | 1 liga /__qlyne/decide e as rotas do desafio em dois passos |
QLYNE_TRUSTED_PROXIES | O IP ou a faixa CIDR de onde o seu servidor web conecta. Vazio: só o loopback pergunta. Qualquer outro recebe 404 |
QLYNE_DECIDE_DENY_STATUS | Deixe sem definir (403). Use 401 só no ingress-nginx |
Em todas as receitas, qlyne:8080 é o proxy do Qlyne e app:3000 é o seu app. Troque os dois pelos endereços que o seu servidor web alcança.
Use quando o NGINX já fica na frente do seu app. Dentro do server {} que você tem:
location / { auth_request /__qlyne/decide; auth_request_set $qlyne_cookie $upstream_http_set_cookie; auth_request_set $qlyne_challenge_passed $upstream_http_qlyne_challenge_passed; # one per Qlyne-* your app uses add_header Set-Cookie $qlyne_cookie always; error_page 403 500 = @qlyne_page; proxy_set_header Qlyne-Challenge-Passed $qlyne_challenge_passed; proxy_pass http://app:3000; # what you already had}location = /__qlyne/decide { internal; proxy_pass http://qlyne:8080/__qlyne/decide; proxy_pass_request_body off; proxy_set_header Content-Length ""; proxy_set_header X-Original-URI $request_uri; proxy_set_header X-Original-Method $request_method; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Host $host;}location @qlyne_page { rewrite ^ /__qlyne/page? break; proxy_pass http://qlyne:8080; proxy_pass_request_body off; proxy_set_header Content-Length ""; proxy_set_header X-Original-URI $request_uri; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Host $host; proxy_set_header Cookie "$http_cookie; $qlyne_cookie";}location /__qlyne/ { proxy_pass http://qlyne:8080; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Host $host; }O que cada parte faz:
auth_request /__qlyne/decidemanda a sub-requisição, sem corpo, com o pedido original descrito emX-Original-URIeX-Original-Method.internalesconde essa rota de fora.auth_request_setguarda um cabeçalho do veredito por variável.$upstream_http_set_cookieleva o passe da sala de espera de volta ao visitante. Acrescente uma linha por cabeçalhoQlyne-*que o seu app lê, e passe adiante comproxy_set_header:Qlyne-Bot-Score,Qlyne-Bot-Reasons,Qlyne-Challenge-Passed,Qlyne-Trusted-Ip,Qlyne-Verified-Bot,Qlyne-Reputation,Qlyne-Reputation-Score,Qlyne-Rule,Qlyne-Gate-User,Qlyne-Leaked-Password,Qlyne-Decoy. Oproxy_set_headersubstitui o que o visitante mandou com o mesmo nome, então ninguém forja umQlyne-*.error_page 403 500 = @qlyne_pageé o primeiro dos dois passos. Oauth_requestdescarta o corpo da resposta e só entende2xx,401e403; qualquer outro status vira500. O@qlyne_pagepede ao proxy a/__qlyne/page, que manda a resposta de verdade para o endereço original: a página de desafio ou de bloqueio com403, ou o302, o429ou o303reais.location /__qlyne/semauth_requesté o segundo passo. A página de desafio manda a solução a/__qlyne/verifycom corpo, e a sub-requisição não leva corpo.- O
X-Forwarded-Foré igual nas três rotas, porque o desafio fica amarrado ao IP do visitante.
Os cookies do Qlyne saem com Secure, então o site precisa estar em HTTPS para o navegador guardá-los.
OpenResty
Seção intitulada “OpenResty”Use a receita do NGINX como está. O auth_request vem com o NGINX de dentro do OpenResty; não precisa de Lua.
Nginx Proxy Manager
Seção intitulada “Nginx Proxy Manager”Abra o host, aba Advanced, e cole em “Custom Nginx Configuration”. O Nginx Proxy Manager escreve o location / sozinho, então o veredito vai no nível do server e o location / herda:
auth_request /__qlyne/decide;auth_request_set $qlyne_cookie $upstream_http_set_cookie;auth_request_set $qlyne_challenge_passed $upstream_http_qlyne_challenge_passed;add_header Set-Cookie $qlyne_cookie always;error_page 403 500 = @qlyne_page;Abaixo dessas linhas, no mesmo campo, acrescente as três rotas do Qlyne da receita do NGINX (= /__qlyne/decide, @qlyne_page e /__qlyne/), com auth_request off; dentro de /__qlyne/. Troque qlyne:8080 por um endereço que o container do Nginx Proxy Manager alcança: o IP do host, ou o nome do container na mesma rede Docker.
O location / que o Nginx Proxy Manager escreve tem proxy_set_header próprios, que anulam os do nível do server. Para mandar os Qlyne-* ao app, crie a localização / em Custom Locations, apontando para o app, e ponha as linhas proxy_set_header Qlyne-... no campo de configuração dela.
ingress-nginx
Seção intitulada “ingress-nginx”Acrescente estas annotations ao Ingress do seu app:
nginx.ingress.kubernetes.io/auth-url: "http://qlyne.<namespace>.svc.cluster.local:8080/__qlyne/decide"nginx.ingress.kubernetes.io/auth-method: "GET"nginx.ingress.kubernetes.io/auth-response-headers: "Qlyne-Challenge-Passed, Qlyne-Bot-Score, Qlyne-Trusted-Ip"nginx.ingress.kubernetes.io/auth-signin: "https://$host/__qlyne/page?to=$escaped_request_uri"Mais três coisas:
- Suba o proxy com
QLYNE_DECIDE_DENY_STATUS=401. O ingress-nginx só manda o visitante aoauth-signinnum401, então todo veredito que não segue sai de/__qlyne/decidecomo401. Oauth-signinleva o navegador a/__qlyne/page, que responde com o status de verdade: a página de desafio ou de bloqueio, o302da sala de espera, o429. - Ponha em
QLYNE_TRUSTED_PROXIESo CIDR dos pods do controller. - Crie um segundo Ingress para o caminho
/__qlyne/, apontando ao Service do proxy do Qlyne, sem as annotations de auth.
O ingress-nginx descreve o pedido original em X-Original-URL, e o proxy tira dele o caminho, a query, o host e o esquema. Não precisa de auth-snippet.
Traefik
Seção intitulada “Traefik”Use com o Traefik v3, pelo provider de arquivo ou pelo provider Docker. Duas peças fazem funcionar: o middleware forwardAuth no router do seu app, e um router para /__qlyne/ sem o middleware, com prioridade maior. O segundo leva a solução do desafio, que tem corpo.
Num arquivo de configuração dinâmica (troque o host, a porta do app e os cookies de passe):
http: middlewares: qlyne: forwardAuth: address: "http://qlyne:8080/__qlyne/decide" trustForwardHeader: true authResponseHeadersRegex: "^Qlyne-" addAuthCookiesToResponse: [qlyne_pass_cap] # one qlyne_pass_<event_key> per queue event routers: qlyne-direct: rule: "Host(`loja.exemplo.com`) && PathPrefix(`/__qlyne/`)" priority: 1000 service: qlyne app: rule: "Host(`loja.exemplo.com`)" middlewares: [qlyne] service: app services: qlyne: { loadBalancer: { servers: [{ url: "http://qlyne:8080" }] } } app: { loadBalancer: { servers: [{ url: "http://app:3000" }] } }Os seus routers de verdade já têm entryPoints e tls; dê ao qlyne-direct os mesmos do app. O addAuthCookiesToResponse lista os cookies que o 200 precisa entregar ao visitante: um qlyne_pass_<event_key> por fila da sala de espera. Os cookies do desafio e da liberação não precisam de nada, porque o Traefik repassa essas respostas inteiras.
Em labels Docker, no serviço do seu app:
- traefik.http.routers.app.middlewares=qlyne- traefik.http.middlewares.qlyne.forwardauth.address=http://qlyne:8080/__qlyne/decide- traefik.http.middlewares.qlyne.forwardauth.trustforwardheader=true- traefik.http.middlewares.qlyne.forwardauth.authresponseheadersregex=^Qlyne-- traefik.http.middlewares.qlyne.forwardauth.addauthcookiestoresponse=qlyne_pass_capE no serviço qlyne, que roda com QLYNE_DECIDE=1 e QLYNE_TRUSTED_PROXIES com a faixa da rede Docker do Traefik:
- traefik.http.routers.qlyne-direct.rule=Host(`loja.exemplo.com`) && PathPrefix(`/__qlyne/`)- traefik.http.routers.qlyne-direct.priority=1000- traefik.http.services.qlyne.loadbalancer.server.port=8080O Traefik, o seu app e o qlyne precisam estar na mesma rede Docker, porque o middleware e o serviço são achados pelo nome. Ponha no qlyne-direct também as labels de entrypoints e tls.certresolver que os seus routers já usam.
Dokploy
Seção intitulada “Dokploy”O domínio que você cadastra num app vira um arquivo de Traefik próprio, que aparece em Advanced, Traefik. Acrescente ali o middleware qlyne, ponha middlewares: [qlyne] no router que o Dokploy escreveu e crie o router qlyne-direct com os mesmos entryPoints e tls desse router.
Suba o qlyne como um serviço Compose no mesmo projeto, ou como app Docker, na rede dokploy-network. O QLYNE_TRUSTED_PROXIES é a faixa dessa rede (docker network inspect dokploy-network). Num projeto Compose, as labels acima vão direto no arquivo.
Coolify
Seção intitulada “Coolify”As labels que o Coolify escreve ficam no editor de labels do recurso. Acrescente as do middleware no serviço do seu app. Suba o qlyne como um recurso Docker Compose na rede coolify, com as labels do router qlyne-direct.
Use com o Caddy 2. A receita inteira:
loja.exemplo.com { route { reverse_proxy /__qlyne/* qlyne:8080 forward_auth qlyne:8080 { uri /__qlyne/decide copy_headers Qlyne-Bot-Score Qlyne-Bot-Reasons Qlyne-Challenge-Passed Qlyne-Trusted-Ip Qlyne-Verified-Bot Qlyne-Reputation Qlyne-Reputation-Score Qlyne-Rule Qlyne-Gate-User Qlyne-Leaked-Password Qlyne-Decoy } @pass expression `{http.reverse_proxy.header.Set-Cookie} != ""` header @pass +Set-Cookie {http.reverse_proxy.header.Set-Cookie} reverse_proxy app:3000 }}Por que cada linha está ali:
routemantém a ordem escrita. Fora dele, o Caddy reordena as diretivas e oforward_authrodaria antes da rota direta.reverse_proxy /__qlyne/*vem antes doforward_auth, porque a solução do desafio chega a/__qlyne/verifycom corpo.copy_headersnomeia cada cabeçalho. O curingaQlyne-*não copia nada. Com os nomes, cada um chega ao app com o valor do veredito, e a cópia mandada pelo visitante é removida.header @pass +Set-Cookieentrega o passe da sala de espera ao visitante. Oforward_authsozinho só o poria no pedido que o seu app recebe.
No proxy, ponha em QLYNE_TRUSTED_PROXIES o IP ou a faixa do Caddy. Com domínio, o Caddy serve HTTPS sozinho, que os cookies Secure do Qlyne exigem.
Em breve, pelo filtro ext_authz do Envoy.
Os outros caminhos
Seção intitulada “Os outros caminhos”| Caminho | Quando usar | O que cobre |
|---|---|---|
| Worker da Cloudflare | O seu domínio está na Cloudflare | Quase tudo (detalhes na página do Worker); roda na borda da Cloudflare |
| Next.js | Um app Next.js, na Vercel ou em outro lugar | O que não depende da resposta do app |
| Hospedado pelo Qlyne | Hospedagem compartilhada, ou nenhum lugar para rodar algo | Tudo, com HTTPS; o tráfego passa pelo Qlyne |
| Proxy do Qlyne | O seu próprio servidor, com o proxy entre o servidor web e o app | Tudo, a coluna da direita da tabela acima inclusive |
Tag JavaScript
Seção intitulada “Tag JavaScript”Em breve: uma linha de script nas suas páginas que dá nota a cada visitante. Com o modo decisão, ela traz de volta a nota de robô que a sub-requisição não consegue injetar.
Confira se funciona
Seção intitulada “Confira se funciona”Antes, mude o site para “Aplicar” em Conector › Configuração. Em “Só observando”, o Qlyne conta o que faria e deixa todo mundo passar. Depois, trocando loja.exemplo.com pelo seu site:
# 1. De um endereço na sua lista de bloqueados: 403curl -s -o /dev/null -w '%{http_code}\n' https://loja.exemplo.com/produtos
# 2. Uma rota com desafio, sem cookie: a página de desafiocurl -s https://loja.exemplo.com/checkout | grep -o '<title>[^<]*'
# 3. Uma página sem regra: 200 do seu appcurl -s -o /dev/null -w '%{http_code}\n' https://loja.exemplo.com/produtosO primeiro precisa de uma máquina cujo IP esteja em Regras de IP, na lista de bloqueados. O segundo imprime <title>Checking your browser para uma rota em “Rotas com desafio” (Pro; veja Bot Management); o curl não manda idioma, então a página sai em inglês. Abra essa rota no navegador também: a página se resolve sozinha e abre a sua.
Problemas comuns
Seção intitulada “Problemas comuns”Todo visitante tem o mesmo IP, ou o IP errado
Seção intitulada “Todo visitante tem o mesmo IP, ou o IP errado”O limite de requisições pega todo mundo de uma vez, ou a lista de bloqueados nunca casa. Um CDN ou balanceador fica na frente do seu servidor web, então o último item do X-Forwarded-For é o endereço dele.
Ponha as faixas dele em QLYNE_TRUSTED_PROXIES, junto com a do seu servidor web. O proxy pula esses itens da direita para a esquerda e julga o primeiro endereço fora da lista. O Traefik e o Caddy também precisam confiar nesse CDN, senão descartam o cabeçalho: forwardedHeaders.trustedIPs no entry point do Traefik, trusted_proxies no Caddy. No NGINX, set_real_ip_from com real_ip_header continua valendo; nunca com 0.0.0.0/0.
A página de desafio volta sempre
Seção intitulada “A página de desafio volta sempre”A solução não chega ao proxy. O /__qlyne/ precisa ir direto ao proxy do Qlyne, fora da sub-requisição: no NGINX, location /__qlyne/ sem auth_request (auth_request off; no Nginx Proxy Manager); no Traefik, o router qlyne-direct com prioridade 1000 e sem middleware; no Caddy, o reverse_proxy /__qlyne/* antes do forward_auth; no ingress-nginx, o segundo Ingress. Sem isso, a solução recebe 403 com DIRECT_ROUTE_REQUIRED.
Outras duas causas: no NGINX, um X-Forwarded-For diferente numa das três rotas (o desafio fica amarrado ao IP); e um site em HTTP puro, em que o navegador descarta os cookies Secure do Qlyne.
A sala de espera ou um limite responde 500 no NGINX
Seção intitulada “A sala de espera ou um limite responde 500 no NGINX”O auth_request só repassa 2xx, 401 e 403. O 302 da sala de espera, o 429 e o 303 do portão viram 500, e o 403 do desafio chega vazio. Acrescente error_page 403 500 = @qlyne_page; e a rota @qlyne_page da receita. No ingress-nginx, a correção é QLYNE_DECIDE_DENY_STATUS=401 com o auth-signin.
/__qlyne/decide responde 404
Seção intitulada “/__qlyne/decide responde 404”O proxy só responde a endereços em QLYNE_TRUSTED_PROXIES, ou ao loopback quando a lista está vazia. Confira se o endereço do seu servidor web está na lista e se QLYNE_DECIDE=1 está definido.