Ollama achter een reverse proxy met Caddy of Nginx voor HTTPS-streaming
HTTPS Ollama zonder streaming-responsen te verstoren.
Het draaien van Ollama achter een reverse proxy is de eenvoudigste manier om HTTPS, optionele toegangscontrole en voorspelbaar streamgedrag te krijgen.
Dit artikel richt zich op Caddy en Nginx ingress voor de Ollama API, niet op clientcode.

Als je al Python- of Go-clients hebt die met Ollama communiceren, is dit artikel het ontbrekende stuk: ingress en transport voor dezelfde API.
Voor informatie over hoe Ollama zich verhoudt tot vLLM, Docker Model Runner, LocalAI en de afwegingen rond cloudhosting, zie LLM-hosting in 2026: Lokaal, Self-Hosted en Cloud-infrastructuur vergeleken.
Voor voorbeelden van aanvragen en clientcode, zie Ollama CLI Cheatsheet.
Voor UI- en multi-user lagen, zie Open WebUI-overzicht, quickstart en alternatieven.
Voor het grotere plaatje over self-hosting en datacontrole, zie LLM self-hosting en AI-soevereiniteit.
Voor een reproduceerbare single-node Ollama-service in Docker Compose (persistente volumes, OLLAMA_HOST, NVIDIA GPU’s, upgrades), zie
Ollama in Docker Compose met GPU en persistent modelopslag.
Waarom je Ollama moet proxen in plaats van poort 11434 bloot te stellen
Ollama is ontworpen om eerst lokaal te draaien. Standaard bindt het aan localhost op poort 11434, wat ideaal is voor een ontwikkelaarswerkstation en een niet-toevallige hint dat de ruwe poort niet bedoeld is voor gebruik via het internet.
Ik behandel poort 11434 als een interne, kostbare API. Als deze bereikbaar is vanaf het openbare internet, kan iedereen die het vindt je CPU- of GPU-tijd opbranden, je schijf vullen door modellen te downloaden of verbindingen openhouden tot er een time-out optreedt. Een reverse proxy maakt Ollama niet magisch veiliger, maar het geeft je een plek om de controles die ertoe doen aan de rand te plaatsen: TLS, authenticatie, time-outs, rate limits en logs.
Dit is belangrijk omdat de lokale Ollama-API niet met een ingebouwd authenticatielaagje wordt geleverd. Als je het exposeert, voeg je doorgaans auth toe aan de rand of houd je het privé en bereikbaar alleen via een vertrouwd netwerk.
De tweede reden is UX. Ollama streamt antwoorden standaard. Als de proxy op de verkeerde plek buffer of comprimeert, voelt het streamen gebroken en lijken UI’s alsof ze “nadenken” zonder output.
Minimale architectuur en bindingstrategie
Een schone minimumopstelling ziet er als volgt uit:
Client (curl, Python, Go, UI)
|
| HTTPS (optionele Basic Auth of SSO)
v
Reverse proxy (Caddy of Nginx)
|
| HTTP (privé LAN, localhost of Docker-netwerk)
v
Ollama-server (ollama serve op 127.0.0.1:11434)
Twee praktische regels houden dit op een goede manier saai.
Ten eerste, houd Ollama privé en verplaats de blootstelling naar de proxy. Als Caddy of Nginx op dezelfde host draait, proxy naar 127.0.0.1:11434 en verander de bindadres van Ollama niet. Als de proxy elders draait (separate host, separate VM of een container-netwerk), bind Ollama aan een privé-interface, niet aan 0.0.0.0 op de openbare NIC, en vertrouw op een firewall.
Ten tweede, beslis vroeg of browsers Ollama direct zullen aanroepen. Als een browsergebaseerd tool Ollama van een andere oorsprong raakt, moet je misschien omgaan met CORS. Als alles via de proxy van één domein wordt geserveerd (aanbevolen voor het hoofd), kun je vaak CORS helemaal vermijden en Ollama streng houden.
Reverse proxy-configuraties voor streaming en WebSockets
De API van Ollama is regulier HTTP en het streamen is newline-delimited JSON (NDJSON). Dat betekent dat je een proxy wilt die drie dingen goed kan doen:
- Geen streaming-antwoorden bufferen.
- Geen langlopende aanvragen afbreken alleen omdat het model even lang duurt om te reageren.
- Als een UI WebSockets gebruikt (sommige doen dat), Upgrade correct doorsturen.
Je kunt dit eenvoudig houden. In veel gevallen is “correcte WebSocket-handling” simpelweg een configuratie die Upgrade-safe is, zelfs als de upstream vandaag WebSockets niet gebruikt.
Caddy Caddyfile-voorbeeld
Caddy is de optie “minder configuratie, meer standaarden”. Als je een openbare domeinnaam in het site-adres zet, zal Caddy doorgaans certificaten automatisch verkrijgen en vernieuwen.
Minimale reverse proxy, HTTPS en streamvriendelijke instellingen:
# ollama.example.com A/AAAA -> jouw proxy-host
ollama.example.com {
# Optionele Basic Auth aan de rand.
# Genereer een wachtwoord-hash met:
# caddy hash-password --algorithm bcrypt
#
# basic_auth {
# alice $2a$12$REDACTED...
# }
reverse_proxy 127.0.0.1:11434 {
# Sommige opstellingen geven de voorkeur aan het vastpinnen van de upstream Host-header.
# De eigen documentatie van Ollama toont dit patroon voor Nginx.
header_up Host localhost:11434
# Voor streaming of chat-achtige werklasten, geef voorkeur aan lage latentie.
# NDJSON-streaming spoelt doorgaans toch direct, maar dit maakt het expliciet.
flush_interval -1
transport http {
# Vermijd upstream gzip-onderhandeling als dit interfereert met streaming.
compression off
# Geef Ollama tijd om een model te laden en het eerste chunk te produceren.
response_header_timeout 10m
dial_timeout 10s
}
}
}
Als je al een SSO-gateway hebt (oauth2-proxy, Authelia, authentik outpost, enz.), heeft Caddy een opiniëerde forward auth-directive. Het patroon is “auth eerst, dan proxy”:
ollama.example.com {
forward_auth 127.0.0.1:4180 {
uri /oauth2/auth
# Kopieer de identiteitsheaders die je gateway teruggeeft, als je ze nodig hebt.
copy_headers X-Auth-Request-User X-Auth-Request-Email Authorization
}
reverse_proxy 127.0.0.1:11434
}
Nginx server block-voorbeeld
Nginx geeft je wat meer touw. Het voordeel is dat de knoppen expliciet zijn en het ingebouwde primitieven heeft voor rate limiting en verbindingenlimieten. De valkuil is buffering: Nginx buffert geproxied antwoorden standaard, wat het tegenovergestelde is van wat je wilt voor NDJSON-streaming.
Dit voorbeeld bevat:
- HTTP naar HTTPS redirect
- TLS-certificaatpaden (Certbot-stijl)
- WebSocket-safe Upgrade-doorsturing
- Streamvriendelijke proxy_buffering off
- Langere time-outs dan de standaard 60s
# /etc/nginx/conf.d/ollama.conf
# WebSocket-safe Connection header-handling
map $http_upgrade $connection_upgrade {
default upgrade;
"" close;
}
# Optionele aanvraag-rate limiting (IP-gebaseerd)
# limit_req_zone $binary_remote_addr zone=ollama_rate:10m rate=10r/s;
server {
listen 80;
server_name ollama.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name ollama.example.com;
ssl_certificate /etc/letsencrypt/live/ollama.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/ollama.example.com/privkey.pem;
# Optionele Basic Auth aan de rand.
# auth_basic "Ollama";
# auth_basic_user_file /etc/nginx/.htpasswd;
location / {
# Optionele rate limit
# limit_req zone=ollama_rate burst=20 nodelay;
proxy_pass http://127.0.0.1:11434;
# Match Ollama-docpatroon bij proxyen naar localhost.
proxy_set_header Host localhost:11434;
# WebSocket Upgrade-handling (onschuldig als niet gebruikt).
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
# Kritisch voor NDJSON-streaming.
proxy_buffering off;
# Voorkom 60s idle-time-outs terwijl er op tokens wordt gewacht.
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
}
Als je een SSO-stijl poort in Nginx wilt, is het equivalente patroon auth_request. Nginx stuurt een subaanvraag naar je auth-service en proxyt alleen naar Ollama wanneer auth 2xx teruggeeft.
TLS-automatisering en vernieuwingstrucjes
Voor TLS is de operationele splitsing simpel.
Met Caddy is TLS doorgaans “een onderdeel van de reverse proxy”. Automatische HTTPS is een van zijn vlaggescheppende functies, dus certificaatuitgifte en -vernieuwing zijn gekoppeld aan Caddy draaiende houden, werkende DNS en het blootstellen van poorten 80 en 443.
Met Nginx is TLS doorgaans “een aparte ACME-client plus Nginx”. De veelvoorkomende faalmodus is geen crypto, het is leidingwerk:
- Poort 80 niet bereikbaar voor HTTP-01-challenges.
- Certificaten opgeslagen in een container maar niet gepersisteerd.
- Rate limits bij het doen van herhaalde frisse installaties of testdeploys.
Een subtiel punt dat belangrijk is voor langlopende diensten is dat certificaatlevensduur kort is per ontwerp. Behandel vernieuwingen als een achtergrondautomatiseringsvereiste, niet als een jaarlijks kalendergebeurtenis.
Authenticatie, misbruikcontrole en verificatie
Dit is het deel dat een internet-facing LLM-endpunt professioneel doet voelen.
Authenticatie-opties, van bot naar elegant
Basic Auth bij de proxy is bot, maar verrassend effectief voor een privé-endpunt. Het is ook eenvoudig toe te passen op zowel HTTP-aanvragen als WebSocket-upgrades.
Als je browser-vriendelijke inlogstromen wilt, zijn forward auth en auth_request het gebruikelijke patroon. Je proxy blijft stateless en een auth-gateway bezit sessies en MFA. De afweging is meer bewegende onderdelen.
Als je al Open WebUI draait, kun je ook vertrouwen op de app-niveau authenticatie en Ollama zelf privé houden. De proxy beschermt dan Open WebUI, niet Ollama direct.
Als je helemaal geen openbare toegang nodig hebt, kan een netwerk-alleen benadering schoner zijn. Bijvoorbeeld, Tailscale Serve kan een lokale service binnen je tailnet blootstellen zonder inkomende poorten op je router te openen.
Misbruikbasis voor een dure API
Ollama is een krachtige lokale API en zijn oppervlak gaat verder dan generatie. Het heeft endpoints voor chat, embeddings, modellenlijsten en versiecontroles. Behandel de hele API als gevoelig.
Officiële API-referentie (endpoints en streaming): https://docs.ollama.com/api
Op het proxylaag zijn er drie lage-inspanningscontroles die dag-één-pijn verminderen:
- Rate limiting per IP op generatie-endpoints.
- Verbindingslimieten om een klein aantal clients te stoppen met alles open te houden.
- Conservatieve time-outs die passen bij jouw model en hardwarewerkelijkheid, niet generieke webstandaarden.
Op het Ollama-lag kan het ook overbelasting afwijzen met 503 en heeft het server-side knoppen voor queueing. Proxy rate limiting houdt je er vaak niet toe.
Verificatiecontrolelijst
Gebruik dezelfde checks die je zou gebruiken voor elke streaming-API.
-
Basisconnectiviteit en TLS
curl -sS https://ollama.example.com/api/versioncurl -sS https://ollama.example.com/api/tags | head
-
Streaming werkt van begin tot eind (geen buffering)
curl -N https://ollama.example.com/api/generate -H "Content-Type: application/json" -d '{"model":"mistral","prompt":"Schrijf slechts 10 woorden.","stream":true}'
Als je achter Basic Auth zit:
curl -N -u alice:REDACTED https://ollama.example.com/api/generate -H "Content-Type: application/json" -d '{"model":"mistral","prompt":"Schrijf slechts 10 woorden.","stream":true}'
-
Browser-UI-zin
- Laad je chat-UI en trigger een reactie.
- Als de UI WebSockets gebruikt, bevestig dat je geen 400- of 426-fouten ziet en de verbinding open blijft tijdens generatie.
Als de curl-output pas aan het einde verschijnt, is het bijna altijd buffering bij de proxy. Controleer proxy_buffering off in Nginx opnieuw en overweeg low-latency flushing te forceren in Caddy voor de Ollama-site-block.