Tooling
Self-hosted AI voor MKB: 17 breekpunten in je homelab
Je zette Ollama en Open WebUI in een weekend op. Toen vroeg ops om SSO, back-ups en een audit log per gebruiker. Hier breekt die homelab stack.

Het is donderdag, 16:40. De inside-sales lead zit twee prompts diep in Open WebUI als de GPU begint te swappen. De developer die de stack heeft gebouwd zit in een vliegtuig naar Schiphol. Ops Slack loopt rood omdat de assistent die verzendvensters offreert opeens niet meer antwoordt. De assistent is niet down. Een PDF van dertig pagina's, opgestart door een ander team, heeft het offertemodel uit het VRAM geduwd, en Ollama serveert nu requests met 0,4 tokens per seconde.
Dit is het moment waarop een homelab AI dev-platform ophoudt persoonlijk gereedschap te zijn en infrastructuur wordt. Die overgang verloopt ruwer dan de meeste technische medeoprichters verwachten.
Het patroon dat elke maand op Hacker News opduikt is bekend. Eén werkstation met een consumenten-GPU. Ollama of vLLM. Open WebUI als chat front-end. LiteLLM als gateway zodra er meer dan één model in het spel komt. Een vector database, meestal Qdrant of pgvector. Caddy of Traefik ervoor. Een Cloudflare Tunnel zodat de oprichter het ding ook vanuit een hotellobby kan bereiken. Het is een lust voor het oog als één persoon het gebruikt. Het is een horrorshow als twaalf mensen, waarvan drie geen engineer zijn, er voor hun dagelijkse omzet van afhankelijk worden.
Bij Nederlandse en Duitse MKB-bedrijven in de €2M tot €20M omzetklasse zijn we deze stack-vorm de afgelopen achttien maanden ongeveer twintig keer tegengekomen. De breekpunten herhalen zich. Hieronder een veldgids, gerangschikt op de enige manier die telt als er over negen dagen loon betaald moet worden: welke fouten je vanavond nog kunt herstellen in docker-compose.yml, en welke fouten een echte rebuild op iets als Coolify of Dokploy afdwingen.
Fouten die je kunt patchen in docker-compose.yml
Deze negen zijn de goedkope save. Een senior die YAML kent klaart ze allemaal in een lange avond, en de stack overleeft de volgende sprint.
1. Gelijktijdige requests duwen elkaar uit het VRAM
Ollama laadt een model bij het eerste request en ontlaadt het weer als er een ander wordt opgevraagd. Twee gebruikers op verschillende modellen op een 24GB-kaart betekent een modelswap per minuut, en elke swap kost vier tot acht seconden dode tijd. Zet OLLAMA_KEEP_ALIVE op iets eerlijks, pin één model per Ollama-container, en draai twee Ollama-instanties achter LiteLLM als je echt twee modellen warm moet houden. Geloof de docs niet die suggereren dat één Ollama meerdere modellen tegelijk kan vasthouden. Dat kan, totdat het niet meer kan.
2. Geen restart-policies
Containers zonder restart: unless-stopped sterven stilletjes bij de eerste OOM en blijven dood liggen. Niemand merkt het tot de ochtendstand-up. Kosten: nul. Inspanning: één regel per service.
3. Geen healthchecks, race conditions bij koude start
Open WebUI start vóór Postgres klaar is, mislukt op de migratie, en serveert een vriendelijk wit scherm. Voeg een healthcheck toe op de database en een depends_on met condition: service_healthy op de consumer. Ja, dit is Docker Compose v3-werk dat de oorspronkelijke homelab-tutorial heeft overgeslagen.
4. De reverse proxy bindt op 0.0.0.0 en de admin UI heeft geen auth
De default Ollama-poort is 11434. De default Open WebUI-poort is 8080. Beide zijn op een doorsnee homelab compose-file bereikbaar vanaf alles op het LAN. De stagiair op het guest-wifi kan het model aanspreken en chats van anderen meelezen. Bind op 127.0.0.1, zet Caddy of Traefik ervoor met basic auth, en exposeer alleen de proxy.
5. Mismatch in volume-UID en GID
De container draait als UID 1000. De host-directory is bij installatie aangemaakt door root. Logs zeggen permission denied, de chathistorie verdwijnt bij de volgende restart, en een junior verspilt een dag aan het beschuldigen van Postgres. Voeg user: "1000:1000" toe en chown de mount bij eerste boot.
6. Geen log-rotatie
De standaard Docker-logging bewaart alles. Een chat-agent onder bescheiden belasting schrijft per dag één tot twee GB aan JSON-logs. De host-schijf loopt in ongeveer een week vol, Postgres gaat read-only, en de hele stack lijkt op een manier kapot die je een uur kost om uit te zoeken. Stel max-size en max-file in op elke service.
7. Tijdzone-drift tussen containers
De host staat op Europe/Amsterdam, Postgres komt op UTC uit, de chat-app op wat de base image meekreeg. Audit logs en rapporten lopen uit de pas met wat gebruikers op het scherm zagen. Pin TZ op elke container en mount /etc/localtime read-only.
8. Default-poorten botsen met de rest van het netwerk
Poort 8080 is ook de router-admin, poort 9000 is de kantoor-NAS, poort 11434 is bezet door een eerdere Ollama-installatie die iemand vergeten was. Wijs poorten expliciet opnieuw toe in compose. Vertrouw niet blind op vrije defaults.
9. Geen CORS-regels op de LLM-gateway
LiteLLM accepteert standaard requests vanuit elke origin. Op het moment dat marketing een kleine interne pagina bouwt die er rechtstreeks vanuit de browser tegenaan praat, heb je een open key-endpoint waarvan alleen de obscuriteit van de URL je nog beschermt. Beperk origins in de gateway-config, en zet basic auth op alles dat met tokens werkt.
Een bruikbaar compose-fragment dat het meeste hierboven afdekt voor de Ollama-service ziet er zo uit.
services:
ollama:
image: ollama/ollama:latest
restart: unless-stopped
ports:
- "127.0.0.1:11434:11434"
environment:
OLLAMA_KEEP_ALIVE: "30m"
OLLAMA_NUM_PARALLEL: "1"
TZ: "Europe/Amsterdam"
volumes:
- ollama-data:/root/.ollama
deploy:
resources:
limits:
memory: 24g
healthcheck:
test: ["CMD", "curl", "-fsS", "http://localhost:11434/api/tags"]
interval: 30s
timeout: 5s
retries: 3
logging:
driver: json-file
options:
max-size: "20m"
max-file: "5"
volumes:
ollama-data:
Fouten die een rebuild afdwingen vóór de volgende loonronde
Deze acht zijn de fouten waar je niet uit YAMLt. Ze zijn organisatorisch en architectonisch, geen configuratie. De kortste weg is om de stack op een managed self-hosted PaaS-laag te zetten, bijvoorbeeld Coolify of Dokploy. Beide geven je de ontbrekende stukken zonder dat je een Vercel-achtige rekening hoeft af te tikken.
10. Geen back-up-verhaal voor de vector DB en chathistorie
Compose kan een volume mounten. Snapshotten kan het niet. Als de SSD in het werkstation onder de verkoopvloer kapotgaat, en dat gaat hij, want het is een consumenten-NVMe die door embeddings is geramd, dan verdwijnen er zes maanden klantgesprekken en tribal knowledge. Je hebt geplande off-host back-ups nodig met minstens zeven dagen bewaarperiode. Coolify levert dat. Dokploy levert dat. Compose niet.
11. Eén gedeelde API-key, nul audit per gebruiker
Iedere medewerker gebruikt dezelfde LiteLLM-key. Als het model een klant de verkeerde levertijd geeft en die klant escaleert, kun je niet achterhalen wie het heeft gevraagd, welke context erbij is geplakt, of de medewerker het antwoord nog heeft bijgeschaafd. Voor een Nederlands MKB-bedrijf onder de €20M is dat onder artikel 5(2) van de AVG een probleem zodra er persoonsgegevens worden verwerkt.
12. Secrets in .env, vaak gecommit naar git
De compose-file verwijst naar .env. De repo staat op een self-hosted Gitea of een private GitHub. Op dag veertien tikt iemand mis en pusht het env-bestand. De provider-key voor het model, het Postgres-wachtwoord en de Cloudflare Tunnel-token staan voortaan voor eeuwig in de git-historie. Compose heeft geen native secret-rotatie. Een platformlaag wel.
13. De Cloudflare Tunnel draait op een laptop die de oprichter mee op vakantie neemt
Dit klinkt grappiger op papier dan in productie. De tunnel-binary draait onder tmux op de MacBook van de oprichter. De oprichter vliegt naar Kreta, deksel dicht, geen stroom. Het hele bedrijf is een week zonder assistent. De fix is geen betere tmux-sessie. Het is een tunnel die op dezelfde host draait als de stack, supervised, plus een stack die er niet van afhangt dat één persoon wakker is.
14. Eén werkstation onder een bureau is een single point of failure
Consumentenhardware, geen ECC-geheugen, geen redundante voeding, en de schoonmaker met een stofzuiger. We hebben alle drie een AI-deployment de das om zien doen. Zodra het platform onder een echte workflow ligt, heeft het op zijn minst een UPS nodig, host-monitoring, en een uitgeschreven antwoord op de vraag wat er gebeurt als de GPU sterft. Dat antwoord is moeilijk in docker-compose.yml op te schrijven.
15. Geen update- of rollback-strategie
Ollama ships hard. Open WebUI nog harder. Minor-versies van Postgres brengen schema-migraties mee. Op een handgebouwde stack is de typische updatecadans 'als er iets stuk lijkt', wat in de praktijk neerkomt op nooit, totdat de volgende CUDA-driver-update de model loader stilletjes sloopt. Een platform dat atomic deploys doet met één-klik-rollback verdient hier zijn gewicht in goud.
16. Geen observability
Je kunt vandaag niet zien welke van je veertien agents de GPU laat smelten, welke prompt-template tokens verspilt, of de nieuwe RAG-retriever de antwoorden juist slechter heeft gemaakt. Prometheus en Grafana bovenop de metrics van LiteLLM en Ollama geven je dat inzicht. Ze kosten ook een weekend om netjes aan te sluiten. Coolify en Dokploy hebben hier first-class hooks voor. Pure compose niet.
17. AVG-dataresidentie en lacunes in verwerkersovereenkomsten
De hele aantrekkingskracht van self-hosted is dat de data hier blijft. Vervolgens voegt het team een Whisper-transcriptie toe die een externe API aanroept. Dan een vector DB die in Frankfurt draait. Dan een logging-backend in Dublin. Zonder een uitgeschreven verwerkingsregister en op zijn minst een verwerkersovereenkomst met elke derde partij in de keten loopt het MKB-bedrijf risico. De Nederlandse Autoriteit Persoonsgegevens schrijft daar in 2026 meer brieven over, niet minder.
Staan er op een vrijdagmiddag drie of meer punten uit lijst twee in het rood, plan dan de rebuild vóór de volgende loonronde. Elke extra week 'we harden 'm later wel' is opnieuw een week waarin klantdata door een stack loopt zonder audit log en zonder back-ups.
De vijfminutenaudit op vrijdag
Open een terminal op de host. Draai vier commando's.
docker ps --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'
docker exec -it postgres pg_dump --version 2>/dev/null \
&& echo "has pg_dump" || echo "MISSING pg_dump"
df -h /var/lib/docker
crontab -l 2>/dev/null | grep -E 'backup|snapshot' \
|| echo "NO backup cron"
Als één poort op 0.0.0.0 gebonden is, als de schijf voorbij 70% zit, als er geen back-up cron bestaat, als pg_dump ontbreekt op de database-container, dan draait de stack al op geleende tijd. Tel die punten op, plus hoeveel van fouten tien tot zeventien je herkent. Drie of meer: de rebuild is over tijd.
Hoe de rebuild er echt uitziet
Wat teams meestal verrast is punt elf, niet punt tien. Back-ups zijn een dagklus. Veertien medewerkers ieder een eigen key geven, elk met een eigen audit-spoor en een gescopet budget op LiteLLM, is twee dagen onboarding omdat niemand op dag één het rolmodel heeft ontworpen. De port van compose naar Coolify draait op een goede avond in vier uur. De auditlaag draait vier dagen.
Toen we deze migratie vorig kwartaal voor een Rotterdamse groothandel deden, schreven we uiteindelijk een kleine admin-UI bovenop LiteLLM, zodat de operationeel manager per persoon kon zien wat er van het model werd gevraagd. Dat soort lijmwerk is waar het meeste werk van een AI-agents rebuild eigenlijk in gaat zitten.
Voordat je hier iets aanraakt: draai eerst de vier-commando-audit hierboven. De eerste kolom van docker ps vertelt je in zo'n negentig seconden of je infrastructuur draait of een wetenschapsproject waar mensen op leunen.
Kern
Een homelab AI stack houdt op veilig te zijn op de dag dat een niet-engineer ervan afhankelijk wordt. Draai de vier-commando-audit; staan er drie items rood, plan dan de rebuild vóór de loonronde.
FAQ
Kan ik de homelab-stack houden en er later dingen aan toevoegen?
Voor één of twee gebruikers wel. Zodra er klantdata doorheen loopt of een niet-engineer er dagelijks van afhangt, wordt de rebuild goedkoper dan het volgende incident.
Coolify of Dokploy?
Allebei werken ze. Coolify heeft bredere plugin-ondersteuning en een luidruchtigere community. Dokploy is leaner en sneller te leren. Voor een Nederlands MKB onder de twintig medewerkers: kies wat je senior dev al gebookmarkt heeft.
Moet ik Ollama dan achterlaten?
Nee. Ollama als model-runner is prima. Het is de omliggende stack die upgrade nodig heeft: secrets, back-ups, audit, observability, en een tunnel die niet afhangt van een opengeklapte laptop.
Dwingt de rebuild een modelwissel af?
Bijna nooit. De rebuild gaat over het platform, niet over de weights. Je houdt hetzelfde model, dezelfde vector DB, vaak dezelfde prompts. Wat verandert is wie wat mag zien, en wat een storing overleeft.