SearXNG selbst hosten: private Suche mit Docker
Betreiben Sie SearXNG auf einem eigenen VPS mit Docker Compose: settings.yml, Limiter, nginx mit TLS und eine JSON-Such-API für eigene Skripte.
Was Sie erstellen
Mit SearXNG auf Ihrem eigenen Server betreiben Sie eine private Suchmaschine. SearXNG ist eine Metasuchmaschine. Sie nimmt Ihre Suchanfrage entgegen, fragt andere Suchmaschinen wie Google, Bing, DuckDuckGo und Wikipedia ab und fasst die Ergebnisse auf einer gemeinsamen Ergebnisseite zusammen. Es wird kein Profil erstellt und kein Tracking-Cookie gesetzt, weil nur Ihr eigener Rechner Ihre Suchanfrage speichert. Wenn Sie ältere Anleitungen zu einem Projekt namens Searx gefunden haben, handelt es sich dabei um das Projekt, von dem dieses Projekt abgespalten wurde. Es wird seit September 2023 nicht mehr gepflegt. Damals wurde im eigenen Repository angekündigt, dass Searx nicht mehr gepflegt wird. Auch der einzige spätere Commit, ein Dokumentationshinweis vom Mai 2026, änderte daran nichts. Prüfen Sie daher den Status beider Projekte, bevor Sie einer Anleitung folgen.
Der Stack ist klein. Er besteht aus zwei Containern, einer Einstellungsdatei und einem Reverse Proxy. Auf einem kleinen VPS läuft er problemlos gemeinsam mit anderen Diensten. Das gilt nicht für jeden selbst gehosteten Dienst: Bei den in PhotoPrism und Immich verglichenen Fotobibliotheken wird der minimale RAM-Bedarf durch den Indexer und nicht durch die Webanwendung bestimmt. Die entscheidende Frage ist, ob die Instanz privat oder öffentlich sein soll. Privat bedeutet, dass nur Sie und Ihre eigenen Skripte darauf zugreifen. Öffentlich bedeutet, dass jeder im Internet Suchanfragen stellen kann. Diese Wahl ändert die Sicherheitseinstellungen. Treffen Sie sie daher, bevor Sie etwas eingeben. Die Standardeinstellung ist privat.
Es gibt noch einen weiteren Grund für den Betrieb einer eigenen Instanz. Eine SearXNG-Instanz stellt eine JSON-Schnittstelle bereit. Dadurch erhält jedes von Ihnen geschriebene Skript oder jeder von Ihnen erstellte KI-Agent eine eigene Such-API. Dafür benötigen Sie keinen Schlüssel. Es fallen keine Gebühren pro Suchanfrage an und es gibt keine Quota-Benachrichtigungen.
SearXNG mit Docker Compose installieren
Das Projekt veröffentlicht ein Container-Image und eine Compose-Datei. 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 Dienste. core ist SearXNG selbst, und valkey ist ein In-Memory-Datenspeicher, der die Ratenbegrenzung und kurzlebigen Status verwaltet. Die Datei bindet ./core-config/ unter /etc/searxng/ in den Container ein. Dadurch befindet sich die gesamte Konfiguration in diesem einen Verzeichnis auf dem Host.
Bearbeiten Sie nun .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 ihre Werte.
SEARXNG_VERSION=latest
SEARXNG_HOST=127.0.0.1
SEARXNG_PORT=8080SEARXNG_HOST=127.0.0.1 ist die entscheidende Einstellung. Sie bindet den veröffentlichten Port an 127.0.0.1:8080:8080 statt an ein nicht näher bestimmtes 8080:8080. Docker veröffentlicht diesen an jeder Adresse. Dadurch antwortet der Container nur an der Loopback-Adresse, und das Internet kann ihn nicht direkt erreichen. Wenn Sie diese Einstellung auslassen, ist der Container sofort nach dem Start erreichbar, weil ein veröffentlichter Docker-Port vor Ihren Firewall-Regeln eingefügt wird. Diese Fehlerquelle sollten Sie vollständig lesen: Veröffentlichte Docker-Ports umgehen ufw.
SEARXNG_VERSION=latest ist während der Einarbeitung in Ordnung. Auf einem Server, der Ihnen wichtig ist, sollten Sie den Tag festlegen. Im Oktober 2026 basieren die Release-Tags auf dem Datum und sehen wie 2026.10.4-d48c4b555 aus. Bei einer festgelegten Version wird die Bereitstellung aktualisiert, wenn Sie das entscheiden, und nicht, wenn sich das Registry-Image unbemerkt ändert. Dieselbe Disziplin ist für alle anderen Dienste sinnvoll, die langfristig auf dem Server laufen. Deshalb legt auch ein selbst gehostetes RustDesk-Relay seine Image-Tags fest: Ein unbeaufsichtigtes Upgrade eines Remotezugriffsdienstes macht sich im ungünstigsten Moment bemerkbar.
settings.yml: die wichtigen Abschnitte
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 gesetzten Schlüssel anzuwenden. Dadurch bleibt Ihre Datei kurz und übersteht Upgrades, die neue Optionen hinzufügen.
Generieren Sie zuerst das Secret, weil 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 Token-Daten. Der mitgelieferte Standardwert ist die Zeichenfolge ultrasecretkey. Wenn Sie sie unverändert lassen, kann jeder, der diesen Standardwert kennt, diese Token fälschen. Ersetzen Sie den Wert einmal und ändern Sie ihn danach nicht mehr. Eine spätere Änderung verwirft alle gespeicherten Einstellungen.
base_url muss die öffentliche HTTPS-Adresse mit abschließendem Schrägstrich enthalten. SearXNG verwendet sie für die Links, die es rendert. Wenn sie auf localhost zeigt, verweist der Link zur „nächsten Seite“ in einem entfernten Browser auf den Rechner des Lesers und schlägt fehl.
formats legt fest, welche Ausgabetypen der Web-Endpunkt liefert. json ist nicht in der Standardliste enthalten. Eine JSON-Anfrage liefert daher 403, bis Sie den Typ hinzufügen. image_proxy: true leitet Vorschaubilder von Ergebnissen über Ihren Server weiter. Die Websites, auf denen diese Bilder liegen, sehen dadurch die Adressen Ihrer Besucher nicht.
Der valkey.url verwendet den Hostnamen valkey, weil dies der Servicename in der Compose-Datei ist. Compose platziert beide Container in einem Netzwerk, in dem Servicenamen aufgelöst werden. Wenn Sie auf localhost verweisen, schlägt der Limiter fehl, weil localhost innerhalb des Containers core auf diesen Container selbst zeigt.
Das Secret liegt in einer einfachen Datei. Schützen Sie daher auch das übergeordnete Verzeichnis. chmod 750 /opt/searxng hält andere Benutzer auf dem Host fern. Sie können core-config/settings.yml außerdem auf den Modus 600 setzen, ohne etwas zu beschädigen: Der Entrypoint des offiziellen Containers startet als root. Wenn FORCE_OWNERSHIP den Standardwert true behält, übergibt der Entrypoint das eingebundene Konfigurationsverzeichnis vor dem Start von SearXNG an den containerinternen Benutzer searxng. Dadurch bleibt die Datei für diesen Benutzer lesbar. Die Auswirkung ist auf dem Host sichtbar: Dieser Schritt ändert den Eigentümer von core-config/ in die Benutzer-ID des Containers. Rechnen Sie daher damit, die Datei anschließend mit sudo zu bearbeiten.
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 im Zustand running anzeigen. Der curl sollte auf HTTP/1.1 200 OK antworten. Wenn er keine Antwort liefert, lesen Sie docker compose logs core. Ein YAML-Fehler in settings.yml erscheint dort als Parse-Fehler mit Angabe der betroffenen Zeile.
Nginx mit TLS davorschalten
Der Container lauscht nur auf Loopback. Nginx macht ihn erreichbar und stellt außerdem die Transportsicherheit (TLS) bereit. 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 um, damit sie auf Port 443 mit einem Zertifikat lauscht, und fügt eine Weiterleitung von Port 80 hinzu. Der DNS-Eintrag für search.example.com muss bereits auf diesen Server zeigen. Die Zertifizierungsstelle weist den Besitz nach, indem sie eine Datei über HTTP abruft. Die vollständige Anleitung einschließlich der Erneuerung finden Sie im Certbot- und nginx-Leitfaden für Ubuntu 24.04.
Die beiden Weiterleitungsheader sind nicht nur Zierde. Ohne X-Forwarded-For und X-Real-IP enthält jede bei SearXNG eintreffende Anfrage die Proxy-Adresse. Dadurch sieht der Rate Limiter 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 liefert 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 Link-Checker oder eine Recherche-Schleife zu versorgen. Diese Ergebnisse an ein Sprachmodell zu übergeben, ist ein größerer Schritt, als es zunächst scheint, da Suchergebnisse nicht vertrauenswürdiger Text sind und eigene Anweisungen enthalten können. Genau damit befasst sich einen KI-Agent auf Ihre SearXNG-Instanz zu verweisen ausführlich.
Das ist für alles relevant, was agentenähnlich arbeitet. Ein Sprachmodell hat einen Trainingsstand. 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 häufig 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, führt dieselbe Überlegung zum Betrieb 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. Dasselbe gilt für den Endpunkt, an den ein selbst gehosteter Standort-Tracker die Position Ihres Telefons meldet. Fragen Sie die API anschließend mit angemessener Rate ab. SearXNG leitet Ihre Anfrage an echte Suchmaschinen weiter. Ein Skript mit hundert Abfragen pro Sekunde fordert Google daher geradezu auf, Ihren Server zu blockieren.
Der Limiter und die Änderungen für eine öffentliche Instanz
Der Limiter ist der Bot-Schutz von SearXNG. Er überwacht Request-Header, IP-Adressen sowie die Anfragerate und verwirft Datenverkehr, der automatisiert erscheint. Er benötigt Valkey, um diesen Status zu speichern; deshalb ist es in der Compose-Datei enthalten.
Auf einer privaten Instanz lassen Sie limiter: false auf false. Ihre eigenen Skripte sind per Definition automatisierter Datenverkehr, weshalb der Limiter genau die JSON-Aufrufe blockieren würde, für die Sie die Instanz erstellt haben. Die Zugriffskontrolle ist stattdessen Aufgabe des Reverse Proxys: ein allow- und deny-Paar in der nginx location, HTTP Basic Authentication oder eine Firewall, die nur Ihre anderen Server zulässt. Wenn Sie eine private Instanz von einem Laptop aus erreichen müssen, der zwischen Netzwerken wechselt, ist das Vorschalten einer v3-Onion-Adresse eine vierte Option, da Tor eine Verbindung zum selben Loopback-Port herstellt, ohne etwas Neues im Internet offenzulegen.
Wenn Sie die Instanz für andere Personen veröffentlichen, schalten Sie beide Optionen ein.
server:
limiter: true
public_instance: trueEine feinere Steuerung erfolgt in core-config/limiter.toml, das der Container unter /etc/searxng/limiter.toml einliest. Sie schreiben nur die Schlüssel hinein, die Sie ändern möchten. Hinter einem Proxy müssen Sie den Proxy deklarieren, da der Limiter sonst Ihre nginx-Adresse als den einen missbräuchlichen Client behandelt.
[botdetection]
trusted_proxies = [
'127.0.0.0/8',
'::1',
]
[botdetection.ip_limit]
link_token = truelink_token = true sorgt dafür, dass SearXNG ein Token ausgibt, das nur eine echte Browsersitzung abruft, was die meisten einfachen Scraper stoppt. Gehen Sie davon aus, dass eine öffentliche Instanz diese innerhalb weniger Tage anzieht. Rechnen Sie auch mit Engine-Fehlern, denn je mehr Datenverkehr Sie weiterleiten, desto eher beginnen Upstream-Engines, CAPTCHAs an Ihre Serveradresse zu senden. Eine öffentliche SearXNG-Instanz ist eine dauerhafte Aufgabe. Eine private Instanz ist das nicht, weshalb sie auf den meisten kurzen Listen von Dingen steht, die sich 2026 für das Self-Hosting lohnen. Nicht jeder Eintrag auf diesen Listen ist Infrastruktur: den Aufbau einer Jellyfin-Bibliothek als begehbaren Videoverleih der 90er Jahre realisieren Sie mit demselben Container hinter demselben nginx-Block, ausgerichtet auf einen gemütlichen Abend statt auf einen Workflow.
Warum Suchanfragen keine Ergebnisse liefern
Öffnen Sie /stats auf Ihrer Instanz. Dort werden alle Engines mit ihrer Fehlerrate und Antwortzeit aufgelistet. Das ist die erste Anlaufstelle, wenn die Ergebnisse unvollständig wirken.
Bei einer Engine mit Fehlern wie „Access denied“ oder „CAPTCHA“ wurde Ihre Serveradresse blockiert. Das kommt bei Adressen aus Rechenzentrumsbereichen häufig vor, weil Suchmaschinen davon ausgehen, dass diese zu Scraping-Diensten gehören. SearXNG setzt die fehlerhafte Engine dann für einen bestimmten Zeitraum aus, statt die Anfrage erneut zu senden. Dadurch fällt eine blockierte Engine unbemerkt aus Ihren Ergebnissen heraus. Deaktivieren Sie sie in settings.yml oder akzeptieren Sie den Verlust. Das sind nicht die einzigen Möglichkeiten, denn für manche CAPTCHA-Sperren gibt es eine Lösung, die einen Neustart übersteht. Die übrigen Engines antworten weiterhin. Ein 429-Fehler ist der uneindeutige Fall, weil er entweder von Ihrem eigenen Limiter oder von einer Upstream-Engine stammen kann, die Ihren Server ablehnt. Anhand der Logzeile erkennen Sie, welcher der beiden Fälle vorliegt, bevor Sie Einstellungen ändern.
Wenn alle Engines gleichzeitig fehlschlagen, verfügt der Container entweder über keine funktionierende ausgehende Namensauflösung oder über keine Route ins Internet. Testen Sie das innerhalb des Containers.
docker compose exec core wget -qO- https://duckduckgo.com > /dev/null && echo okAuf dem System wird nicht angezeigt, wann diese Prüfung fehlschlägt. Führen Sie sie daher über cron aus und lassen Sie einen Fehler eine Meldung von Ihrem eigenen ntfy-Server an Ihr Telefon senden, statt zu warten, bis Ihnen die unvollständigen Ergebnisse auffallen.
FAQ
Macht SearXNG meine Suchanfragen anonym?
SearXNG verbirgt Ihre Identität vor den abgefragten Suchmaschinen, weil diese Ihren Server als Absender der Anfrage sehen und nicht Ihren Browser. Vor Ihrem Server wird die Suchanfrage dadurch nicht verborgen, und auch Ihr Server bleibt für die Suchmaschinen sichtbar. Bei einer Instanz für einen einzelnen 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. Wie Sie gegenüber Ihrem ISP, dem Betreiber einer öffentlichen Instanz und den Suchmaschinen selbst dastehen, wird in was SearXNG tatsächlich verbirgt erläutert.
Warum liefert eine JSON-Anfrage 403 Forbidden zurück?
Dafür gibt es zwei Ursachen. Beide hängen mit der Konfiguration zusammen. Entweder fehlt json in der Liste formats unter search: in settings.yml. Das ist der Standardzustand. Oder der Limiter ist aktiviert und hat Ihr Script als Bot eingestuft. Fügen Sie zuerst das Format hinzu und starten Sie mit docker compose restart core neu. Versuchen Sie es anschließend 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 auch ohne den Container. Der Limiter kann jedoch später ohne ihn nicht aktiviert werden. Außerdem speichert der Container weiteren kurzlebigen Zustand. Der Container ist klein und speichert nur Cache-Daten. Seine Entfernung spart daher nur sehr wenig Speicherplatz und nimmt Ihnen diese Option.
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. Dadurch bleibt settings.yml erhalten. Da use_default_settings: true Ihre Schlüssel mit den ausgelieferten Standardwerten zusammenführt, werden neue Optionen aus Upstream-Versionen mit sinnvollen Werten übernommen, ohne 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 jedes Besuchers gespeichert. Deshalb müssen Sie keine Benutzerkonten verwalten. Überwachen Sie /stats eine Woche lang, nachdem Sie die Instanz freigegeben haben. Die Suchmaschinen beginnen, Ihren Server abzulehnen, lange bevor Ihnen fehlende Ergebnisse auffallen.