Integrationen
Forward Auth für nginx, Apache und HAProxy
Ein kleiner Container, den nginx, Nginx Proxy Manager, Apache, HAProxy, Traefik oder Caddy zu jeder Anfrage befragt.
Installation
- 1Legen Sie eine Forward-Auth-Website im Dashboard an und kopieren Sie ihre Site-ID.
- 2Starten Sie das Gate im Docker-Netzwerk Ihres Proxys mit Ihrem API-Schlüssel und der Site-ID. Veröffentlichen Sie seinen Port nicht.
- 3Fügen Sie das Snippet für Ihren Proxy ein.
ghcr.io/ipscanner/forward-auth ist ein statisches Binary für linux/amd64 und linux/arm64, das ohne Root-Rechte und ohne Shell läuft. Binaries für Linux und macOS gibt es auf der Releases-Seite.
Eine neue Website startet im Monitor-Modus: Sie erhält Header, blockiert wird nichts, bis Sie auf Enforce umschalten.
Überblick auf der Seite zu nginx, Apache und HAProxy, Quellcode auf GitHub.
services:
ipscanner:
image: ghcr.io/ipscanner/forward-auth:0.1
restart: unless-stopped
environment:
IPSCANNER_API_KEY: ${IPSCANNER_API_KEY}
SITE_ID: site_...Proxy-Snippets
- nginx
auth_requestauth_requestfragt/checkzu jeder Anfrage. Ein blockierter Besucher sieht die 403-Seite des Gates, ein nicht erreichbares Gate lässt den Traffic durch. nginx löst das Gate beim Start auf, starten Sie es also zuerst. - Nginx Proxy Manager
auth_requestDasselbe im Tab Advanced des Proxy-Hosts, mit dem Gate im Docker-Netzwerk von NPM.
- Traefik
ForwardAuthEine ForwardAuth-Middleware in den Labels Ihrer App. Das Traefik-Plugin leistet dasselbe ohne Container.
- Caddy
forward_authforward_authan/check, mit Übernahme derX-IPScanner-*-Header. Das Caddy-Modul leistet dasselbe ohne Container. - HAProxy
UPSTREAM_URLProxy-Modus mit
UPSTREAM_URL=http://app:80. Die App ist der Backup-Server, der Traffic fließt also weiter, wenn das Gate ausfällt. - Apache
UPSTREAM_URLProxy-Modus wie bei HAProxy, mit der App als Hot Standby.
location / {
auth_request /_ipscanner;
auth_request_set $ipscanner_status $upstream_http_x_ipscanner_status;
auth_request_set $ipscanner_class $upstream_http_x_ipscanner_class;
auth_request_set $ipscanner_action $upstream_http_x_ipscanner_action;
auth_request_set $ipscanner_network $upstream_http_x_ipscanner_network_class;
auth_request_set $ipscanner_anonymized $upstream_http_x_ipscanner_anonymized;
auth_request_set $ipscanner_risk $upstream_http_x_ipscanner_risk;
auth_request_set $ipscanner_country $upstream_http_x_ipscanner_country;
auth_request_set $ipscanner_site $upstream_http_x_ipscanner_site;
auth_request_set $ipscanner_request_id $upstream_http_x_ipscanner_request_id;
error_page 403 = @ipscanner_blocked;
proxy_set_header X-IPScanner-Status $ipscanner_status;
proxy_set_header X-IPScanner-Class $ipscanner_class;
proxy_set_header X-IPScanner-Action $ipscanner_action;
proxy_set_header X-IPScanner-Network-Class $ipscanner_network;
proxy_set_header X-IPScanner-Anonymized $ipscanner_anonymized;
proxy_set_header X-IPScanner-Risk $ipscanner_risk;
proxy_set_header X-IPScanner-Country $ipscanner_country;
proxy_set_header X-IPScanner-Site $ipscanner_site;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://app:80;
}
location = /_ipscanner {
internal;
proxy_pass http://ipscanner:8080/check;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Original-URI $request_uri;
proxy_set_header X-Original-Method $request_method;
proxy_connect_timeout 1s;
proxy_read_timeout 5s;
error_page 500 502 503 504 = @ipscanner_down;
}
location @ipscanner_down {
return 204;
}
location @ipscanner_blocked {
internal;
proxy_method GET;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-IPScanner-Request-Id $ipscanner_request_id;
rewrite ^ /blocked break;
proxy_pass http://ipscanner:8080;
}Endpunkte
/checkForward Auth200 mit den
X-IPScanner-*-Headern oder 403 mit Sperrseite undX-IPScanner-Request-Id./blockedForward AuthDie 403-Seite für die Request-ID in
X-IPScanner-Request-Id, für nginxerror_page./healthzbeide Modi200 als JSON: Version, Modus, Website, Backoff, letzter Fehler und die zwischengespeicherte Richtlinie.
/check liest die ursprüngliche Anfrage aus den Headern des Proxys: X-Forwarded-For (oder IP_HEADERS), User-Agent, X-Forwarded-Uri oder X-Original-URI sowie X-Forwarded-Method oder X-Original-Method.
Konfiguration
IPSCANNER_API_KEYIhr API-Schlüssel. Ohne Schlüssel passiert jede Anfrage ungeprüft.
IPSCANNER_API_KEY_FILEDatei mit dem Schlüssel, für Docker-Secrets. Hat Vorrang vor
IPSCANNER_API_KEY.SITE_IDSite-ID aus dem Dashboard. Modus und Richtlinie kommen dann aus dem Dashboard.
MODEStandard monitormonitor oder enforce. Mit Website wirkt nur monitor: Die Website bleibt dann im Monitor-Modus.
BLOCK_CLASSESStandard malicious_automationOhne Website: im Enforce-Modus blockierte Klassen, durch Komma getrennt, aus malicious_automation, ai_agent, tor, vpn, proxy, hosting, relay oder none.
TRUSTED_PROXIESStandard privateAdressen und CIDR-Bereiche, deren IP- und URI-Headern vertraut wird. private, cloudflare oder none für nur die Peer-Adresse.
IP_HEADERSStandard X-Forwarded-ForHeader, die der Reihe nach von einem vertrauenswürdigen Proxy gelesen werden. Hinter Cloudflare:
CF-Connecting-IP.TIMEOUT_MSStandard 1500Zeitbudget für eine Prüfung in Millisekunden. Bei Zeitüberschreitung passiert die Anfrage.
CACHE_TTLStandard 600Sekunden, die ein Ergebnis pro Website, IP und User-Agent wiederverwendet wird. Angaben wie 10m gehen auch.
CACHE_SIZEStandard 10000Ergebnisse im Speicher.
POLICY_TTLStandard 30Sekunden, die die Richtlinie der Website wiederverwendet wird. Zeitangaben gehen auch.
SKIP_PATHSStandard statische DateienRegex auf den Pfad, ohne Groß- und Kleinschreibung. Passende Anfragen werden nicht geprüft; leer prüft jeden Pfad.
UPSTREAM_URLSchaltet den Proxy-Modus ein: Erlaubte Anfragen gehen an diese URL.
LISTENStandard :8080Listen-Adresse.
HEALTH_PATHStandard /healthzHealth-Endpunkt.
BLOCK_MESSAGEStandard Blocked by IPScanner edge guard.Text der 403-Seite.
IPSCANNER_API_URLStandard https://ipscanner.ioBasis-URL der API.
DEBUGStandard falseProtokolliert jede Entscheidung in einer Zeile. Im Proxy-Modus kommen Status-, Class- und Action-Header in die Antworten.
Ungültige Werte stoppen das Gate beim Start mit einer Log-Zeile. Der API-Schlüssel wird nie protokolliert.
Client-IP
TRUSTED_PROXIESX-Forwarded-Forwird nur gelesen, wenn der Peer in dieser Liste steht, und zwar die Kette zurück bis zur ersten Adresse, die kein vertrauenswürdiger Proxy ist. Bei allen anderen gilt die Peer-Adresse.privateDer Standard. Passt zu einem Proxy, der das Gate über ein Docker- oder privates Netzwerk erreicht. Können andere in diesem Netzwerk das Gate erreichen, tragen Sie stattdessen die Adresse Ihres Proxys ein.
:8080Veröffentlichen Sie den Port des Gates nicht: Nur Ihr Proxy soll es erreichen.
Gesetzte Header
Bei 200 von /check, damit Ihr Proxy sie an die App weitergibt, und im Proxy-Modus an der Anfrage an Ihre App. Der Proxy-Modus entfernt eingehende X-IPScanner-*-Header; die Snippets tun das im Proxy.
X-IPScanner-Statusok, error, timeout, backoff, skippedOb die Prüfung lief und falls nicht, warum.
X-IPScanner-Classhuman, verified_bot, ai_agent, …Traffic-Klasse des Besuchers.
X-IPScanner-Actionallow, flag, block, would_flag, would_blockWas mit der Anfrage geschah. Im Monitor-Modus
would_flagundwould_block.X-IPScanner-Network-Classresidential_clean, hosting, vpn, tor, …Netzwerkklasse der Adresse.
X-IPScanner-Anonymizedtrue, falseDas Netzwerk verbirgt, wo der Besucher ist.
X-IPScanner-Risk0-100Risikowert der Adresse.
X-IPScanner-CountryDELand der Adresse.
X-IPScanner-Sitesite_...Die Site-ID, wenn eine gesetzt ist.
Schlägt eine Prüfung fehl oder wird sie übersprungen, ist nur X-IPScanner-Status gesetzt.
X-IPScanner-Status: ok
X-IPScanner-Class: ai_agent
X-IPScanner-Action: would_block
X-IPScanner-Network-Class: hosting
X-IPScanner-Anonymized: true
X-IPScanner-Risk: 60
X-IPScanner-Country: US
X-IPScanner-Site: site_4fQ8nZ2kLm7xR1vT9cBwCache und Fail-open
- Richtlinie der WebsiteGET /v1/sites/{id}/policy
Modus und Richtlinie pro Klasse, 30 s im Cache. Scheitert eine Aktualisierung, gilt die letzte gültige Richtlinie bis zu 24 Stunden. Änderungen greifen ohne Neustart.
- Ergebnis-Cache
Eine Prüfung pro Besucher (Website, IP, User-Agent) alle 10 Minuten, im Speicher, pro Gate-Instanz.
- Fail-open
1,5 s für Ergebnis und Richtlinie zusammen. Bei Zeitüberschreitung oder API-Fehler passiert die Anfrage, und Prüfungen pausieren 30 s, nach 401, 402, 403 oder 429 fünf Minuten.
- Gate nicht erreichbar
nginx und NPM lassen nach dem Connect-Timeout von 1 s durch, HAProxy schickt den Traffic sofort an die App, Apache lässt eine Anfrage scheitern und nutzt dann die App. Traefik antwortet mit 500 und Caddy mit 502, starten Sie das Gate daher mit
restart: unless-stopped. - Immer durchgelassen
Verifizierte Crawler, OPTIONS-Anfragen, private und Loopback-Adressen sowie Pfade auf der Ausnahmeliste.
- Blockiert
Eine 403-Seite mit der Request-ID. Der Monitor-Modus blockiert nie.
- Free-Plan
Websites im Free-Plan bleiben im Monitor-Modus.
- Kosten
2 Request-Einheiten pro Besucher ohne Cache-Treffer. Wiederholte Anfragen im Cache-Fenster sind kostenlos.
Was gesendet wird
- POST /v1/edge/checkZählt als 2 Anfragen
Ein Aufruf pro Besucher ohne Cache-Treffer.
- GET /v1/sites/{id}/policyNicht berechnet
Die Richtlinie der Website, wenn eine Site-ID gesetzt ist.
X-IPScanner-Source: forward_authKennzeichnet die Aufrufe in Traffic und Nutzung als Aufrufe dieser Integration.
User-Agent: ipscanner-forward-auth/<version>Die Version, angezeigt auf der Seite der Website im Dashboard.
Request-Body
sitestringDie Site-ID, wenn eine gesetzt ist.
ipstringDie Adresse des Besuchers.
user_agentstringDer User-Agent des Besuchers.
headersobjectAccept, Accept-Language, Accept-Encoding, Sec-CH-UA* und Sec-Fetch-*, jeweils auf 512 Byte gekürzt.
request_idstringDie
X-Request-Idder Anfrage oder eine neue ID, die auch auf der Sperrseite steht.
curl https://ipscanner.io/v1/edge/check \
-H "Authorization: Bearer $IPSCANNER_API_KEY" \
-H "X-IPScanner-Source: forward_auth" \
-H "User-Agent: ipscanner-forward-auth/0.1.0" \
-H "Content-Type: application/json" \
-d '{
"site": "site_4fQ8nZ2kLm7xR1vT9cBw",
"ip": "203.0.113.7",
"user_agent": "Mozilla/5.0",
"headers": {
"accept-language": "en-US"
},
"request_id": "9f2c41b7d03e77f2"
}'