Ollama dietro un proxy inverso con Caddy o Nginx per lo streaming HTTPS
HTTPS con Ollama senza interrompere le risposte in streaming.
Eseguire Ollama dietro un proxy inverso è il modo più semplice per ottenere HTTPS, un controllo degli accessi opzionale e un comportamento di streaming prevedibile.
Questo post si concentra sull’ingresso Caddy e Nginx per l’API di Ollama, non sul codice client.

Se hai già client Python o Go che comunicano con Ollama, questo post è il tassello mancante: l’ingresso e il trasporto per la stessa API.
Per capire come Ollama si inserisce accanto a vLLM, Docker Model Runner, LocalAI e i compromessi dell’hosting cloud, consulta LLM Hosting in 2026: Local, Self-Hosted & Cloud Infrastructure Compared.
Per esempi di richieste e codice client, vedi Ollama CLI Cheatsheet.
Per le interfacce utente e i livelli multi-utente, vedi Open WebUI overview, quickstart and alternatives.
Per una visione d’insieme sull’auto-hosting e il controllo dei dati, vedi LLM self-hosting and AI sovereignty.
Per un servizio Ollama a singolo nodo riproducibile in Docker Compose (volumi persistenti, OLLAMA_HOST, GPU NVIDIA, aggiornamenti), vedi
Ollama in Docker Compose with GPU and Persistent Model Storage.
Perché dovresti usare un proxy per Ollama invece di esporre la porta 11434
Ollama è progettato per funzionare principalmente in locale. Di default si lega a localhost sulla porta 11434, il che è ottimo per una workstation di sviluppo e costituisce un indizio non così sottile che la porta grezza non è destinata a essere esposta su Internet.
Tratto la porta 11434 come un’API interna ad alto costo. Se è raggiungibile dal pubblico Internet, chiunque la trovi può consumare il tempo della tua CPU o GPU, riempire il tuo disco scaricando modelli, o semplicemente mantenere le connessioni aperte fino a quando non si verifica un timeout. Un proxy inverso non rende Ollama più sicuro per magia, ma ti offre un punto in cui inserire i controlli che contano al confine: TLS, autenticazione, timeout, limiti di velocità e log.
Questo è importante perché l’API locale di Ollama non include un livello di autenticazione integrato. Se la esponi, tipicamente aggiungi l’autenticazione al confine o la mantieni privata e raggiungibile solo tramite una rete di fiducia.
La seconda ragione riguarda l’esperienza utente (UX). Ollama trasmette le risposte in streaming di default. Se il proxy tampona o comprime nel punto sbagliato, lo streaming sembra rotto e le interfacce utente sembrano “pensare” senza produrre alcun output.
Architettura minima e strategia di binding
Un minimo pulito sembra così:
Client (curl, Python, Go, UI)
|
| HTTPS (opzionale Basic Auth o SSO)
v
Reverse proxy (Caddy o Nginx)
|
| HTTP (LAN privata, localhost o rete Docker)
v
Ollama server (ollama serve su 127.0.0.1:11434)
Due regole pratiche mantengono tutto noioso nel migliore dei modi.
Prima, mantieni Ollama privato e sposta l’esposizione al proxy. Se Caddy o Nginx girano sullo stesso host, fai il proxy verso 127.0.0.1:11434 e non cambiare l’indirizzo di binding di Ollama. Se il proxy gira altrove (host separato, VM separata o rete di container), collega Ollama a un’interfaccia privata, non a 0.0.0.0 sulla NIC pubblica, e affidati a un firewall.
Secondo, decidi presto se i browser chiameranno Ollama direttamente. Se uno strumento basato su browser colpisce Ollama da un’origine diversa, potresti dover gestire le CORS. Se tutto viene servito da un dominio tramite il proxy (consigliato per sanità mentale), spesso puoi evitare completamente le CORS e mantenere Ollama rigoroso.
Configurazioni del proxy inverso per lo streaming e WebSockets
L’API di Ollama è HTTP regolare e il suo streaming è JSON delimitato da newline (NDJSON). Questo significa che vuoi un proxy che sappia fare bene tre cose:
- Non tamponare le risposte in streaming.
- Non uccidere le richieste a lungo termine solo perché il modello ha impiegato del tempo a parlare.
- Se un’UI utilizza WebSockets (alcune lo fanno), inoltra l’Upgrade in modo pulito.
Puoi mantenere le cose semplici. In molti casi, la “gestione corretta dei WebSockets” è solo avere una configurazione che è sicura per l’Upgrade anche se l’upstream non utilizza WebSockets oggi.
Esempio Caddyfile per Caddy
Caddy è l’opzione “meno configurazione, più valori predefiniti”. Se inserisci un nome dominio pubblico nell’indirizzo del sito, Caddy otterrà e rinnoverà i certificati automaticamente.
Impostazioni minime per proxy inverso, HTTPS e amichevoli per lo streaming:
# ollama.example.com A/AAAA -> tuo host proxy
ollama.example.com {
# Opzionale Basic Auth al confine.
# Genera un hash di password con:
# caddy hash-password --algorithm bcrypt
#
# basic_auth {
# alice $2a$12$REDACTED...
# }
reverse_proxy 127.0.0.1:11434 {
# Alcune configurazioni preferiscono fissare l'header Host upstream.
# I documenti di Ollama mostrano questo pattern per Nginx.
header_up Host localhost:11434
# Per carichi di lavoro in streaming o simili a chat, preferisci bassa latenza.
# Lo streaming NDJSON solitamente scarica immediatamente comunque, ma questo lo rende esplicito.
flush_interval -1
transport http {
# Evita la negoziazione gzip upstream se interferisce con lo streaming.
compression off
# Dà a Ollama il tempo di caricare un modello e produrre il primo chunk.
response_header_timeout 10m
dial_timeout 10s
}
}
}
Se hai già un gateway SSO (oauth2-proxy, Authelia, authentik outpost, ecc.), Caddy ha una direttiva di autenticazione in avanti opinata. Il pattern è “prima autenticazione, poi proxy”:
ollama.example.com {
forward_auth 127.0.0.1:4180 {
uri /oauth2/auth
# Copia gli header di identità restituiti dal tuo gateway, se ne hai bisogno.
copy_headers X-Auth-Request-User X-Auth-Request-Email Authorization
}
reverse_proxy 127.0.0.1:11434
}
Esempio blocco server per Nginx
Nginx ti dà un po’ più di libertà. Il vantaggio è che i controlli sono espliciti e ha primitivi integrati per il rate limiting e il limite delle connessioni. Il rischio è il buffering: Nginx tampona le risposte proxy di default, che è l’opposto di ciò che vuoi per lo streaming NDJSON.
Questo esempio include:
- Reindirizzamento da HTTP a HTTPS
- Percorsi dei certificati TLS (stile Certbot)
- Inoltro Upgrade sicuro per WebSocket
- proxy_buffering off per lo streaming
- Timeout più lunghi rispetto al default di 60s
# /etc/nginx/conf.d/ollama.conf
# Gestione sicura dell'header Connection per WebSocket
map $http_upgrade $connection_upgrade {
default upgrade;
"" close;
}
# Limitazione della velocità delle richieste opzionale (basata su IP)
# 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;
# Opzionale Basic Auth al confine.
# auth_basic "Ollama";
# auth_basic_user_file /etc/nginx/.htpasswd;
location / {
# Limitazione della velocità opzionale
# limit_req zone=ollama_rate burst=20 nodelay;
proxy_pass http://127.0.0.1:11434;
# Corrispondi al pattern dei documenti di Ollama quando si proxy verso localhost.
proxy_set_header Host localhost:11434;
# Gestione Upgrade WebSocket (innocuo se non usato).
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
# Critico per lo streaming NDJSON.
proxy_buffering off;
# Previene i timeout di inattività di 60s mentre si attendono i token.
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
}
Se vuoi un gate stile SSO in Nginx, il pattern equivalente è auth_request. Nginx invia una sotto-richiesta al tuo servizio di autenticazione e proxy verso Ollama solo quando l’autenticazione restituisce 2xx.
Insidie dell’automazione e del rinnovo TLS
Per TLS, la divisione operativa è semplice.
Con Caddy, TLS è solitamente “parte del proxy inverso”. HTTPS automatico è una delle sue funzionalità di punta, quindi l’emissione e il rinnovo dei certificati sono accoppiati al mantenimento di Caddy in esecuzione, avere DNS funzionanti ed esporre le porte 80 e 443.
Con Nginx, TLS è solitamente “un client ACME separato più Nginx”. Il modo di fallimento comune non è la crittografia, ma la tubatura:
- Porta 80 non raggiungibile per le sfide HTTP-01.
- Certificati memorizzati in un container ma non persistenti.
- Limiti di velocità quando si eseguono installazioni fresche ripetute o deployment di test.
Un punto sottile che conta per servizi a lunga durata è che le vite dei certificati sono brevi per progettazione. Tratta i rinnovi come un requisito di automazione di background, non come un evento annuale sul calendario.
Autenticazione, controllo degli abusi e verifica
Questa è la parte che rende un endpoint LLM esposto su Internet professionale.
Opzioni di autenticazione, dal semplice all’elegante
Basic Auth al proxy è semplice, ma sorprendentemente efficace per un endpoint privato. È anche facile da applicare sia alle richieste HTTP che agli upgrade WebSocket.
Se vuoi flussi di login amichevoli per il browser, forward auth e auth_request sono il pattern comune. Il tuo proxy rimane stateless e un gateway di autenticazione gestisce sessioni e MFA. Il compromesso è più parti in movimento.
Se stai già utilizzando Open WebUI, puoi anche affidarti alla sua autenticazione a livello di applicazione e mantenere Ollama stesso privato. Il proxy protegge quindi Open WebUI, non Ollama direttamente.
Se non hai bisogno di accesso pubblico affatto, un approccio solo di rete può essere più pulito. Ad esempio, Tailscale Serve può esporre un servizio locale all’interno della tua tailnet senza aprire porte in ingresso sul tuo router.
Basi degli abusi per un’API costosa
Ollama è un’API locale potente e la sua superficie va oltre la generazione. Ha endpoint per chat, embeddings, elenco modelli e controlli versione. Tratta l’intera API come sensibile.
Riferimento API ufficiale (endpoint e streaming): https://docs.ollama.com/api
Al livello del proxy, ci sono tre controlli a basso sforzo che riducono il dolore del primo giorno:
- Limitazione della velocità per IP sugli endpoint di generazione.
- Limiti di connessione per fermare un piccolo numero di client che tengono tutto aperto.
- Timeout conservativi che corrispondono alla realtà del tuo modello e hardware, non ai valori predefiniti web generici.
Al livello di Ollama, può anche rifiutare il sovraccarico con 503 e ha manopole lato server per la coda. La limitazione della velocità del proxy ti impedisce di arrivare lì così spesso.
Checklist di verifica
Usa gli stessi controlli che useresti per qualsiasi API in streaming.
-
Connettività di base e TLS
curl -sS https://ollama.example.com/api/versioncurl -sS https://ollama.example.com/api/tags | head
-
Lo streaming funziona da capo a fondo (senza buffering)
curl -N https://ollama.example.com/api/generate -H "Content-Type: application/json" -d '{"model":"mistral","prompt":"Write 10 words only.","stream":true}'
Se sei dietro Basic Auth:
curl -N -u alice:REDACTED https://ollama.example.com/api/generate -H "Content-Type: application/json" -d '{"model":"mistral","prompt":"Write 10 words only.","stream":true}'
-
Sanità dell’UI del browser
- Carica la tua UI di chat e innesca una risposta.
- Se l’UI utilizza WebSockets, conferma di non vedere errori 400 o 426 e che la connessione rimanga aperta durante la generazione.
Se l’output di curl appare solo alla fine, è quasi sempre buffering al proxy. Ricontrolla proxy_buffering off in Nginx e considera di forzare lo scaricamento a bassa latenza in Caddy per il blocco del sito Ollama.