SSD Nodes Learn 🎉 VPS vanaf $5.50/mnd
Gidsen Matt ConnorDoor Matt Connor · Bijgewerkt 2026-08-21

Hister zelf hosten als persoonlijke zoekmachine

Host Hister op uw eigen VPS om uw volledige browsergeschiedenis en lokale bestanden te doorzoeken. Leer hoe u binaries of Docker instelt inclusief TLS, authenticatie en MCP.

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 deze verzameling kunt doorzoeken via een webinterface, een terminalclient, een HTTP API of een AI-assistent (artificiële intelligentie). Hister beantwoordt één vraag: waar heb ik dat gelezen.

De meeste gebruikers komen met dit concept in aanraking via SearXNG, maar dit zijn niet dezelfde tools. SearXNG is een metazoek-proxy. Uw zoekopdracht gaat naar deze proxy, die namens u andere zoekmachines raadpleegt en de resultaten zonder tracking teruggeeft. De index is eigendom van die zoekmachines. Hister bouwt een eigen index op basis van de inhoud die u aanlevert: pagina's die zijn vastgelegd via een browserextensie, geïmporteerde browsergeschiedenis, gecrawlde URL's en bestanden in mappen die u aan de tool toewijst. Een zelf-gehoste SearXNG-instantie biedt u privétoegang tot het openbare web. Hister biedt u een zoekfunctie voor uw eigen leesgeschiedenis. De taken zijn verschillend, dus het is gebruikelijk om beide op één server te draaien.

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 opdrachten 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 nooit. Een VPS (virtual private server) blijft altijd actief, zodat elk apparaat dat u bezit naar dezelfde index schrijft en de crawler doorwerkt terwijl u slaapt.

De tweede reden is scheiding. Door user_handling: true in de sectie app in te stellen, krijgt elk account zijn eigen inloggegevens en zijn eigen documentverzameling op één instantie. Eén server kan dan dienen voor een huishouden of een klein team, zonder dat iemand de leesgeschiedenis van een ander kan doorzoeken.

De derde reden is de infrastructuur. De VPS beschikt al over een publieke hostnaam en een certificaat; dit is precies wat de browserextensie nodig heeft om de server te bereiken vanaf een netwerk dat u niet beheert.

Installatiepad één: het release-binary

Hister levert één binary per platform. Download deze samen met het checksum-bestand en verifieer de integriteit 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.txt

Een 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 in dat geval 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.yml

create-config schrijft een standaardconfiguratiebestand en toont aan dat de binary op deze machine kan worden uitgevoerd. Een download voor de verkeerde architectuur faalt hier direct met cannot execute binary file: Exec format error.

Pas de 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.com

Genereer het token met openssl rand -hex 32. Het bestand bevat nu een inloggegeven; beperk daarom de toegangsrechten voordat de service wordt gestart.

sudo chown root:hister /etc/hister/config.yml
sudo chmod 640 /etc/hister/config.yml

Uitvoeren 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.target

HISTER_CONFIG is de gedocumenteerde omgevingsvariabele voor het configuratiepad, zodat de unit niet afhankelijk is van de thuismap van het hister-account. ProtectSystem=strict maakt het volledige bestandssysteem alleen-lezen voor deze service; daarom moet ReadWritePaths de datamap benoemen. ProtectHome=yes verbergt /home voor de service, waardoor een geobserveerde map 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 het 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 wordt 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:4433

Elke configuratiesleutel heeft een environment override in de vorm HISTER__<SECTION>__<KEY>, waarbij twee underscores als scheidingsteken dienen. Een container-deployment heeft daarom geen gemount configuratiebestand nodig. Bewaar HISTER_ACCESS_TOKEN in een .env-bestand naast het compose-bestand. Als u liever een bestand bewerkt, drukt docker run --rm ghcr.io/asciimoo/hister:v0.17.0 create-config > config.yml de standaardwaarden af.

De twee bovenstaande regels zijn foutgevoelig en beide zijn belangrijk om te begrijpen.

Het adres binnen de container moet 0.0.0.0:4433 zijn. Een container heeft een eigen netwerk-namespace; een proces dat daar aan 127.0.0.1 is gebonden, is alleen bereikbaar vanuit die container zelf, waardoor 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. Deze regels worden geëvalueerd vóór de ufw-regels, waardoor een simpele 4433:4433 bereikbaar blijft 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 rechtenfout. 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 blootstellen het slechtste is wat u kunt doen

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 paginainhoud, 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 geserveerd 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. Eén gebruiker heeft alleen app.access_token nodig, een gedeeld geheim dat door de browserextensie, de terminalclient en elke MCP-client wordt verzonden. 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.yml

Het 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 via 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 weet wat u doet. De publieke modus staat niet-geauthenticeerd zoeken, previews, het serveren van bestanden en MCP-zoeken toe, terwijl schrijfacties, toegang tot de geschiedenis en beheerdershandelingen 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 route, 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 afgehandeld. 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 status

Poort 4433 ontbreekt bewust in die lijst.

server.base_url moet exact overeenkomen met het adres dat u in de browser typt, inclusief het schema. Wanneer dit niet overeenkomt, laadt de interface zonder opmaak en ontbreken afbeeldingen, omdat de server de links naar assets opbouwt op basis van base_url en de browser deze vervolgens opvraagt bij een bron die geen antwoord geeft. Diezelfde URL wordt gebruikt in de browserextensie.

De index vullen

De browserextensie is de voornaamste verzamelaar. Installeer deze vanuit de 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 zonder dat uw server over inloggegevens hoeft te beschikken. Dit betekent ook dat alles wat u bekijkt een kandidaat is voor de index; daarom gaan uitsluitingsregels (skip rules) voor op de rest van de inhoud.

Uitsluitingsregels bevinden zich 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 bij 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 weer kunt hervatten. Bookmark-diensten worden op dezelfde manier geïmporteerd, waaronder Linkwarden, Karakeep, Wallabag, Linkding, Readeck en Shaarli. Een herhaalde import haalt alleen de items 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, afgehandeld door zelf-gehoste crawlers die pagina's omzetten naar schone tekst.

Zoeken is gebaseerd op velden, dus de query-taal is de tien minuten leestijd meer dan waard:

"connection reset" domain:github.com added:<30d
title:(wireguard|nftables) -tutorial sort:-visits

Een coding agent koppelen aan 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 serveert dit op POST /mcp onder dezelfde basis-URL, via het streamable HTTP-transport, en stelt search, get_preview en get_history beschikbaar. Authenticatie verloopt via hetzelfde bearer token als de rest van de API.

{
  "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 meerwaarde zit in wat de agent doorzoekt. Een open webzoekopdracht retourneert wat vandaag hoog scoort, wat voor snel veranderende software vaak documentatie is 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 afzonderlijke 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 de gecomprimeerde preview. Honderdduizend pagina's beslaan dus ruwweg 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 previews, en rules.json. Een back-up bestaat uit een gestopte service en een kopie van de volledige map inclusief 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 indexeringsinstellingen. Als het geheugengebruik stijgt tijdens een grote import, stel dan detect_languages: false in binnen de indexer sectie en voer de herindexering opnieuw uit. hister cleanup verwijdert verweesde preview- 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 --verbose

Een verwijderde pagina keert terug als een collector deze opnieuw indient; voeg daarom de skip-regel toe voordat u tot verwijdering overgaat.

De AGPLv3 is pas van belang 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 tussen beide systemen 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 bij het opstarten. Een rechtenfout op ./data betekent dat de directory 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 geweigerd.

Geheugengebruik stijgt tijdens een import. Taaldetectie over een grote geschiedenis is de gebruikelijke oorzaak. Stel detect_languages: false in en voer daarna hister reindex uit.

FAQ

Hoe verschilt Hister van SearXNG?

SearXNG is een metazoek-proxy: het stuurt uw zoekopdracht door naar publieke zoekmachines en retourneert de resultaten zonder tracking, waardoor de index bij die zoekmachines blijft. Hister onderhoudt een eigen full-text index van de pagina's die u heeft bezocht en de bestanden die u bewaart. Hister beantwoordt dus 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 geen authenticatie. Stel app.access_token of user_handling: true in, plaats een reverse proxy met TLS ervoor en houd poort 4433 gesloten in de firewall. Een full-text index van uw leesgeschiedenis is platte tekst; iedereen die de poort kan bereiken, 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. Het leest de eigen geschiedenisdatabase van de browser en draait daarom op de computer waar het browserprofiel staat, in plaats van op de server. De extensie houdt de index vanaf dat moment actueel en legt pagina's achter een login 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 (model context protocol) server 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 vandaag de dag hoog scoort in een publieke zoekmachine.