Ich benutze die normale Google-Suche inzwischen tatsächlich nur noch sehr selten. Wenn ich etwas suche, frage ich entweder ChatGPT oder benutze meine eigene SearXNG-Instanz.
Das hat auch lange ziemlich problemlos funktioniert. Meine Suche ist öffentlich erreichbar und darf durchaus von anderen Menschen benutzt werden. Genau das soll auch so bleiben.
Was ich allerdings nicht haben möchte: irgendwelche Bots und Scraper, die rund um die Uhr automatisiert Suchanfragen durch meine Instanz jagen.
Ein Follower im Fediverse hat mich irgendwie auf die Idee gebracht, mich mit dem Thema mehr auseinander zu setzen und hatte Crowdsec vorgeschlagen, ich weiß nicht, warum, aber irgendwie kam ich darüber auf Anubis.
Die massenhaften Anfragen von Bots/Crawlern wurden schnell zum Problem.
Plötzlich nur noch Timeouts, CAPTCHAs und 429
Anfangs sah es einfach danach aus, als wären einige Suchmaschinen in SearXNG etwas unzuverlässig geworden.
In den Logs tauchten immer häufiger Meldungen dieser Art auf:
TooManyRequests
CAPTCHA
403 Forbidden
ConnectTimeout
Brave beschwerte sich über zu viele Anfragen, Startpage präsentierte CAPTCHAs, Google erkannte „ungewöhnlichen Traffic“ und DuckDuckGo reagierte irgendwann überhaupt nicht mehr.
Bei DuckDuckGo ließ sich das sogar direkt auf dem Server nachvollziehen:
curl -4 -I --max-time 10 https://html.duckduckgo.com/
Ergebnis:
curl: (28) Connection timed out after 10002 milliseconds
Andere Webseiten waren gleichzeitig problemlos erreichbar.
Zunächst lag natürlich der Gedanke nahe, einfach die Timeouts von SearXNG zu erhöhen. Das hätte aber das eigentliche Problem überhaupt nicht gelöst.
Denn ein Blick in die Logs zeigte etwas viel Interessanteres.
Eine Armee aus angeblichen Kindle Fires
Während ich selbst beispielsweise schlicht nach „Wetter“ suchte, tauchten plötzlich ganz andere Suchanfragen in den Logs auf.
Dazu kamen User-Agents wie:
Kindle Fire Build/GINGERBREAD
Android 2.3.4
AmazonWebAppPlatform
kombiniert mit russischer Sprache und ständig wechselnden IPv6-Adressen.
Mein Kindle-Fire-Besucherandrang war also überraschend groß. Nur besitze ich gar keinen Kindle-Fire-Fanclub. 😉
Die Anfragen kamen automatisiert von Bots.
Damit wurde auch klar, warum nach und nach die eigentlichen Suchmaschinen meine Server-IP nicht mehr mochten:
Bot
↓
meine SearXNG-Instanz
↓
Google / Brave / DuckDuckGo / Startpage
↓
„Was zum Teufel macht diese IP da?“
↓
CAPTCHA / 429 / Sperre
Mein Server läuft bei Hetzner. Rechenzentrums-IP-Adressen stehen bei Suchmaschinen ohnehin schneller unter Verdacht als ein gewöhnlicher Privatanschluss. Wenn dann zusätzlich irgendwelche Bots über diese IP Tausende Suchanfragen produzieren, ist irgendwann Feierabend.
Der SearXNG-Limiter alleine reichte mir nicht
SearXNG besitzt bereits einen eigenen Limiter und verwendet dafür Valkey.
Das ist sinnvoll und sollte meiner Meinung nach auch unbedingt aktiviert bleiben:
server:
limiter: true
public_instance: true
valkey:
url: valkey://valkey:6379/0
Der Limiter tat bei mir auch durchaus etwas. Besonders schön ist beispielsweise, dass IPv6-Adressen zu Netzen zusammengefasst werden können. Ein Bot kann dadurch nicht einfach innerhalb seines IPv6-Netzes ständig die Adresse wechseln und jedes Mal wieder von vorne anfangen.
Trotzdem wollte ich verhindern, dass der ganze Müll überhaupt bis SearXNG kommt.
Ich brauchte also einen Türsteher.
Anubis als Türsteher vor SearXNG
Hier kam Anubis ins Spiel.
Anubis sitzt als zusätzliche Schicht vor einer Webanwendung und stellt verdächtigen Clients eine Proof-of-Work-Challenge.
Ein echter Browser kann diese Challenge relativ problemlos lösen. Für einen einzelnen Besucher ist der zusätzliche Rechenaufwand kaum relevant.
Für einen Scraper, der Tausende oder Millionen Requests erzeugen möchte, sieht die Rechnung etwas anders aus.
Mein Aufbau sieht inzwischen so aus:
Internet
↓
Nginx
↓
Anubis
↓
SearXNG
↓
Valkey
SearXNG, Valkey und Anubis laufen bei mir gemeinsam über Docker Compose.
SearXNG selbst benötigt dabei überhaupt keinen öffentlich erreichbaren Port mehr. Nur Anubis wird lokal an den Host gebunden:
ports:
- "127.0.0.1:8383:8080"
Anubis wiederum kennt SearXNG über das gemeinsame Docker-Netz:
TARGET: "http://searxng:8080"
Mein Host-Nginx spricht damit nicht mehr direkt mit SearXNG.
Vorher:
proxy_pass http://127.0.0.1:8383;
wobei dort SearXNG lauschte.
Heute lauscht auf diesem Port Anubis:
Nginx
↓
127.0.0.1:8383
↓
Anubis
↓
searxng:8080
Die wichtigen Proxy-Header bleiben natürlich erhalten:
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
Danach wurde es in den Logs ziemlich unterhaltsam.
Die ganzen angeblichen Kindle-Fire-Nutzer waren weiterhin da – nur bekamen sie jetzt von Anubis:
new challenge issued
Und genau dort endete ihre Reise.
Das war der erste große Erfolg.
Damit war aber erst die Hälfte des Problems gelöst
Anubis schützt die Eingangsseite:
Bot → Anubis → Ende
Die Hetzner-IP war bei einigen Suchmaschinen aber offensichtlich bereits verbrannt.
Google und Brave meldeten weiterhin zu viele Requests, Startpage wollte ein CAPTCHA und DuckDuckGo war über die normale Server-IP überhaupt nicht erreichbar.
Also brauchte SearXNG zusätzlich einen anderen Ausgang ins Internet.
Und dafür verwende ich Gluetun.
Gluetun als VPN-Ausgang für SearXNG
Gluetun ist ein VPN-Client für Docker und unterstützt verschiedene VPN-Anbieter.
Ich wollte allerdings nicht den gesamten Netzwerk-Namespace von SearXNG an Gluetun hängen. Stattdessen benutze ich den in Gluetun eingebauten HTTP-Proxy.
Damit sieht die endgültige Architektur so aus:
INTERNET
│
▼
Nginx
│
▼
Anubis
│
▼
SearXNG
│
▼
Gluetun HTTP Proxy
│
▼
VPN
│
▼
Suchmaschinen
Gluetun bekommt im Compose beispielsweise:
gluetun:
image: qmcgaw/gluetun:latest
container_name: searxng-gluetun
restart: unless-stopped
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun:/dev/net/tun
environment:
- VPN_SERVICE_PROVIDER=MEIN_VPN_ANBIETER
- VPN_TYPE=wireguard
# Zugangsdaten sind abhängig vom Anbieter
- HTTPPROXY=on
- HTTPPROXY_LOG=off
- HTTPPROXY_STEALTH=on
Wichtig: Port 8888 muss dafür nicht öffentlich auf dem Server freigegeben werden.
SearXNG und Gluetun befinden sich im gleichen Docker-Netz und sprechen direkt miteinander.
In der settings.yml von SearXNG landet dann:
outgoing:
request_timeout: 6.0
max_request_timeout: 12.0
extra_proxy_timeout: 4
pool_connections: 100
pool_maxsize: 20
enable_http2: true
proxies:
all://:
- http://gluetun:8888
Kleine Stolperfalle am Rande:
extra_proxy_timeout: 4.0
mochte meine SearXNG-Version nicht.
Es musste tatsächlich ein Integer sein:
extra_proxy_timeout: 4
Solche Dinge findet man natürlich grundsätzlich erst abends, wenn man eigentlich längst fertig sein wollte.
Und plötzlich funktionierte die Suche wieder
Danach war der Unterschied ziemlich deutlich.
Vorher:
Google → unusual traffic
Brave → 429 Too Many Requests
Startpage → CAPTCHA
DuckDuckGo → ConnectTimeout
Qwant → teilweise 403
Nach dem VPN-Wechsel funktionierte der Großteil meiner Suchmaschinen wieder normal.
Einzelne Engines mögen natürlich auch VPN-Ausgangs-IP-Adressen nicht. Aktuell machen bei mir beispielsweise Startpage und teilweise DuckDuckGo noch Probleme.
Das ist für mich allerdings kein Grund, die gesamte Installation wieder umzubauen.
SearXNG lebt schließlich gerade davon, mehrere Suchmaschinen zusammenzufassen. Lieber benutze ich fünf bis acht zuverlässige Engines als zwanzig Stück, von denen ständig sechs einen Fehler produzieren.
Wikipedia möchte ich beispielsweise auf jeden Fall noch stärker einbinden.
Warum Anubis und VPN zusammen für mich Sinn ergeben
Nur einen VPN vor SearXNG zu setzen hätte mein ursprüngliches Problem nicht wirklich gelöst.
Die Bots hätten dann einfach die neue VPN-IP ebenfalls mit Suchanfragen bombardiert.
Nur Anubis zu verwenden hätte wiederum die bereits problematische Hetzner-IP nicht sofort wieder bei allen Suchmaschinen rehabilitiert.
Zusammen ergibt das für mich inzwischen wesentlich mehr Sinn:
EINGANG
│
echte Nutzer
│
▼
Anubis
│
▼
SearXNG
│
▼
Gluetun
│
▼
VPN
│
▼
Suchmaschinen
AUSGANG
Anubis schützt also vorne, Gluetun verändert hinten den Ausgang.
Und der SearXNG-Limiter mit Valkey bleibt zusätzlich aktiv.
Eine kleine Anubis-Macke unter Firefox auf iOS
Ganz problemlos war Anubis bei mir allerdings auch nicht.
Unter Firefox auf iOS bekomme ich gelegentlich die Meldung, Cookies seien deaktiviert, obwohl das so nicht unbedingt stimmt.
Das Problem ist bereits bekannt und es gibt dazu einen entsprechenden Issue bei Anubis.
In Safari funktioniert die Challenge bei mir dagegen problemlos.
Da meine Suche öffentlich bleiben soll, möchte ich die Anubis-Sicherheit deshalb nicht wegen eines einzelnen Browserproblems aufweichen. Bis das behoben ist, muss ich damit leben.
Bots dürfen draußen bleiben, Menschen dürfen weiterhin suchen
Das war mir bei der ganzen Aktion wichtig.
Ich wollte meine SearXNG-Instanz nicht einfach nur mit Passwortschutz versehen und ausschließlich für mich selbst benutzen.
Andere Menschen dürfen meine Suche gerne verwenden.
Was ich nicht brauche, sind irgendwelche Scraper, die automatisiert Tausende Suchanfragen darüber schicken und mir anschließend die IP bei Google, Brave, DuckDuckGo und anderen Suchmaschinen verbrennen.
Nach etwas Fluchen, diversen Nginx-Konfigurationen, Timeouts, einem kurzen Ausflug zu CrowdSec und mehreren Docker-Neustarts sieht mein Setup inzwischen so aus, wie ich es eigentlich von Anfang an hätte aufbauen sollen:
Nginx → Anubis → SearXNG → Gluetun/VPN.
Und vor allem:
Die normale Google-Suche kann damit weiterhin dort bleiben, wo sie bei mir schon seit längerer Zeit ist: weitgehend unbenutzt. 😉
Wie ist deine Meinung?
Schreib gern einen Kommentar unter dem Artikel oder diskutiere mit anderen im Matrix-Kanal:
#dasnetzundich:matrix.org