SSD Nodes Learn Hosting plans →
Guide Matt ConnorDi Matt Connor

Ollama su VPS: come ospitare un LLM in sicurezza

Un modello 7B richiede 8 GB di RAM e produce 4-10 token al secondo su CPU. Usa un VPS e 127.0.0.1:11434/v1, lasciando chiusa la porta 11434.

Cosa si sta configurando

Un singolo modello linguistico open-weight eseguito su un server di proprietà, accessibile tramite un'API HTTP e, se necessario, tramite una pagina di chat nel browser. Ollama scarica il modello, lo carica in memoria e gestisce le richieste su http://127.0.0.1:11434. L'installazione richiede un solo comando. La parte complessa è altrove: scegliere un modello che il VPS riesca effettivamente a contenere in RAM e non pubblicare per errore su Internet un server di inferenza privo di autenticazione.

Prima di iniziare, è importante considerare due aspetti. Un VPS che usa soltanto la CPU esegue lentamente i modelli di piccole dimensioni. Inoltre, l'API non include alcun meccanismo di autenticazione integrato. Entrambi gli aspetti sono descritti in dettaglio più avanti, perché sono le principali cause di problemi in questa configurazione.

Il controllo della capacità, espresso in numeri semplici

L'ingombro in memoria di un modello corrisponde all'incirca alla dimensione del file, più circa un gigabyte di overhead di runtime e un'ulteriore quantità per la finestra di contesto. I tag predefiniti della maggior parte dei modelli Ollama più diffusi, tra cui llama3.2:3b, llama3.1:8b e mistral:7b, usano una quantizzazione a 4 bit (indicata come Q4_K_M), che richiede circa mezzo gigabyte di RAM per ogni miliardo di parametri. Non tutti i valori predefiniti sono Q4: i modelli più piccoli, come smollm2:135m, vengono distribuiti a 16 bit. Controllate quindi la riga relativa alla quantizzazione nella pagina del modello della libreria prima di eseguire i calcoli. L'aritmetica è semplice e determina tutto. L'ultimo termine è quello che impostate voi: aumentare num_ctx oltre il valore predefinito ridotto di Ollama lascia spazio a prompt più lunghi, ma aumenta la cache KV in RAM. Stabilite quindi una lunghezza del contesto prima di valutare se un modello può essere eseguito.

Un modello 3B come llama3.2:3b richiede un download di circa 2 GB e circa 4 GB di RAM libera per l'esecuzione. Un modello 7B o 8B, come mistral:7b o llama3.1:8b, occupa circa 5 GB sul disco e richiede circa 8 GB di RAM, oppure 16 GB per lavorare senza difficoltà. Un modello 13B o 14B richiede circa 16 GB. Qualsiasi modello nell'intervallo da 30B a 70B richiede un server con molta RAM o, realisticamente, una GPU. Su una VPS con CPU non entrerà nella memoria disponibile oppure risponderà così lentamente da risultare inutilizzabile.

Passiamo ora alla velocità, perché questo aspetto viene spesso sottovalutato. L'inferenza sulla CPU è limitata dalla larghezza di banda della memoria, non dalla frequenza di clock, e una vCPU condivisa su una VPS offre una larghezza di banda modesta. Prevedete prestazioni da una singola cifra a una bassa doppia cifra di token al secondo: un modello 7-8B Q4 può produrre da 4 a 10 token al secondo, mentre un modello 3B può produrne da 10 a 25. Una GPU è all'incirca un ordine di grandezza più veloce. Questi valori sono volutamente approssimativi. La scelta corretta è misurare il vostro server; il passaggio di esecuzione seguente mostra come farlo. Fidatevi dei vostri eval rate, non del numero riportato in un articolo, incluso questo.

La conclusione pratica è questa: i modelli quantizzati piccoli eseguiti sulla CPU sono realmente utili per redigere testi, creare riepiloghi e svolgere classificazioni, se potete accettarne la velocità. Per modelli più grandi o per ottenere risposte più rapide, prevedete il costo di un'istanza con GPU. Se preferite vedere questi calcoli applicati dall'inizio alla fine a un modello specifico, eseguire Nemotron 3.5 Lightning su una VPS spiega quale tag scaricare, quanta RAM richiede effettivamente e se l'esecuzione solo sulla CPU offre prestazioni sufficienti.

Per confrontare un modello specifico con un server specifico, stimate qui il suo ingombro in memoria:

ToolLLM VRAM and model-size calculator

Install Ollama

Esistono due metodi semplici. Lo script ufficiale è la soluzione più rapida su un VPS senza altri servizi:

curl -fsSL https://ollama.com/install.sh | sh

Questo crea un utente di sistema denominato ollama, installa il binario in /usr/local/bin/ollama e registra un servizio systemd denominato ollama.service, avviato al boot e in ascolto su 127.0.0.1:11434. Verifica che sia attivo:

systemctl status ollama
ollama --version

Se usi già Docker, utilizza invece il container:

docker run -d --name ollama \
  -p 127.0.0.1:11434:11434 \
  -v ollama:/root/.ollama \
  --restart always \
  ollama/ollama

Nota il prefisso 127.0.0.1: nella mappatura della porta. In questo modo la porta è associata soltanto a localhost. Se scrivi -p 11434:11434, la porta viene pubblicata su tutte le interfacce: è l'errore descritto nella sezione sulla sicurezza. Scegli un solo metodo di installazione. Non eseguire contemporaneamente lo script e il container, altrimenti due processi entrano in conflitto per la stessa porta.

Scaricare ed eseguire il primo modello

ollama pull llama3.2:3b
ollama run llama3.2:3b

pull scarica i layer del modello sul disco, circa 2 GB in questo caso. run li carica in memoria e apre un prompt >>>. Inserire una domanda. Il primo token può richiedere diversi secondi mentre i pesi vengono caricati dal disco nella RAM; quindi la risposta viene trasmessa in streaming. Inserire /bye per uscire dalla chat; Ollama continua a essere eseguito in background.

Verificare cosa è stato caricato e come viene utilizzato:

ollama ps

La colonna PROCESSOR mostra lo stato effettivo. 100% CPU significa che non viene utilizzata alcuna GPU; questa è la causa della lentezza. Misurare la velocità effettiva con il flag verbose:

ollama run --verbose llama3.2:3b "Write two sentences about Linux."

La riga eval rate visualizzata alla fine indica il numero di token al secondo ottenuto da questo hardware. Questo è il valore da considerare per la pianificazione.

Dove si trovano i modelli e quanto spazio su disco acquistare

Installati dallo script ed eseguiti come servizio, i modelli si trovano nella home dell'utente ollama:

sudo du -sh /usr/share/ollama/.ollama/models

Se li esegui interattivamente come utente personale, si trovano in ~/.ollama/models. Nel container si trovano nel volume denominato ollama. Questo aspetto è importante perché i pesi quantizzati occupano rapidamente molto spazio: un modello 3B occupa circa 2 GB, un modello 7-8B circa 5 GB e un modello 14B circa 9 GB. Se scarichi quattro modelli per confrontarli, puoi occupare 20 GB senza accorgertene. Dimensiona il disco in base ai modelli che intendi conservare ed elimina gli altri con ollama rm <model>. Se lo stesso VPS esegue già un altro servizio che richiede molto spazio, ad esempio PhotoPrism o Immich che conservano una libreria fotografica, sottrai prima quello spazio dalla capacità libera e considera ciò che rimane come il budget effettivo per i modelli.

Esegui il servizio sotto il tuo controllo

Lo script di installazione ha già registrato ollama.service, quindi il servizio viene riavviato all'avvio senza altre operazioni. Le impostazioni che vale la pena modificare sono il tempo di permanenza del modello in memoria e, in alcune configurazioni, l'indirizzo di bind. Entrambe vanno inserite in un drop-in di systemd, così un aggiornamento di Ollama non le sovrascrive:

sudo systemctl edit ollama.service

Aggiungi questo contenuto sotto l'intestazione [Service] mostrata dall'editor:

[Service]
Environment="OLLAMA_KEEP_ALIVE=30m"

OLLAMA_KEEP_ALIVE indica per quanto tempo un modello rimane in memoria dopo l'ultima richiesta (il valore predefinito è 5 minuti). Aumentalo su un server a cui invii richieste per tutta la giornata, per evitare di ricaricare i pesi ogni volta. Impostalo su 0 su un server con poca memoria, per liberare la RAM non appena termina una richiesta. Se vuoi mantenere un modello residente indefinitamente, invece che per un intervallo prestabilito, mantenere un modello Ollama caricato in modo permanente descrive il campo keep_alive per singola richiesta e come mantenere nuovamente i pesi già disponibili dopo un riavvio, invece di attendere la prima richiesta lenta. systemctl edit ricarica i file delle unità, quindi riavvia il servizio per applicare la modifica:

sudo systemctl restart ollama

Il punto di sicurezza più importante

Per impostazione predefinita, Ollama è in ascolto su 127.0.0.1:11434, quindi solo i processi presenti sul VPS possono raggiungerlo. Questa impostazione predefinita è corretta. Mantienila.

L'API non usa alcuna autenticazione. Nessuna. Non esistono chiavi API, accesso utente o rate limiting. L'unica allow-list disponibile, OLLAMA_ORIGINS, controlla soltanto quali origini del browser possono effettuare chiamate (CORS); non impedisce a curl o a uno script su un altro computer di connettersi. Chiunque possa raggiungere la porta 11434 può eseguire qualsiasi modello scaricato, scaricarne di nuovi, eliminarli e mantenere la CPU o la GPU al 100% indefinitamente. Scanner come Shodan indicizzano migliaia di istanze Ollama esposte e un'istanza pubblica viene individuata e abusata nel giro di poche ore.

Quindi esiste un unico errore da non commettere: non impostare OLLAMA_HOST=0.0.0.0 e non aprire la porta 11434 nel firewall. In questo modo esporresti a Internet un server di inferenza privo di autenticazione. Nessuna configurazione può rendere sicuro l'accesso diretto a 11434 su 0.0.0.0, perché nessuna delle impostazioni documentate di Ollama aggiunge l'autenticazione all'API locale e una allow-list delle origini non è un sistema di accesso. Questa regola riguarda questo servizio specifico, non vieta di aprire una porta in ogni circostanza: un relay RustDesk self-hosted per il desktop remoto deve accettare traffico pubblico per funzionare e lo fa usando una propria autenticazione basata su chiavi e un elenco breve e documentato di porte, caratteristiche che Ollama non offre.

Esistono tre modi sicuri per raggiungere il modello da un sistema diverso dal VPS:

  • Mantienilo locale. Se l'unico client è un altro programma sullo stesso VPS, uno script cron, un bot o un server MCP che collega i tuoi strumenti al modello, lascia il bind su 127.0.0.1 e configura il programma affinché chiami http://127.0.0.1:11434. Nulla viene esposto e non serve altro.
  • Raggiungilo tramite un tunnel privato. Inserisci il VPS in una VPN WireGuard gestita da te, imposta OLLAMA_HOST sull'indirizzo del tunnel (ad esempio 10.8.0.1, non 0.0.0.0) e consenti la connessione soltanto ai peer della VPN. Su Internet la porta 11434 continuerà a non essere visibile.
  • Usa un reverse proxy con autenticazione. Termina TLS e richiedi una password o un token tramite nginx, Traefik o Caddy, quindi inoltra le richieste a 127.0.0.1:11434. Ollama mantiene il bind su localhost; il proxy è l'unico componente in ascolto sulla porta pubblica. È lo stesso approccio adottato per mettere un certificato Let's Encrypt su nginx davanti a un servizio locale.

L'opzione del reverse proxy è esattamente quella che l'interfaccia chat offre nella sezione successiva, con un accesso utente reale associato.

Aggiungere un'interfaccia chat con Open WebUI, dietro TLS

Open WebUI è un'interfaccia chat self-hosted. Eseguirla in Docker e collegarla all'istanza locale di Ollama:

docker run -d \
  --name open-webui \
  --network=host \
  -e OLLAMA_BASE_URL=http://127.0.0.1:11434 \
  -v open-webui:/app/backend/data \
  --restart always \
  ghcr.io/open-webui/open-webui:main

Il flag --network=host è il dettaglio importante su una VPS Linux. Inserisce il container nel namespace di rete dell'host, quindi 127.0.0.1 all'interno del container corrisponde al loopback dell'host e il container raggiunge Ollama tramite 127.0.0.1:11434 senza che Ollama debba restare in ascolto su altre interfacce. La configurazione con bridge network descritta altrove, --add-host=host.docker.internal:host-gateway con OLLAMA_BASE_URL=http://host.docker.internal:11434, qui non funziona: quel nome viene risolto nell'indirizzo del gateway del bridge Docker e un servizio associato a 127.0.0.1 sull'host non è raggiungibile attraverso il bridge. Di conseguenza Open WebUI continua semplicemente a segnalare che non riesce a connettersi a Ollama.

Il compromesso del networking dell'host è che Open WebUI ora resta in ascolto sulla porta 8080 dell'host su tutte le interfacce; qualsiasi mapping -p viene ignorato e Docker stampa un avviso che lo conferma. Chiudi quindi 8080 sia sul firewall dell'host sia su quello del provider e lascia che il reverse proxy TLS sia l'unico punto di accesso pubblico. Alla prima visita Open WebUI chiede di creare un account amministratore. Questo account costituisce il livello di autenticazione, quindi scegli una password robusta.

Per aprire la chat dal laptop tramite HTTPS, configura un reverse proxy TLS davanti a 127.0.0.1:8080. Se sul server instradi già diverse applicazioni Docker, Traefik con TLS automatico per più applicazioni è la soluzione più adatta: un unico blocco di label rilascia il certificato e instrada chat.example.com verso Open WebUI. La stessa configurazione basata su una label per applicazione verrà usata da ogni altra interfaccia web del server, che si tratti di una dashboard di stato o di qualcosa di più originale come Halcyon, che presenta una libreria Jellyfin come un videonoleggio degli anni 90, ciascuna con il proprio hostname e il proprio accesso. La regola della sezione sulla sicurezza resta valida: il proxy gestisce la porta pubblica e l'autenticazione, mentre Ollama rimane su localhost e la porta 8080 di Open WebUI resta protetta dal firewall.

Usare l'endpoint compatibile con OpenAI dal codice

Ollama espone un sottoinsieme dell'API chat di OpenAI su /v1, quindi la maggior parte delle librerie client di OpenAI funziona dopo aver modificato due elementi: l'URL di base e una chiave usa e getta.

from openai import OpenAI

client = OpenAI(base_url="http://127.0.0.1:11434/v1", api_key="ollama")

resp = client.chat.completions.create(
    model="llama3.2:3b",
    messages=[{"role": "user", "content": "Name three Linux distributions."}],
)
print(resp.choices[0].message.content)

api_key è obbligatoria per la libreria client, ma Ollama la ignora, quindi è sufficiente una stringa qualsiasi. model deve corrispondere a un nome già scaricato; un nome sconosciuto restituisce un errore 404 con model 'x' not found. Una semplice chiamata curl segue lo stesso principio:

curl http://127.0.0.1:11434/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{"model":"llama3.2:3b","messages":[{"role":"user","content":"Hello"}]}'

È anche il modo per collegare il modello agli strumenti per agenti ed editor. Se sviluppi già sul server, un modello locale può supportare script e plugin insieme a Claude Code in esecuzione sul VPS all'interno di tmux, mantenendo le attività di stesura economiche e private fuori da un'API a pagamento, mentre il ragionamento più complesso resta affidato a un modello ospitato.

Modalità di errore, con le stringhe esatte visualizzate

Il processo viene terminato durante la generazione. Avvii un modello di grandi dimensioni e il terminale visualizza Killed, oppure il log del server (journalctl -u ollama) mostra una riga che inizia con llama-server process has terminated. Questa è la dicitura usata da Ollama 0.40.7, verificata il 21 ottobre 2026; le versioni precedenti visualizzavano llama runner process has terminated: signal: killed. Il killer OOM di Linux ha arrestato il processo perché il modello richiedeva più RAM di quella disponibile sul server. Conferma la causa con sudo dmesg | grep -i oom: visualizzerai una riga simile a Out of memory: Killed process .... La soluzione consiste nell'usare un modello più piccolo o con una quantizzazione più aggressiva, llama3.2:3b invece di un 13B, oppure nell'aggiungere swap, in modo che un carico che supera di poco la RAM fisica possa completarsi lentamente invece di terminare. Lo swap trasforma un arresto immediato in una risposta lenta; non rende pratico eseguire un modello 70B su 4 GB. La terminazione è silenziosa, a meno che tu non stia osservando il terminale. Su un server interrogato da un altro sistema, associare un'unità OnFailure= a ollama.service, che invia una notifica a un server ntfy che gestisci per ricevere notifiche push, permette di sapere subito quando il processo termina invece di accorgertene solo alla richiesta successiva.

Ollama rifiuta di caricare il modello. La richiesta fallisce immediatamente con un errore, senza arrestare il processo, e il log del server registra model is too large for system memory (Ollama 0.40.7, verificato il 21 ottobre 2026). Le versioni precedenti visualizzavano Error: model requires more system memory (X GiB) than is available (Y GiB) direttamente al prompt. È la versione ordinata dell'arresto descritto sopra: Ollama ha calcolato la memoria necessaria e si è fermato, invece di lasciare che intervenisse il killer OOM. Scegli un modello con requisiti inferiori alla RAM libera (controlla con free -h), riduci la lunghezza del contesto oppure passa a un VPS più grande. Nessun flag consente di far entrare il modello nella memoria disponibile: la memoria richiesta è effettiva.

Il primo token richiede molto tempo, poi tutto funziona normalmente. Un modello non ancora caricato non visualizza nulla per cinque-trenta secondi, quindi inizia a generare normalmente. La pausa è dovuta al caricamento iniziale dei pesi dal disco alla RAM, e uno storage lento la aumenta. Dopo il caricamento, il modello rimane residente per la durata di OLLAMA_KEEP_ALIVE, quindi il secondo prompt riceve una risposta immediata. Se il primo caricamento supera un timeout in un punto della catena della richiesta, ottieni un errore invece di una risposta lenta. Stabilire quale livello ha segnalato context deadline exceeded permette di capire se il timeout è stato causato dal client, dal proxy o dal caricamento stesso. Aumenta quel valore se le pause sono problematiche e usa ollama ps per verificare se un modello è attualmente caricato.

Tutto è semplicemente lento. Dieci token al secondo o meno, senza alcun errore. È l'inferenza su CPU che si comporta come previsto. ollama ps mostra 100% CPU, il che significa che non è disponibile alcuna GPU. Non è un bug e nessuna impostazione può trasformare una CPU in una GPU, perché il limite principale è la larghezza di banda della memoria. Su una VM vale comunque la pena provare un'impostazione: Ollama sceglie il numero di thread in base ai core fisici rilevati, ma un hypervisor può riportare un valore errato. In una sessione ollama run --verbose, prova /set parameter num_thread 4 (oppure il numero di vCPU), esegui di nuovo lo stesso prompt e mantieni il valore che offre il miglior eval rate. Oltre a questo, usa un modello più piccolo, accetta la velocità disponibile oppure passa a un'istanza con GPU. Prima di concludere che qualcosa non funziona, misura la velocità effettiva con --verbose. Quando l'attesa dipende dalla lunghezza della risposta e non dalla velocità di generazione, limitare la risposta con num_predict impedisce a un modello prolisso di impiegare minuti per generare token che non avresti comunque letto.

Connessione rifiutata da un altro computer. Dal laptop, curl 8.23.0 (verificato il 21 ottobre 2026) visualizza curl: (7) Failed to connect to <ip>:11434 after <n> ms: Could not connect to server, mentre la versione curl 8.5.0 inclusa in Ubuntu 24.04 visualizza curl: (7) Failed to connect to <ip> port 11434 after <n> ms: Couldn't connect to server. Le parole "Connection refused" compaiono solo se aggiungi -v, in una riga che contiene connect to <ip> port 11434 from ... failed: Connection refused. Questo comportamento è previsto: Ollama è in ascolto soltanto su localhost. Non "risolvere" il problema associando il servizio a 0.0.0.0, perché sarebbe esattamente l'errore di esposizione descritto sopra. Raggiungi il modello tramite la VPN o attraverso il proxy con autenticazione.

Hai esposto 11434 a Internet. Se hai impostato OLLAMA_HOST=0.0.0.0, aperto il firewall e ora visualizzi pull di modelli che non hai avviato oppure la CPU è al 100% a causa di client sconosciuti, il server è stato individuato e utilizzato da terzi. Questo è l'errore principale, non un caso limite. Configura nuovamente l'ascolto su 127.0.0.1 o sull'indirizzo della VPN, chiudi la porta 11434 nel firewall e configura l'autenticazione davanti al servizio. Considera come interrogato da estranei qualsiasi servizio raggiungibile a quell'indirizzo mentre la porta era aperta.

Backup e aggiornamenti

Lo stato da preservare è limitato. I modelli possono essere scaricati di nuovo, quindi vale la pena eseguire il backup solo del volume dati di Open WebUI, degli account, della cronologia delle chat, delle impostazioni e di eventuali drop-in di systemd creati manualmente. Eseguire il backup del volume con un container temporaneo:

docker run --rm -v open-webui:/data -v "$PWD":/backup alpine \
  tar czf /backup/open-webui.tgz -C /data .

Aggiornare Ollama eseguendo di nuovo lo script di installazione; aggiornare Open WebUI con docker pull ghcr.io/open-webui/open-webui:main, quindi ricreare il container. Una nota sul disco per la serie 0.40: Ollama 0.40.2 ha iniziato ad aggiornare in background i modelli scaricati con le versioni precedenti e conserva le copie originali come backup. Di conseguenza, queste copie occupano spazio aggiuntivo finché non vengono rimosse; la versione 0.40.3 (11 October 2026) ha sospeso questo aggiornamento in background. Dopo un aggiornamento, controllare df -h e consultare le note di rilascio per individuare il comando che elimina questi backup. Non bloccare le versioni a lungo termine: la qualità dei modelli e il runtime evolvono rapidamente. Consultare quindi le note di rilascio e ripetere i benchmark sul proprio server, invece di fare affidamento sui risultati dello scorso trimestre.

FAQ

Posso davvero eseguire un LLM su un VPS con solo CPU?

Sì, entro certi limiti. I modelli quantizzati di piccole dimensioni, nella fascia da 3B a 8B, funzionano su CPU e sono realmente utili per creare bozze, riepiloghi e classificazioni, ma sono lenti: su una vCPU condivisa raggiungono da pochi token al secondo fino a valori a due cifre basse. I modelli da 13B in su sono estremamente lenti oppure non entrano affatto nella RAM disponibile. Per ottenere una velocità maggiore o usare modelli più grandi serve un'istanza con GPU.

Quanta RAM richiede ogni modello?

Per i tag a 4 bit (Q4) usati per impostazione predefinita dalla maggior parte dei modelli più diffusi, una stima approssimativa è di circa 0.5 GB di RAM per ogni miliardo di parametri per i pesi, più circa 1 GB di overhead e una quantità aggiuntiva per il contesto. Un modello da 3B richiede quindi circa 4 GB liberi, uno da 7-8B circa 8 GB e uno da 14B circa 16 GB. Verifica lo spazio disponibile con free -h e lascia margine per il sistema operativo e per gli altri servizi presenti sul server.

L'API di Ollama è autenticata?

No. Ollama non offre autenticazione integrata, chiavi API o rate limiting: chiunque possa raggiungere la porta 11434 ne ha il controllo completo. L'impostazione OLLAMA_ORIGINS limita soltanto le origini del browser autorizzate a chiamarla, non gli utenti che possono connettersi. Per questo, per impostazione predefinita, Ollama è in ascolto su 127.0.0.1 e non devi mai esporre la porta 11434 su 0.0.0.0 verso Internet. Raggiungila localmente, tramite una VPN privata oppure attraverso un reverse proxy che aggiunga una schermata di accesso.

Come aggiungo un'interfaccia web per la chat?

Esegui Open WebUI in Docker con --network=host, in modo che condivida il loopback dell'host e raggiunga Ollama nativo su http://127.0.0.1:11434. Quindi configura un reverse proxy TLS davanti alla sua porta 8080 per accedervi dal laptop. Mantieni 8080 chiusa nel firewall, così il proxy resta l'unico punto di accesso pubblico. L'account amministratore di Open WebUI fornisce l'autenticazione; imposta la password al primo avvio.

Come posso chiamarlo dalla mia applicazione?

Usa l'endpoint compatibile con OpenAI disponibile su http://127.0.0.1:11434/v1. Indirizza qualsiasi SDK OpenAI a quell'URL di base, passa una stringa qualsiasi come chiave API perché viene ignorata e imposta model sul nome di un modello che hai scaricato. Il codice OpenAI esistente di solito funziona senza modifiche, salvo per l'URL di base e la chiave.