Hister zelf hosten: uw eigen persoonlijke zoekmachine
Hister zelf hosten op een VPS voor het doorzoeken van uw volledige browsergeschiedenis en bestanden. Leer hoe u Docker instelt, TLS configureert en het MCP endpoint gebruikt.
Wat Hister is, en wat het niet is
Hister is een persoonlijke zoekmachine die u zelf host. Het indexeert de volledige tekst van de pagina's die u heeft bezocht en de bestanden die u bewaart, waarna u die verzameling kunt doorzoeken via een webinterface, een terminal-client, een HTTP API of een AI-assistent (artificiële intelligentie). Hister beantwoordt één vraag: waar heb ik dat gelezen.
De meeste lezers maken via SearXNG kennis met dit concept. De twee zijn niet dezelfde tool. Als de naam die u kent Searx is, heeft dat project sinds 2023 geen codecommit meer ontvangen en bouwt SearXNG daarop voort, waardoor een nieuwe instance die u vandaag opzet in beide gevallen SearXNG is. SearXNG is een metasearch-proxy. U stuurt uw zoekopdracht naar SearXNG. Het vraagt namens u andere zoekmachines om resultaten en geeft die terug zonder trackinggegevens. De index is eigendom van die zoekmachines. Hister bouwt zijn eigen index op uit inhoud die u aanlevert: pagina's die met een browserextensie zijn vastgelegd, geïmporteerde browsergeschiedenis, gecrawlde URL's en bestanden in mappen die u aanwijst. Een zelfgehoste SearXNG-instance geeft u privétoegang tot het openbare web. Hister biedt zoeken in uw eigen leesgeschiedenis. De functies verschillen, dus het is normaal om beide op één server te draaien. Als u dat doet, is het goed om te weten hoeveel van uw zoekactiviteiten SearXNG daadwerkelijk afschermt, omdat het uw IP-adres bij de zoekmachines vervangt door dat van uw server en niet de zoekopdrachten zelf verbergt.
Hister is vrije software onder de AGPLv3 (GNU Affero General Public License, versie 3) of later. Het bevat geen telemetrie en vereist geen cloudservice. Deze handleiding is gebaseerd op versie v0.17.0, de huidige release op 2026-07-28. Controleer de releases-pagina voor de actuele tag voordat u commando's kopieert, en gebruik vervolgens de tag die u daar vindt.
Waarom Hister zelf hosten op een VPS
Een index is alleen nuttig als deze volledig is, en hij is alleen volledig als de server actief was terwijl u aan het lezen was. Een laptop slaapt de helft van de dag. Pagina's die u gedurende die tijd op uw telefoon opent, bereiken de server nooit en een import die 's nachts moet draaien, start niet. Een VPS (virtual private server) blijft altijd actief, waardoor elk apparaat dat u bezit naar dezelfde index schrijft en de crawler blijft werken terwijl u slaapt.
De tweede reden is scheiding. Door user_handling: true in te stellen in de app sectie krijgt elk account zijn eigen inloggegevens en zijn eigen documentverzameling op één instantie. Eén server kan dan dienstdoen voor een huishouden of een klein team, zonder dat iemand in de leesgeschiedenis van een ander kan zoeken.
De derde reden is de infrastructuur. De VPS heeft al een publieke hostnaam en een certificaat. Daarmee kan de browserextensie de server bereiken vanaf een netwerk dat u niet beheert. Deze combinatie wordt elders op de server opnieuw gebruikt, omdat openGym de eerste passkey registreert tegen de hostnaam die op dat moment actief is. Daarom moeten de naam en het certificaat zijn vastgesteld voordat u het eerste account aanmaakt.
Installatiepad één: het release-binary
Hister levert één binary per platform. Download deze samen met het checksum-bestand en verifieer het bestand vóór de installatie.
cd /tmp
curl -LO https://github.com/asciimoo/hister/releases/download/v0.17.0/hister_0.17.0_linux_amd64
curl -LO https://github.com/asciimoo/hister/releases/download/v0.17.0/hister_0.17.0_checksums.txt
sha256sum --ignore-missing -c hister_0.17.0_checksums.txtEen correct resultaat is de enkele regel hister_0.17.0_linux_amd64: OK. Een FAILED-regel betekent dat de download beschadigd of gewijzigd is; download het bestand opnieuw in plaats van het te installeren.
Installeer de binary en maak vervolgens een systeemaccount en de bijbehorende mappen aan.
sudo install -m 755 /tmp/hister_0.17.0_linux_amd64 /usr/local/bin/hister
sudo useradd --system --home-dir /var/lib/hister --shell /usr/sbin/nologin hister
sudo install -d -o hister -g hister -m 750 /var/lib/hister
sudo install -d -m 755 /etc/hister
sudo hister create-config /etc/hister/config.ymlcreate-config schrijft een standaardconfiguratiebestand en toont tevens aan dat de binary op deze machine draait. Een download voor de verkeerde architectuur faalt hier direct met cannot execute binary file: Exec format error.
Pas de enkele instellingen aan die van belang zijn. De rest van het gegenereerde bestand kan ongewijzigd blijven.
app:
directory: /var/lib/hister
access_token: 'paste-a-long-random-string-here'
server:
address: 127.0.0.1:4433
base_url: https://hister.example.comGenereer het token met openssl rand -hex 32. Het bestand bevat nu een inloggegeven, dus beperk de toegangsrechten voordat de service wordt gestart.
sudo chown root:hister /etc/hister/config.yml
sudo chmod 640 /etc/hister/config.ymlUitvoeren onder systemd
Schrijf /etc/systemd/system/hister.service:
[Unit]
Description=Hister personal search engine
After=network-online.target
Wants=network-online.target
[Service]
User=hister
Group=hister
Environment=HISTER_CONFIG=/etc/hister/config.yml
ExecStart=/usr/local/bin/hister listen
Restart=on-failure
NoNewPrivileges=yes
PrivateTmp=yes
ProtectSystem=strict
ProtectHome=yes
ReadWritePaths=/var/lib/hister
[Install]
WantedBy=multi-user.targetHISTER_CONFIG is de gedocumenteerde omgevingsvariabele voor het configuratiepad, zodat de unit niet afhankelijk is van de home-directory van het hister-account. ProtectSystem=strict maakt het volledige bestandssysteem alleen-lezen voor deze service, wat de reden is dat ReadWritePaths de datadirectory moet benoemen. ProtectHome=yes verbergt /home voor de service, waardoor een geobserveerde directory onder /home leeg lijkt voor de indexer. Verwijder die regel als u bestanden op die locatie moet indexeren.
sudo systemctl daemon-reload
sudo systemctl enable --now hister
systemctl status hister --no-pager
curl -sS -o /dev/null -w '%{http_code}\n' http://127.0.0.1:4433/Elke HTTP-statuscode die door dat laatste commando wordt getoond, betekent dat het proces luistert. curl: (7) Failed to connect betekent dat dit niet het geval is, en journalctl -u hister -n 50 --no-pager geeft aan waarom.
Installatiepad twee: Docker Compose
De image is gepubliceerd op de GitHub container registry, met één tag per release.
services:
hister:
image: ghcr.io/asciimoo/hister:v0.17.0
container_name: hister
user: '1000:1000'
restart: unless-stopped
environment:
- HISTER__SERVER__ADDRESS=0.0.0.0:4433
- HISTER__SERVER__BASE_URL=https://hister.example.com
- HISTER__APP__ACCESS_TOKEN=${HISTER_ACCESS_TOKEN}
volumes:
- ./data:/hister/data
ports:
- 127.0.0.1:4433:4433Elke configuratiesleutel heeft een environment override in de vorm HISTER__<SECTION>__<KEY>, met twee underscores als scheidingsteken, waardoor een container-deployment geen gemount configuratiebestand vereist. Bewaar HISTER_ACCESS_TOKEN in een .env-bestand naast het compose-bestand. Als u liever een bestand bewerkt, print docker run --rm ghcr.io/asciimoo/hister:v0.17.0 create-config > config.yml de standaardwaarden.
De twee bovenstaande regels worden vaak verkeerd begrepen en zijn beide belangrijk om te doorgronden.
Het adres binnen de container moet 0.0.0.0:4433 zijn. Een container heeft een eigen netwerk-namespace, waardoor een proces dat daar aan 127.0.0.1 is gebonden, alleen van binnenuit die container bereikbaar is en de gepubliceerde poort niets heeft om naar door te sturen.
De gepubliceerde poort wordt geschreven als 127.0.0.1:4433:4433, niet 4433:4433. Docker publiceert poorten door eigen netfilter-regels in te voegen, en die regels worden geëvalueerd vóór de ufw-regels. Hierdoor blijft een standaard 4433:4433 bereikbaar vanaf het internet, zelfs op een server waar ufw status aangeeft dat de poort gesloten is. Door de host-zijde aan 127.0.0.1 te binden, blijft de reverse proxy de enige toegangsweg. Dezelfde valkuil geldt voor elke container op de server, en Docker Compose op een VPS behandelt de rest van dit onderwerp.
De standaard image draait als UID 1000 en GID 1000, dus ./data moet schrijfbaar zijn voor dat account, anders stopt de container bij het opstarten met een permissiefout. sudo chown -R 1000:1000 ./data lost dit op. Als deze getallen onbekend zijn, lees dan eerst met welke UID en GID een container bestanden schrijft.
Waarom een persoonlijke zoekindex de slechtste service is om bloot te stellen
Hister luistert standaard op 127.0.0.1:4433, en die standaardinstelling is bewust gekozen. Denk na over wat de index na een maand gebruik bevat: interne wiki-pagina's, facturen, supporttickets die u opende terwijl u ingelogd was, pagina's voor het opnieuw instellen van wachtwoorden en de volledige tekst van alles wat u verder leest. De projectdocumentatie stelt het direct: "Hister verzendt uw volledige browsegeschiedenis, inclusief pagina-inhoud, van en naar de server."
Een gelekte wachtwoorddatabase moet nog worden gekraakt. Een gelekte persoonlijke index is platte tekst en al doorzoekbaar, dus deze vereist meer zorg dan de kleine zelfgehoste applicatie waar het op lijkt.
Hieruit volgen twee feiten. Hister vereist standaard geen authenticatie, dus een reverse proxy publiceert op zichzelf een doorzoekbare kopie van uw leesgedrag aan iedereen die de hostnaam achterhaalt. Het MCP-eindpunt wordt ook standaard aangeboden op /mcp, en zonder token kan elke client die dit bereikt een zoekopdracht uitvoeren op de index.
Configureer authenticatie voordat de service voor het eerst localhost verlaat. Een enkele gebruiker heeft alleen app.access_token nodig, één gedeeld geheim dat wordt verzonden door de browserextensie, de terminal-client en elke MCP-client. Voor meerdere personen stelt u user_handling: true in en maakt u accounts aan:
sudo -u hister hister create-user alice --admin --config /etc/hister/config.ymlHet commando vraagt om een wachtwoord van minimaal 8 tekens. Elk account krijgt zijn eigen documenten en een persoonlijk API-token, dat de eigenaar kan vernieuwen vanaf de profielpagina of met de --regen-token-vlag op hister update-user. Het genereren van een nieuw token maakt het vorige onmiddellijk ongeldig, dus elk apparaat dat dat account gebruikt, moet daarna worden bijgewerkt.
Laat app.public ongewijzigd, tenzij u zeker weet wat u doet. De publieke modus staat niet-geauthenticeerd zoeken, previews, bestandsservering en MCP-zoeken toe, terwijl schrijfacties, toegang tot de geschiedenis en beheerdersfuncties geblokkeerd blijven.
Reverse proxy, TLS en de firewall
Hister biedt zelf geen HTTPS aan, dus beëindig TLS (transport layer security) vóór de applicatie. Caddy is de kortste weg, omdat deze zelfstandig certificaten aanvraagt en vernieuwt via ACME (automatic certificate management environment).
hister.example.com {
reverse_proxy 127.0.0.1:4433
}Herlaad de configuratie met sudo systemctl reload caddy. Er moet aan twee voorwaarden worden voldaan voordat een certificaat kan worden uitgegeven: het A-record voor hister.example.com moet naar deze server wijzen en poort 80 moet openstaan, omdat de HTTP-01 challenge daar wordt beantwoord. Wanneer een van beide ontbreekt, krijgt de browser een TLS-fout in plaats van de pagina en herhaalt het Caddy-logboek de mislukte challenge.
Sluit vervolgens alle overige poorten.
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw statusPoort 4433 ontbreekt bewust in die lijst. Een publieke hostnaam is bovendien niet de enige toegangsweg; een onion service die naar dezelfde loopback-poort wijst bereikt uw index vanaf uw eigen apparaten zonder dat er een DNS-record of een inkomende poort open hoeft te staan.
server.base_url moet overeenkomen met het adres dat u in de browser typt, inclusief het schema. Wanneer dit niet overeenkomt, laadt de interface met onopgemaakte tekst en ontbrekende afbeeldingen, omdat de server de asset-links opbouwt op basis van base_url en de browser deze vervolgens opvraagt bij een bron die niet antwoordt. Diezelfde URL wordt in de browserextensie ingevoerd.
De index vullen
De browserextensie is de voornaamste verzamelaar. Installeer deze via Mozilla Add-ons of de Chrome Web Store, open de optiepagina, stel de server-URL in op https://hister.example.com en plak het toegangstoken. De extensie legt vervolgens de titel, volledige tekst, HTML en favicon van elke bezochte pagina vast en verstuurt deze naar uw server. Extractie vindt plaats aan de clientzijde, binnen de browser. De extensie neemt geen contact op met derden; het enige externe verzoek dat wordt gedaan, is voor het ophalen van de favicon van de pagina.
Extractie aan de clientzijde maakt een privé-index mogelijk. De extensie ziet een pagina precies zoals u deze ziet, na het inloggen en na het renderen. Hierdoor worden interne wiki-pagina's of betaalde artikelen correct geïndexeerd en hoeft uw server nooit over inloggegevens te beschikken. Dit betekent ook dat alles wat u bekijkt een kandidaat is voor de index, wat de reden is dat uitsluitingsregels (skip rules) voorrang hebben op het toevoegen van inhoud.
Uitsluitingsregels staan in rules.json bij een installatie voor één gebruiker, of per gebruiker in de database. Het tabblad Rules in de webinterface is de eenvoudigste manier om deze te bewerken. Het zijn Go-reguliere expressies die worden getoetst aan de volledige URL:
^https://mail\.example\.com
^https://bank\.example\.com
.*?utm_source=Een patroon zoals ^mail.example.com komt nooit overeen, omdat de geteste tekenreeks begint met https://. Een afsluitende $ faalt eveneens op elke URL met een query-string, aangezien query-parameters behouden blijven tijdens het matchen.
Bestaande geschiedenis wordt geïmporteerd door de eigen database van de browser uit te lezen. Dit commando moet daarom worden uitgevoerd op de machine waar het browserprofiel staat, oftewel uw laptop en niet de VPS. Installeer daar hetzelfde binaire bestand en verwijs naar de server:
export HISTER_TOKEN='your-access-token'
hister import browser firefox -u https://hister.example.com -t "$HISTER_TOKEN"Een import draait als een hervatbare taak genaamd browser-import-YYYY-MM-DD, waardoor u deze kunt onderbreken en later opnieuw kunt starten. Bladwijzerservices worden op dezelfde manier geïmporteerd, waaronder Linkwarden, Karakeep, Wallabag, Linkding, Readeck en Shaarli. Een herhaalde import haalt alleen de gegevens op die nieuwer zijn dan de vorige import.
Bestanden op de server worden geïndexeerd door mappen op te geven in de configuratie:
indexer:
directories:
- path: '/var/lib/hister/documents'
label: 'documents'
filetypes: ['pdf', 'docx', 'md', 'txt']PDF-, DOCX-, Markdown-, Org-mode- en geldige UTF-8-tekstbestanden worden als volledige tekst gelezen. Foto's en video's staan niet op die lijst; een fotobibliotheek vereist een server die gezichten, locaties en datums indexeert in plaats van tekst. PhotoPrism en Immich zijn de twee die doorgaans voor die taak worden vergeleken. Een enkele pagina wordt toegevoegd met hister index https://example.com. Het omzetten van volledige websites naar schone tekst voor andere tools is een afzonderlijke taak, die wordt afgehandeld door self-hosted crawlers die pagina's omzetten naar schone tekst.
Zoeken is gebaseerd op velden, dus het loont om tien minuten te besteden aan het lezen van de querytaal:
"connection reset" domain:github.com added:<30d
title:(wireguard|nftables) -tutorial sort:-visitsWijs een coding agent naar uw eigen index via MCP
MCP (model context protocol) is de interface die een assistent gebruikt om tools op een server aan te roepen. Hister biedt deze aan op POST /mcp onder dezelfde basis-URL, via het streamable HTTP-transport, en stelt search, get_preview en get_history beschikbaar. Voor authenticatie wordt hetzelfde bearer-token gebruikt als voor de rest van de API. Als het aanroepen van tools nieuw voor u is, is zelf een kleine agentlus schrijven de snelste manier om te zien welke gegevens een endpoint zoals dit daadwerkelijk aan een assistent doorgeeft.
{
"mcpServers": {
"hister": {
"url": "https://hister.example.com/mcp",
"headers": {
"Authorization": "Bearer YOUR_ACCESS_TOKEN"
}
}
}
}Een X-Access-Token-header werkt als alternatief voor Authorization.
De waarde hiervan zit in wat de agent doorzoekt. Een open webzoekopdracht retourneert wat vandaag hoog scoort; voor snel veranderende software is dat vaak documentatie voor een versie die u niet draait. Uw eigen index retourneert de pagina die u al heeft gelezen en heeft bewaard, en get_preview serveert de opgeslagen kopie, waardoor het antwoord behouden blijft als de oorspronkelijke pagina offline gaat. Geef de agent beide bronnen als u ook publieke resultaten wilt: een browserzoekfunctie ondersteund door SearXNG voegt het open web toe als een aparte tool. Zodra u meer dan één van deze endpoints draait, is het hosten van MCP-servers op een VPS het lezen waard, omdat ze allemaal dit blootstellingsprobleem delen.
Schijfgebruik, back-ups en onderhoud
De documentatie schat één geïndexeerde pagina op ongeveer 100 KB, inclusief het gecomprimeerde voorbeeld, dus honderdduizend pagina's beslaan ongeveer 10 GB. Er is geen quotumsysteem. Twee instellingen worden vaak verward: indexer.max_file_size_mb (standaard 1 MiB) beperkt een enkel geobserveerd bestand, en server.max_batch_body_size (standaard 40 MiB) beperkt één API-verzoek.
De map die wordt aangeduid door app.directory bevat index.db met de indexbestanden per taal, db.sqlite3 voor accounts en taken, data/html/ voor voorbeelden, en rules.json. Een back-up bestaat uit een gestopte service en een kopie van die volledige map en het configuratiebestand. hister export backup.json schrijft documenten als JSON voor migratiedoeleinden; dit is geen back-up van de server.
Twee onderhoudscommando's zijn van belang. hister reindex herbouwt de zoekindexen, wat vereist is na het wijzigen van indexeerinstellingen. Als het geheugengebruik stijgt tijdens een grote import, stel dan detect_languages: false in binnen de indexer sectie en voer de indexering opnieuw uit. hister cleanup verwijdert verweesde voorbeeld- en favicon-bestanden die zijn achtergebleven na verwijderingen.
Verwijderen is een query, voer deze daarom eerst uit in de dry-run modus:
hister delete 'domain:example.com' --dry --verboseEen verwijderde pagina keert terug als een collector deze opnieuw indient; voeg daarom de skip-regel toe voordat u tot verwijdering overgaat.
De AGPLv3 is alleen relevant als u de code wijzigt. Het draaien van een ongewijzigde kopie voor eigen gebruik brengt geen verplichtingen met zich mee. Als u Hister aanpast en anderen uw versie via een netwerk laat gebruiken, vereist de licentie dat u hen uw aangepaste broncode aanbiedt.
Foutmodi en de meldingen die u zult zien
De server start niet. Of poort 4433 is al in gebruik, of het configuratiebestand bevat een YAML-syntaxfout. sudo ss -lntp | grep 4433 toont welk proces de poort bezet houdt en journalctl -u hister -n 50 --no-pager geeft de parse-fout weer.
De interface laadt, maar ziet er defect uit. Door elkaar lopende tekst en ontbrekende afbeeldingen betekenen dat server.base_url niet overeenkomt met de URL in de adresbalk. Een afsluitende slash telt als een mismatch.
De extensie maakt geen verbinding. De server-URL in de extensie moet gelijk zijn aan base_url, de server moet actief en up-to-date zijn, en een firewall daartussen blokkeert de verbinding zonder melding op de pagina. Firefox houdt extensielogs buiten de normale console: open about:debugging#/runtime/this-firefox en inspecteer de Hister-extensie.
De container stopt direct bij het opstarten. Een rechtenfout op ./data betekent dat de map eigendom is van een andere UID dan 1000, wat het account is binnen de standaard image.
403 Forbidden bij een admin-route. POST /api/reindex en POST /api/cleanup zijn alleen toegankelijk voor beheerders wanneer gebruikersbeheer is ingeschakeld; een gewoon account wordt daar dus geweigerd.
Geheugengebruik stijgt tijdens een import. Taaldetectie over een grote geschiedenis is hiervan meestal de oorzaak. Stel detect_languages: false in en voer daarna hister reindex uit.
FAQ
Hoe verschilt Hister van SearXNG?
SearXNG is een metazoekmachine-proxy: deze stuurt uw zoekopdracht door naar openbare zoekmachines en retourneert de resultaten zonder tracking, maar de index blijft eigendom van die zoekmachines. Hister onderhoudt een eigen full-text index van de pagina's die u heeft bezocht en de bestanden die u bewaart. Hister beantwoordt de vraag "waar heb ik dat gelezen", terwijl SearXNG antwoord geeft op "wat zegt het internet". Ze lossen verschillende problemen op en veel gebruikers draaien beide op één server.
Is het veilig om mijn volledige browsegeschiedenis op een VPS te plaatsen?
Alleen als u eerst de nodige beveiligingsmaatregelen treft. Hister bindt standaard aan 127.0.0.1:4433 en vereist standaard geen authenticatie. Stel app.access_token of user_handling: true in, plaats een reverse proxy met TLS voor de applicatie en houd poort 4433 gesloten in de firewall. Een full-text index van uw leesgeschiedenis bestaat uit platte tekst; iedereen die toegang krijgt tot de poort kan alles lezen zonder enige beveiliging te hoeven kraken.
Heb ik de browserextensie nodig, of kan ik mijn geschiedenis gewoon importeren?
De import is een eenmalige actie om gegevens aan te vullen. Deze leest de eigen geschiedenisdatabase van de browser en wordt daarom uitgevoerd op de computer waar het browserprofiel staat, in plaats van op de server. De extensie houdt de index daarna actueel en legt pagina's achter een inlogscherm vast, omdat de inhoud in de browser wordt geëxtraheerd nadat de pagina is geladen. Een gebruikelijke opzet is één import, gevolgd door het gebruik van de extensie.
Kan een coding agent mijn Hister-index doorzoeken?
Ja. Hister is een MCP-server (model context protocol) op POST /mcp op uw basis-URL, die search, get_preview en get_history beschikbaar stelt. Wijs de client naar https://your-host/mcp met een Authorization: Bearer-header die uw toegangstoken bevat. De agent doorzoekt vervolgens de documentatie die u daadwerkelijk heeft gelezen, in de versie waarin u deze heeft gelezen, in plaats van wat er op dit moment hoog scoort in een openbare zoekmachine.