SearXNG selbst hosten mit Docker Compose und TLS
Betreiben Sie SearXNG privat auf dem eigenen VPS: mit settings.yml, Limiter, nginx und TLS sowie einer JSON-API, die Ihre Skripte ohne API-Key nutzen.
Was Sie erstellen
Mit einem selbst gehosteten SearXNG betreiben Sie eine private Suchmaschine auf Ihrem eigenen Server. SearXNG ist eine Metasuchmaschine. Sie nimmt Ihre Suchanfrage entgegen, fragt andere Suchmaschinen wie Google, Bing, DuckDuckGo und Wikipedia ab und führt die Ergebnisse auf einer Ergebnisseite zusammen. Es wird kein Profil erstellt und kein Tracking-Cookie gesetzt, weil nur Ihr eigener Rechner Ihre Suchanfrage speichert.
Der Stack ist klein. Zwei Container, eine Einstellungsdatei und ein Reverse-Proxy. Die entscheidende Frage ist, ob die Instanz privat ist, also nur Sie und Ihre eigenen Skripte darauf zugreifen, oder öffentlich, also ob jeder im Internet Suchanfragen stellen kann. Diese Entscheidung ändert die Sicherheitseinstellungen. Treffen Sie sie, bevor Sie etwas eingeben. Die Standardeinstellung ist privat.
Es gibt noch einen weiteren Grund, eine solche Instanz zu betreiben. Eine SearXNG-Instanz stellt JSON bereit. Dadurch erhält jedes Skript und jeder von Ihnen erstellte KI-Agent eine eigene Such-API, ohne Schlüssel, Abrechnung pro Suchanfrage oder Quota-Benachrichtigungen.
SearXNG mit Docker Compose installieren
Das Projekt stellt ein Container-Image und eine Compose-Datei bereit. Laden Sie beides auf einen neuen Ubuntu 24.04-Server herunter, auf dem Docker Engine und das Compose-Plugin bereits installiert sind. Wenn Docker für Sie neu ist, beginnen Sie mit Grundlagen zu Docker Compose auf einem VPS und kehren Sie anschließend hierher zurück.
sudo install -d -o "$USER" -g "$USER" -m 750 /opt/searxng
cd /opt/searxng
mkdir -p core-config
curl -fsSL \
-O https://raw.githubusercontent.com/searxng/searxng/master/container/docker-compose.yml \
-O https://raw.githubusercontent.com/searxng/searxng/master/container/.env.example
cp -i .env.example .envDie Compose-Datei definiert zwei Services. core ist SearXNG selbst, und valkey ist ein In-Memory-Datenspeicher für die Ratenbegrenzung und kurzlebige Zustände. Sie bindet ./core-config/ im Container unter /etc/searxng/ ein. Daher befindet sich die gesamte Konfiguration in diesem einen Verzeichnis auf dem Host.
Bearbeiten Sie jetzt .env. Jede Zeile im mitgelieferten Beispiel ist auskommentiert. Deshalb startet der Container auf Port 8080 an jeder Adresse. Kommentieren Sie diese drei Zeilen aus und setzen Sie die Werte.
SEARXNG_VERSION=latest
SEARXNG_HOST=127.0.0.1
SEARXNG_PORT=8080SEARXNG_HOST=127.0.0.1 ist die wichtigste Einstellung. Damit wird der veröffentlichte Port auf 127.0.0.1:8080:8080 statt auf [::]:8080:8080 gesetzt. Der Container antwortet dann nur über die Loopback-Adresse, und das Internet kann ihn nicht direkt erreichen. Wenn Sie diese Einstellung überspringen, ist der Container sofort nach dem Start erreichbar. Ein veröffentlichter Docker-Port wird vor Ihren Firewall-Regeln eingefügt. Diese typische Falle wird hier vollständig erklärt: Veröffentlichte Docker-Ports umgehen ufw.
SEARXNG_VERSION=latest ist zum Lernen geeignet. Auf einem Server, der Ihnen wichtig ist, sollten Sie den Tag festlegen. Seit Juli 2026 basieren die Release-Tags auf dem Datum und sehen wie 2026.3.25-541c6c3cb aus. Eine festgelegte Bereitstellung wird dann aktualisiert, wenn Sie es entscheiden, und nicht wenn sich die Registry ohne Ihr Zutun ändert.
settings.yml: die wichtigen Teile
Erstellen Sie core-config/settings.yml vor dem ersten Start. use_default_settings: true weist SearXNG an, zunächst die mitgelieferten Standardwerte zu laden und anschließend nur die von Ihnen angegebenen Schlüssel anzuwenden. Dadurch bleibt Ihre Datei kurz und ist gegen Upgrades geschützt, die neue Optionen hinzufügen.
Generieren Sie zuerst das Secret, da der Wert direkt in die Datei geschrieben wird.
openssl rand -hex 32use_default_settings: true
general:
instance_name: "search.example.com"
server:
base_url: "https://search.example.com/"
secret_key: "paste-the-openssl-output-here"
limiter: false
public_instance: false
image_proxy: true
valkey:
url: valkey://valkey:6379/0
search:
safe_search: 0
autocomplete: "duckduckgo"
formats:
- html
- jsonsecret_key signiert Sitzungs- und Tokendaten. Der mitgelieferte Standardwert ist die Zeichenfolge ultrasecretkey. Wenn Sie ihn unverändert lassen, kann jeder, der diesen Standardwert kennt, diese Tokens fälschen. Ersetzen Sie ihn einmal und ändern Sie ihn danach nicht mehr. Eine spätere Änderung verwirft alle gespeicherten Einstellungen.
base_url muss die öffentliche HTTPS-Adresse mit dem abschließenden Schrägstrich sein. SearXNG schreibt diese Adresse in die erzeugten Links. Wenn sie auf localhost zeigt, verweist der Link "next page" in einem entfernten Browser auf den Computer des Lesers und funktioniert nicht.
formats legt fest, welche Ausgabetypen der Web-Endpunkt erzeugt. json ist nicht in der Standardliste enthalten. Eine JSON-Anfrage gibt daher 403 zurück, bis Sie den Typ hinzufügen. image_proxy: true leitet Ergebnisvorschaubilder über Ihren Server weiter. Die Websites, auf denen diese Bilder liegen, sehen dadurch niemals die Adressen Ihrer Besucher.
Der valkey.url verwendet den Hostnamen valkey, weil dies der Servicename in der Compose-Datei ist. Compose verbindet beide Container mit einem Netzwerk, in dem Servicenamen aufgelöst werden. Wenn Sie auf localhost verweisen, funktioniert der Limiter nicht, weil localhost innerhalb des core-Containers auf diesen Container selbst zeigt.
Das Secret befindet sich in einer unverschlüsselten Datei. Schützen Sie daher das Verzeichnis, in dem die Datei liegt, und nicht nur die Datei selbst. chmod 750 /opt/searxng hält andere Benutzer auf dem Host fern. Setzen Sie core-config/settings.yml nicht auf den Modus 600. Der Container läuft als eigener nicht privilegierter Benutzer. Wenn dieser Benutzer die Datei nicht lesen kann, startet SearXNG überhaupt nicht.
Starten Sie den Stack und prüfen Sie ihn.
cd /opt/searxng
docker compose up -d
docker compose ps
curl -I http://127.0.0.1:8080/docker compose ps sollte beide Container mit dem Status running anzeigen. Der curl sollte mit HTTP/1.1 200 OK antworten. Wenn keine Antwort erfolgt, lesen Sie docker compose logs core. Ein YAML-Fehler in settings.yml wird dort als Parse-Fehler mit Angabe der betreffenden Zeile angezeigt.
Hinter nginx mit TLS betreiben
Der Container lauscht nur auf dem Loopback-Interface. nginx macht ihn erreichbar und fügt außerdem die Transportsicherheit (TLS) hinzu. Schreiben Sie /etc/nginx/sites-available/searxng.
server {
listen 80;
server_name search.example.com;
location / {
proxy_pass http://127.0.0.1:8080;
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;
}
}sudo ln -s /etc/nginx/sites-available/searxng /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
sudo certbot --nginx -d search.example.comnginx -t gibt syntax is ok und test is successful aus, bevor Sie nginx neu laden. Certbot schreibt dieselbe Datei so um, dass sie mit einem Zertifikat auf Port 443 lauscht, und fügt eine Weiterleitung von Port 80 hinzu. Der DNS-Eintrag für search.example.com muss bereits auf diesen Server zeigen, weil die Zertifizierungsstelle den Besitz durch das Abrufen einer Datei über HTTP nachweist. Die vollständige Anleitung einschließlich der Erneuerung finden Sie im Certbot- und nginx-Leitfaden für Ubuntu 24.04.
Die beiden Weiterleitungs-Header sind nicht nur Zierde. Ohne X-Forwarded-For und X-Real-IP enthält jede bei SearXNG eintreffende Anfrage die Proxy-Adresse. Der Ratenbegrenzer sieht dann einen Client, der den gesamten Datenverkehr erzeugt, und kann die Besucher nicht unterscheiden.
Warum Skripte und Agents eine JSON-Such-API benötigen
Mit json in formats gibt derselbe Endpunkt, der die Seite rendert, strukturierte Daten zurück.
curl -s 'http://127.0.0.1:8080/search?q=wireguard+mtu&format=json' \
| jq -r '.results[0:5][] | .url'Sie erhalten ein Objekt mit einem results-Array. Jeder Eintrag enthält url, title, content und die Suchmaschine, die das Ergebnis geliefert hat, sowie answers, infoboxes und suggestions. Das reicht aus, um einen Zusammenfasser, einen Linkprüfer oder eine Recherche-Schleife zu versorgen.
Das ist für alle Anwendungen mit Agents wichtig. Ein Sprachmodell hat einen Trainingsstichtag. Daher benötigt es eine Live-Suche, um Fragen zur Gegenwart zu beantworten. Kommerzielle Such-APIs berechnen Gebühren pro Abfrage und begrenzen die Rate stark. Eine lokale Instanz benötigt nur einen Container auf einem Server, für den Sie bereits bezahlen. Die Abfragen verlassen diesen Server nicht. Wenn Sie Tools in ein Modell integrieren, gilt dieselbe Überlegung für das Betreiben von MCP-Servern auf einem VPS. Ein Such-Tool ist dabei meist das erste Tool, das hinzugefügt wird.
Beachten Sie bei der API-Nutzung zwei Regeln. Halten Sie die Instanz privat. Binden Sie die API-Seite an die Loopback-Adresse oder an ein privates Netzwerk. Lassen Sie nur Ihre eigenen Hosts darauf zugreifen. Senden Sie anschließend Abfragen mit geringer Rate. SearXNG leitet Ihre Anfrage an echte Suchmaschinen weiter. Ein Skript, das hundert Abfragen pro Sekunde ausführt, fordert Google daher auf, Ihren Server zu blockieren.
Der Limiter und was sich bei einer öffentlichen Instanz ändert
Der Limiter ist der Bot-Schutz von SearXNG. Er überwacht Request-Header, Adressen und Request-Raten und verwirft Netzwerkverkehr, der automatisiert wirkt. Dafür benötigt er Valkey, um diesen Status zu speichern. Deshalb ist Valkey in der Compose-Datei enthalten.
Auf einer privaten Instanz lassen Sie limiter: false aktiviert. Ihre eigenen Skripte erzeugen definitionsgemäß automatisierten Netzwerkverkehr. Der Limiter würde daher genau die JSON-Aufrufe blockieren, für die Sie die Instanz eingerichtet haben. Die Zugriffskontrolle ist stattdessen Aufgabe des Reverse-Proxys: mit einem allow- und deny-Paar in der nginx-location, mit HTTP-Basisauthentifizierung oder mit einer Firewall, die nur Ihre anderen Server zulässt.
Wenn Sie die Instanz für andere Personen veröffentlichen, aktivieren Sie beide Schalter.
server:
limiter: true
public_instance: trueEine genauere Steuerung ist in core-config/limiter.toml möglich. Der Container liest diese Datei unter /etc/searxng/limiter.toml ein. Sie tragen nur die Schlüssel ein, die Sie ändern möchten. Hinter einem Proxy müssen Sie den Proxy deklarieren. Andernfalls behandelt der Limiter Ihre nginx-Adresse als die eines einzigen missbräuchlichen Clients.
[botdetection]
trusted_proxies = [
'127.0.0.0/8',
'::1',
]
[botdetection.ip_limit]
link_token = truelink_token = true veranlasst SearXNG, ein Token auszugeben, das nur eine echte Browsersitzung abruft. Dadurch werden die meisten einfachen Scraper gestoppt. Rechnen Sie damit, dass eine öffentliche Instanz innerhalb weniger Tage solche Zugriffe anzieht. Rechnen Sie auch mit Engine-Fehlern. Je mehr Netzwerkverkehr Sie weiterleiten, desto früher senden vorgelagerte Engines CAPTCHAs an Ihre Serveradresse zurück. Eine öffentliche SearXNG-Instanz erfordert laufende Arbeit. Eine private Instanz nicht. Deshalb steht sie auf den meisten kurzen Listen mit Dingen, die sich 2026 für Self-Hosting lohnen.
Warum Suchvorgänge keine Ergebnisse liefern
Öffnen Sie /stats auf Ihrer Instanz. Dort werden alle Engines mit ihrer Fehlerquote und Antwortzeit aufgeführt. Diese Übersicht ist der erste Prüfpunkt, wenn nur wenige Ergebnisse angezeigt werden.
Eine Engine mit den Fehlern "Access denied" oder "CAPTCHA" hat Ihre Serveradresse blockiert. Das kommt bei Adressen aus Rechenzentrumsbereichen häufig vor, weil Suchmaschinen davon ausgehen, dass diese zu Scraper-Servern gehören. SearXNG deaktiviert die fehlerhafte Engine anschließend für einen bestimmten Zeitraum, statt sie erneut abzufragen. Dadurch fällt eine blockierte Engine unbemerkt aus Ihren Ergebnissen heraus. Deaktivieren Sie sie in settings.yml oder akzeptieren Sie den Verlust. Die übrigen Engines antworten weiterhin.
Wenn alle Engines gleichzeitig ausfallen, verfügt der Container über keine funktionierende Namensauflösung nach außen oder keine Route zum Internet. Testen Sie dies innerhalb des Containers.
docker compose exec core wget -qO- https://duckduckgo.com > /dev/null && echo okFAQ
Macht SearXNG meine Suchanfragen anonym?
SearXNG verbirgt Ihre Identität vor den abgefragten Suchmaschinen, weil diese sehen, dass Ihr Server die Anfrage stellt, und nicht Ihr Browser. Die Suchanfrage bleibt für Ihren Server sichtbar, und Ihr Server bleibt für die Suchmaschinen sichtbar. Bei einer Instanz mit nur einem Benutzer stammt der gesamte Datenverkehr von dieser Adresse von Ihnen. Dadurch wird die Adresse selbst zum Identifikator. Der Datenverkehr zwischen Ihrem Browser und Ihrer Instanz ist durch das TLS-Zertifikat geschützt.
Warum gibt eine JSON-Anfrage 403 Forbidden zurück?
Dafür gibt es 2 Ursachen, und beide liegen an der Konfiguration. Entweder fehlt json in der Liste formats unter search: in settings.yml. Das ist der Standardzustand. Oder der Limiter ist aktiviert und hat Ihr Skript als Bot eingestuft. Fügen Sie zuerst das Format hinzu und starten Sie mit docker compose restart core neu. Versuchen Sie es dann erneut. Wenn die Anfrage weiterhin fehlschlägt, setzen Sie limiter: false und steuern Sie den Zugriff stattdessen am Reverse Proxy.
Benötige ich den Valkey-Container, wenn der Limiter deaktiviert bleibt?
Lassen Sie ihn laufen. SearXNG funktioniert ohne ihn. Der Limiter kann später jedoch ohne ihn nicht aktiviert werden. Außerdem speichert der Container weiteren kurzlebigen Status. Der Container ist klein und speichert nur zwischengespeicherte Daten. Durch das Entfernen sparen Sie daher sehr wenig und verlieren die Möglichkeit, den Limiter später zu aktivieren.
Wie aktualisiere ich SearXNG?
Führen Sie docker compose pull und anschließend docker compose up -d in /opt/searxng aus. Compose erstellt jeden Container neu, dessen Image geändert wurde, und lässt Ihr Verzeichnis core-config/ unverändert. Daher bleibt settings.yml erhalten. Da use_default_settings: true Ihre Schlüssel mit den ausgelieferten Standardwerten zusammenführt, werden mit Upstream hinzugefügte Optionen mit sinnvollen Werten übernommen, statt die Datei unbrauchbar zu machen.
Können mehrere Personen eine Instanz gemeinsam verwenden?
Ja. In diesem Fall aktivieren Sie den Limiter und setzen public_instance: true. Einstellungen werden im Browser der jeweiligen Person gespeichert. Daher müssen Sie keine Konten verwalten. Überwachen Sie /stats eine Woche lang, nachdem Sie die Instanz freigegeben haben. Upstream-Suchmaschinen beginnen, Ihren Server abzulehnen, lange bevor Sie fehlende Ergebnisse bemerken.