SearXNG zelf hosten met Docker Compose
Host uw eigen privé-zoekmachine met SearXNG op een VPS. Leer hoe u Docker Compose, settings.yml, nginx met TLS en de JSON API configureert voor veilige en snelle zoekresultaten.
Wat u bouwt
Het zelf hosten van SearXNG biedt u een privé-zoekmachine die op uw eigen server draait. SearXNG is een metazoekmachine: deze neemt uw zoekopdracht, vraagt andere zoekmachines zoals Google, Bing, DuckDuckGo en Wikipedia, en voegt de resultaten samen op één pagina. Er wordt geen profiel opgebouwd en er worden geen tracking-cookies geplaatst, omdat de enige machine die uw zoekopdracht bewaart, die van u is. Als u oudere handleidingen heeft gevonden voor een project genaamd Searx, dan is dat het project waar dit van is afgesplitst. Dat project heeft sinds 2023 geen commits meer ontvangen, dus controleer de status van beide voordat u er een volgt.
De stack is compact. Twee containers, één configuratiebestand, één reverse proxy. Het kan probleemloos op een kleine VPS draaien, wat niet voor elke zelf-gehoste service geldt: de fotobibliotheken die in PhotoPrism versus Immich worden vergeleken, bepalen hun minimale RAM-gebruik op basis van de indexeerder in plaats van de webapplicatie. De belangrijkste beslissing is of de instantie privé is, wat betekent dat alleen u en uw eigen scripts deze kunnen benaderen, of publiek, wat betekent dat iedereen op het internet er zoekopdrachten naar kan sturen. Die keuze beïnvloedt de beveiligingsinstellingen, dus bepaal dit voordat u begint met typen. Het standaardantwoord is privé.
Er is een tweede reden om er een te draaien. Een SearXNG-instantie spreekt JSON, waardoor elk script of elke AI-agent die u schrijft beschikt over een zoek-API die van u is, zonder API-key, zonder kosten per zoekopdracht en zonder quota-beperkingen.
SearXNG installeren met Docker Compose
Het project publiceert een container-image en een Compose-bestand. Haal beide op naar een verse Ubuntu 24.04-server waarop Docker Engine en de Compose-plugin al zijn geïnstalleerd. Als Docker nieuw voor u is, begin dan bij Docker Compose basics op een VPS en keer daarna terug.
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 .envHet Compose-bestand definieert twee services. core is SearXNG zelf en valkey is een in-memory datastore die wordt gebruikt voor rate limiting en tijdelijke statusinformatie. Het mount ./core-config/ op /etc/searxng/ in de container, waardoor alles wat u configureert in die ene map op de host blijft staan.
Bewerk nu .env. Elke regel in het meegeleverde voorbeeld is uitgeschakeld met commentaar, waardoor de container op elk adres op poort 8080 start. Haal de commentaartekens weg en stel deze drie in.
SEARXNG_VERSION=latest
SEARXNG_HOST=127.0.0.1
SEARXNG_PORT=8080SEARXNG_HOST=127.0.0.1 is de belangrijkste. Deze zorgt ervoor dat de gepubliceerde poort 127.0.0.1:8080:8080 is in plaats van [::]:8080:8080, zodat de container alleen antwoordt op het loopback-adres en het internet deze niet rechtstreeks kan bereiken. Slaat u dit over, dan is de container direct bij het opstarten blootgesteld, omdat een gepubliceerde Docker-poort vóór uw firewallregels wordt ingevoegd. Die valkuil is het volledig lezen waard: gepubliceerde Docker-poorten omzeilen ufw.
SEARXNG_VERSION=latest is prima terwijl u het systeem leert kennen. Op een server die u belangrijk vindt, moet u de tag vastzetten. Sinds juli 2026 zijn de release-tags gebaseerd op de datum en zien ze eruit als 2026.3.25-541c6c3cb, zodat een vastgezette implementatie pas upgradet wanneer u dat beslist, en niet wanneer de registry onder u verandert. Dezelfde discipline loont voor alles wat langdurig op de server draait; daarom zet een self-hosted RustDesk relay zijn image-tags ook vast: een onbeheerde upgrade van een service voor externe toegang kondigt zichzelf aan op het slechtst mogelijke moment.
settings.yml: de relevante onderdelen
Maak core-config/settings.yml aan vóór de eerste start. use_default_settings: true instrueert SearXNG om de meegeleverde standaardinstellingen te laden en vervolgens alleen de door u opgegeven sleutels toe te passen. Hierdoor blijft uw bestand kort en blijft het bruikbaar na upgrades die nieuwe opties toevoegen.
Genereer eerst het geheim, aangezien de waarde direct in het bestand moet worden geplaatst.
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 ondertekent sessie- en tokendata. De standaardwaarde is de letterlijke tekst ultrasecretkey. Als u deze laat staan, kan iedereen die deze standaardwaarde kent, tokens vervalsen. Vervang deze één keer en wijzig deze daarna niet meer: het later wijzigen ervan maakt alle opgeslagen voorkeuren ongeldig.
base_url moet het publieke HTTPS-adres zijn, inclusief de afsluitende slash. Dit is het adres dat SearXNG in de gegenereerde links plaatst. Als u dit op localhost laat staan, verwijst de "volgende pagina"-link in een externe browser naar de machine van de gebruiker zelf, wat tot een fout leidt.
formats bepaalt welke outputtypes het web-endpoint produceert. json staat niet in de standaardlijst, waardoor een JSON-verzoek een 403-foutmelding geeft totdat u dit toevoegt. image_proxy: true routeert resultaat-thumbnails via uw server, zodat de websites die deze afbeeldingen hosten nooit de IP-adressen van uw bezoekers zien.
De valkey.url gebruikt de hostnaam valkey omdat dit de servicenaam is in het Compose-bestand. Compose plaatst beide containers op hetzelfde netwerk waar servicenamen worden omgezet. Wijs dit naar localhost en de limiter faalt, omdat localhost binnen de core-container naar de container zelf verwijst.
Het geheim staat in een tekstbestand; beveilig daarom de map eromheen in plaats van het bestand zelf. chmod 750 /opt/searxng houdt andere gebruikers op de host buiten. Maak core-config/settings.yml niet strenger met modus 600: de container draait als een eigen gebruiker zonder privileges, en een bestand dat deze niet kan lezen, zorgt ervoor dat SearXNG helemaal niet start.
Start de stack en controleer deze.
cd /opt/searxng
docker compose up -d
docker compose ps
curl -I http://127.0.0.1:8080/docker compose ps hoort beide containers in de status running te tonen. De curl hoort HTTP/1.1 200 OK te antwoorden. Als er geen antwoord komt, lees dan docker compose logs core, aangezien een YAML-fout in settings.yml daar verschijnt als een parse-fout met vermelding van het regelnummer.
Plaats het achter nginx met TLS
De container luistert alleen op loopback, dus nginx maakt de service bereikbaar en voegt transport layer security (TLS) toe. Schrijf /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 toont syntax is ok en test is successful voordat u de configuratie opnieuw laadt. Certbot herschrijft hetzelfde bestand om op poort 443 te luisteren met een certificaat en voegt een redirect toe vanaf poort 80. Het DNS-record voor search.example.com moet al naar deze server verwijzen, omdat de certificaatautoriteit het eigendom verifieert door een bestand via HTTP op te halen. De volledige handleiding, inclusief vernieuwing, staat in de Certbot en nginx handleiding voor Ubuntu 24.04.
De twee forwarding-headers zijn geen overbodige toevoeging. Zonder X-Forwarded-For en X-Real-IP draagt elk verzoek dat bij SearXNG aankomt het adres van de proxy, waardoor de rate limiter één client ziet die al het verkeer genereert en geen onderscheid kan maken tussen bezoekers.
Waarom scripts en agents een JSON-zoek-API vereisen
Met json in formats retourneert hetzelfde eindpunt dat de pagina rendert ook gestructureerde data.
curl -s 'http://127.0.0.1:8080/search?q=wireguard+mtu&format=json' \
| jq -r '.results[0:5][] | .url'U ontvangt een object met een results-array, waarbij elk item url, title, content en de engine die het resultaat leverde bevat, naast answers, infoboxes en suggestions. Dat is voldoende om een samenvattingsfunctie, een link-checker of een onderzoekslus te voeden. Het doorgeven van deze resultaten aan een taalmodel is een grotere stap dan het lijkt, aangezien zoekresultaten niet-vertrouwde tekst zijn die eigen instructies kunnen bevatten. Dit is wat het koppelen van een AI-agent aan uw SearXNG-instantie in detail behandelt.
Dit is van belang voor alles wat de vorm van een agent heeft. Een taalmodel heeft een trainingsdatum in het verleden, dus heeft het live zoekopdrachten nodig om vragen over het heden te beantwoorden, en commerciële zoek-API's rekenen per query en hanteren strikte rate limits. Een lokale instantie kost één container op een server waar u al voor betaalt, en de zoekopdrachten verlaten de server nooit. Als u tools koppelt aan een model, volgt dezelfde redenering voor het draaien van MCP-servers op een VPS, waarbij een zoektool meestal de eerste is die wordt toegevoegd.
Twee regels voor API-gebruik. Houd de instantie privé; bind de API-zijde aan het loopback-adres of aan een privénetwerk en sta alleen toe dat uw eigen hosts deze bereiken. Voer zoekopdrachten daarnaast voorzichtig uit. SearXNG stuurt uw verzoek door naar echte zoekmachines, dus een script dat honderd zoekopdrachten per seconde uitvoert, vraagt erom dat Google uw server blokkeert.
De limiter, en wat er verandert voor een publieke instantie
De limiter is de bot-beveiliging van SearXNG. Deze houdt request-headers, IP-adressen en de frequentie van verzoeken in de gaten en blokkeert verkeer dat er geautomatiseerd uitziet. Hiervoor is Valkey nodig om de status bij te houden, wat de reden is dat het Compose-bestand dit meelevert.
Houd op een privé-instantie limiter: false aan. Uw eigen scripts zijn per definitie geautomatiseerd verkeer, waardoor de limiter precies de JSON-aanroepen zou blokkeren waarvoor u de instantie heeft opgezet. Toegangscontrole is in plaats daarvan de taak van de reverse proxy: een allow en deny paar in de nginx location, HTTP basic authentication, of een firewall die alleen uw andere servers toelaat. Als u een privé-instantie wilt bereiken vanaf een laptop die tussen netwerken wisselt, is het plaatsen van een v3 onion-adres ervoor een vierde optie, omdat tor verbinding maakt met dezelfde loopback-poort zonder iets nieuws bloot te stellen aan het internet.
Als u de instantie wel openstelt voor anderen, schakel dan beide opties in.
server:
limiter: true
public_instance: trueFijner beheer vindt plaats in core-config/limiter.toml, dat de container inleest op /etc/searxng/limiter.toml. U schrijft alleen de keys die u wilt wijzigen. Achter een proxy moet u de proxy declareren, anders behandelt de limiter uw nginx-adres als de enige misbruikende client.
[botdetection]
trusted_proxies = [
'127.0.0.0/8',
'::1',
]
[botdetection.ip_limit]
link_token = truelink_token = true zorgt ervoor dat SearXNG een token uitgeeft dat alleen door een echte browsersessie wordt opgehaald, wat de meeste eenvoudige scrapers stopt. Ga ervan uit dat een publieke instantie binnen enkele dagen scrapers aantrekt. Verwacht ook engine-fouten, want hoe meer verkeer u doorstuurt, hoe sneller upstream-engines CAPTCHAs gaan retourneren naar uw serveradres. Een publieke SearXNG-instantie is een doorlopende taak. Een privé-instantie is dat niet, en daarom staat het op de meeste korte lijsten van dingen die de moeite waard zijn om in 2026 zelf te hosten. Niet elk item op die lijsten is infrastructuur: het ombouwen van een Jellyfin-bibliotheek tot een beloopbare videotheek uit de jaren 90 is dezelfde container achter hetzelfde nginx-blok, gericht op een avondje ontspanning in plaats van een workflow.
Waarom zoekopdrachten geen resultaten opleveren
Open /stats op uw instantie. Hierin staan alle engines met hun foutpercentage en responstijd; dit is de eerste plek om te kijken wanneer resultaten achterblijven.
Een engine met de foutmelding "Access denied" of "CAPTCHA" heeft het adres van uw server geblokkeerd. Dat komt vaak voor bij adressen in datacenterranges, omdat zoekmachines aannemen dat deze bij scrapers horen. SearXNG schort de betreffende engine vervolgens tijdelijk op in plaats van de aanvraag opnieuw uit te voeren. Daardoor verdwijnt een geblokkeerde engine ongemerkt uit uw resultaten. Schakel deze uit in settings.yml of accepteer dat verlies. Dat zijn niet de enige opties, omdat voor sommige CAPTCHA-blokkades een oplossing bestaat die ook na een herstart blijft werken. De overige engines blijven antwoorden. Een 429 is het onduidelijke geval. Deze status kan afkomstig zijn van uw eigen limiter of van een upstream-engine die uw server weigert. De logregel laat zien met welke van deze twee situaties u te maken hebt voordat u instellingen gaat wijzigen.
Als elke engine tegelijkertijd faalt, heeft de container geen werkende uitgaande naamresolutie of geen route naar het internet. Test dit vanuit de container.
docker compose exec core wget -qO- https://duckduckgo.com > /dev/null && echo okNiets op de server geeft aan wanneer die controle begint te falen, dus voer deze uit via cron en laat een foutmelding via uw eigen ntfy-server naar uw telefoon sturen in plaats van te wachten tot u merkt dat de resultaten zijn afgenomen.
FAQ
Maakt SearXNG mijn zoekopdrachten anoniem?
Het verbergt uw identiteit voor de zoekmachines die het bevraagt, omdat zij uw server het verzoek zien doen in plaats van uw browser. Het verbergt de zoekopdracht niet voor uw server, en het verbergt uw server niet voor hen. Op een instance voor één gebruiker is al het verkeer vanaf dat adres van u, waardoor het adres zelf de identificator wordt. Verkeer tussen uw browser en uw instance wordt beschermd door het TLS-certificaat. Wat dit betekent voor uw positie ten opzichte van uw ISP, de beheerder van een publieke instance en de zoekmachines zelf, wordt behandeld in wat SearXNG daadwerkelijk verbergt.
Waarom geeft een JSON-verzoek een 403 Forbidden foutmelding?
Er zijn twee oorzaken, en beide hebben te maken met de configuratie. Ofwel ontbreekt json in de formats-lijst onder search: in settings.yml, wat de standaardinstelling is, of de limiter is ingeschakeld en heeft uw script geclassificeerd als een bot. Voeg het formaat toe, herstart met docker compose restart core en probeer het opnieuw. Als het nog steeds niet werkt, stel dan limiter: false in en beheer de toegang via de reverse proxy.
Heb ik de Valkey-container nodig als ik de limiter uitgeschakeld laat?
Laat deze draaien. SearXNG werkt zonder, maar de limiter kan later niet worden ingeschakeld zonder deze container, en hij bevat ook andere tijdelijke statusinformatie. De container is klein en slaat alleen gecachte gegevens op, dus verwijderen levert nauwelijks winst op en ontneemt u de mogelijkheid om de limiter later te gebruiken.
Hoe update ik SearXNG?
Voer docker compose pull uit en vervolgens docker compose up -d in /opt/searxng. Compose maakt elke container opnieuw aan waarvan de image is gewijzigd en laat uw core-config/-map ongemoeid, waardoor settings.yml behouden blijft. Omdat use_default_settings: true uw sleutels samenvoegt met de standaardinstellingen, worden opties die upstream worden toegevoegd voorzien van zinvolle waarden in plaats van dat het bestand corrupt raakt.
Kunnen meerdere mensen één instance delen?
Ja, en dat is het scenario waarin u de limiter inschakelt en public_instance: true instelt. Voorkeuren worden opgeslagen in de browser van elke bezoeker zelf, dus er zijn geen accounts om te beheren. Monitor /stats gedurende een week nadat u de instance heeft opengesteld, omdat upstream-zoekmachines uw server al lang beginnen te blokkeren voordat u merkt dat er resultaten ontbreken.