Como hospedar o Ollama com segurança em um VPS
Um modelo 7B precisa de 8 GB de RAM e entrega 4 a 10 tokens por segundo na CPU. Use 127.0.0.1:11434/v1 e mantenha a porta 11434 fechada.
O que você vai criar
Um único modelo de linguagem de pesos abertos, executado num servidor sob o seu controlo, respondendo através de uma API HTTP e, se quiser, com uma página de chat no navegador. O Ollama é o componente que descarrega o modelo, o carrega na memória e atende pedidos em http://127.0.0.1:11434. A instalação requer um único comando. A parte difícil está noutros pontos: escolher um modelo que o seu VPS consiga manter na RAM e não publicar acidentalmente um servidor de inferência sem autenticação em toda a Internet.
Primeiro, dois avisos importantes. Um VPS apenas com CPU executa modelos pequenos lentamente e a API não tem autenticação incorporada. Ambos os pontos são abordados em detalhe abaixo, porque são as situações que mais frequentemente causam problemas.
A verificação realista do dimensionamento, em números simples
A memória ocupada por um modelo corresponde aproximadamente ao tamanho do ficheiro, mais cerca de 1 GB de sobrecarga de execução e mais alguma memória para a janela de contexto. Os modelos predefinidos do Ollama usam quantização de 4 bits (identificada como Q4), que consome cerca de 0,5 GB de RAM por cada mil milhões de parâmetros. Por isso, o cálculo é simples e determina tudo. O último termo é definido por si: aumentar num_ctx acima do valor predefinido reduzido do Ollama dá espaço para prompts mais longos, mas aumenta a cache KV em RAM. Defina o tamanho do contexto antes de avaliar se um modelo cabe.
Um modelo 3B, como llama3.2:3b, é uma transferência de ~2 GB e precisa de cerca de 4 GB de RAM livre para funcionar. Um modelo 7B ou 8B, como mistral:7b ou llama3.1:8b, ocupa ~5 GB em disco e precisa de cerca de 8 GB de RAM; 16 GB dão uma margem confortável. Um modelo 13B ou 14B precisa de aproximadamente 16 GB. Qualquer modelo entre 30B e 70B precisa de um servidor com muita RAM ou, realisticamente, de uma GPU. Num VPS com CPU, não cabe ou responde tão lentamente que se torna inútil.
Agora, a velocidade, porque este é o aspeto que costuma ser subestimado. A inferência em CPU é limitada pela largura de banda da memória, não pela velocidade do clock, e um vCPU partilhado num VPS tem uma largura de banda moderada. Conte com valores de um dígito baixo a dois dígitos baixos de tokens por segundo: um modelo 7-8B Q4 pode atingir 4 a 10 tokens por segundo, e um modelo 3B, 10 a 25. Uma GPU é aproximadamente uma ordem de grandeza mais rápida. Estes valores são deliberadamente aproximados. A abordagem correta é medir o seu próprio servidor, como mostrado no passo de execução abaixo. Confie no seu eval rate, não num número publicado num artigo, incluindo este.
A conclusão prática é a seguinte: modelos pequenos quantizados em CPU são realmente úteis para criar rascunhos, resumir e classificar, se aceitar essa velocidade. Para modelos maiores ou mais rápidos, reserve orçamento para uma instância com GPU. Se preferir ver este cálculo aplicado do início ao fim a um modelo específico, executar o Nemotron 3.5 Lightning num VPS mostra qual a tag a transferir, a RAM de que realmente precisa e se a execução apenas em CPU acompanha o ritmo.
Para comparar um modelo específico com um servidor específico, estime aqui a memória ocupada:
Instalar o Ollama
Existem duas formas simples. O script oficial é a opção mais fácil numa VPS sem outros componentes:
curl -fsSL https://ollama.com/install.sh | shIsto cria um utilizador de sistema chamado ollama, instala o binário em /usr/local/bin/ollama e regista um serviço systemd chamado ollama.service, que inicia no boot e escuta em 127.0.0.1:11434. Confirme que está ativo:
systemctl status ollama
ollama --versionSe já utiliza Docker, use o contentor:
docker run -d --name ollama \
-p 127.0.0.1:11434:11434 \
-v ollama:/root/.ollama \
--restart always \
ollama/ollamaTenha em atenção o prefixo 127.0.0.1: no mapeamento da porta. Isto liga a porta apenas a localhost. Se escrever -p 11434:11434, a porta fica publicada em todas as interfaces. Esse é o erro alertado na secção de segurança. Escolha um método de instalação. Não execute o script e o contentor ao mesmo tempo, porque os dois processos entram em conflito pela mesma porta.
Obtenha e execute o seu primeiro modelo
ollama pull llama3.2:3b
ollama run llama3.2:3bpull transfere as camadas do modelo para o disco (cerca de 2 GB neste caso). run carrega-as para a memória e apresenta um prompt >>>. Introduza uma pergunta. O primeiro token pode demorar vários segundos enquanto os pesos são carregados do disco para a RAM. Depois, a resposta é transmitida. Introduza /bye para sair do chat. O Ollama continua a executar-se em segundo plano.
Veja o que está carregado e como é utilizado:
ollama psA coluna PROCESSOR mostra a situação real. 100% CPU significa que não existe uma GPU envolvida. Essa é a causa da lentidão. Meça a velocidade real com a flag verbose:
ollama run --verbose llama3.2:3b "Write two sentences about Linux."A linha eval rate apresentada no fim mostra o número de tokens por segundo neste hardware. Esse é o valor que deve usar no planeamento.
Onde os modelos ficam e quanto espaço em disco reservar
Instalados pelo script e executados como um serviço, os modelos ficam no diretório pessoal do utilizador ollama:
sudo du -sh /usr/share/ollama/.ollama/modelsQuando são executados interativamente pelo seu próprio utilizador, ficam em ~/.ollama/models. No contentor, ficam no volume nomeado ollama. Isto é importante porque os pesos quantizados ocupam espaço rapidamente: um modelo 3B ocupa cerca de 2 GB, um modelo 7-8B ocupa cerca de 5 GB e um modelo 14B ocupa cerca de 9 GB. Transfira quatro modelos para os comparar e terá ocupado 20 GB sem se aperceber. Dimensione o disco para os modelos que pretende manter e elimine os restantes com ollama rm <model>. Se o mesmo VPS já executar algo com um consumo elevado de espaço, como PhotoPrism ou Immich com uma biblioteca de fotografias, subtraia primeiro esse espaço ao espaço livre e considere o restante como o orçamento real para os modelos.
Execute-o como um serviço sob o seu controlo
O script de instalação já registou ollama.service, por isso o serviço é reiniciado no boot sem trabalho adicional. A configuração que vale a pena alterar é o tempo durante o qual um modelo permanece residente e, em algumas configurações, o endereço de bind. Ambas devem ficar num drop-in do systemd, para que uma atualização do Ollama não as substitua:
sudo systemctl edit ollama.serviceAdicione isto sob o cabeçalho [Service] apresentado pelo editor:
[Service]
Environment="OLLAMA_KEEP_ALIVE=30m"OLLAMA_KEEP_ALIVE define durante quanto tempo um modelo permanece na memória depois do último pedido (o valor predefinido é 5 minutos). Aumente-o num servidor ao qual faz pedidos durante todo o dia, para evitar recarregar os pesos a cada pedido. Defina-o como 0 num servidor com pouca memória, para libertar a RAM assim que o pedido terminar. Se quiser manter um modelo residente indefinidamente, em vez de o manter durante uma janela fixa, manter um modelo Ollama carregado permanentemente explica o campo keep_alive por pedido e como voltar a aquecer os pesos depois de um reboot, em vez de o fazer no primeiro pedido lento. systemctl edit recarrega os ficheiros das unidades automaticamente, por isso reinicie para aplicar a alteração:
sudo systemctl restart ollamaO aspeto de segurança mais importante
Por predefinição, o Ollama faz bind em 127.0.0.1:11434, pelo que apenas os processos no próprio VPS conseguem aceder-lhe. Esta predefinição está correta. Mantenha-a.
A API não tem autenticação. Nenhuma. Não existe chave de API, login, limite de pedidos nem lista de permissões. Qualquer pessoa que consiga aceder à porta 11434 pode executar qualquer modelo que tenha transferido, transferir modelos novos, eliminá-los e manter o CPU ou GPU a 100% de utilização indefinidamente. Scanners como o Shodan indexam milhares de instâncias Ollama abertas, e uma instância exposta é encontrada e abusada em poucas horas.
O erro que nunca deve cometer é este: não configure OLLAMA_HOST=0.0.0.0 e abra a porta 11434 na firewall. Isso publica um servidor de inferência sem autenticação em toda a Internet. Nenhuma configuração torna o acesso direto à porta 11434 em 0.0.0.0 seguro, porque não há autenticação para configurar no Ollama: esse mecanismo simplesmente não existe. Esta regra aplica-se a este serviço específico, não é uma proibição geral de abrir portas: um relay RustDesk autoalojado para acesso remoto ao ambiente de trabalho precisa de aceitar tráfego público para funcionar e justifica essa exposição com a sua própria autenticação baseada em chave e uma lista curta e documentada de portas. O Ollama não oferece nada disso.
Existem três formas seguras de aceder ao modelo a partir de outro local:
- Mantenha-o local. Se o único cliente for outro programa no mesmo VPS, um script cron, um bot ou um servidor MCP que liga as suas ferramentas ao modelo, deixe o bind em
127.0.0.1e faça esse programa chamarhttp://127.0.0.1:11434. Nada fica exposto e não é necessário mais nada. - Aceda através de um túnel privado. Coloque o VPS numa VPN WireGuard que aloja e defina
OLLAMA_HOSTpara o endereço do túnel (por exemplo,10.8.0.1, não0.0.0.0). Apenas os peers da VPN poderão ligar-se. A Internet pública continuará sem ver nada na porta 11434. - Coloque um reverse proxy com autenticação à frente. Termine o TLS e exija uma palavra-passe ou um token no nginx, Traefik ou Caddy. Depois, faça proxy para
127.0.0.1:11434. O Ollama mantém o bind em localhost; o proxy é o único serviço a escutar na porta pública. Este é o mesmo modelo usado para colocar um certificado Let's Encrypt no nginx à frente de qualquer serviço local.
A opção de reverse proxy é exatamente a que a interface de chat disponibiliza a seguir, com um login real associado.
Adicionar uma interface de chat com Open WebUI, protegida por TLS
O Open WebUI é uma interface de chat auto-hospedada. Execute-o no Docker e aponte-o para o Ollama local:
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:mainA opção --network=host é o detalhe importante numa VPS Linux. Ela coloca o contentor no namespace de rede do host. Assim, 127.0.0.1 dentro do contentor corresponde ao loopback do próprio host, e o contentor alcança o Ollama através de 127.0.0.1:11434 sem que o Ollama escute noutra interface. A configuração de rede bridge apresentada noutro local, --add-host=host.docker.internal:host-gateway com OLLAMA_BASE_URL=http://host.docker.internal:11434, não funciona aqui. Esse nome resolve para o gateway da bridge do Docker. Um serviço ligado a 127.0.0.1 no host não fica acessível através da bridge. Por isso, o Open WebUI fica a indicar que não consegue ligar-se ao Ollama.
A desvantagem da rede do host é que o Open WebUI passa a escutar na porta 8080 do host em todas as interfaces. Qualquer mapeamento -p é ignorado, e o Docker apresenta um aviso a indicar isso. Por isso, feche 8080 tanto no host como na firewall do fornecedor. Deixe o reverse proxy TLS ser o único ponto de acesso público. Na primeira visita, o Open WebUI pede-lhe para criar uma conta de administrador. Essa conta é a sua camada de autenticação. Escolha uma palavra-passe forte.
Para abrir o chat no portátil através de HTTPS, coloque um reverse proxy TLS à frente de 127.0.0.1:8080. Se já encaminha várias aplicações Docker no servidor, Traefik com TLS automático para várias aplicações é a opção mais adequada. Um único bloco de labels emite o certificado e encaminha chat.example.com para o Open WebUI. Esse mesmo encaminhamento baseado numa label por aplicação será usado por todas as outras interfaces Web no servidor, seja um dashboard de estado ou algo mais descontraído, como Halcyon, que apresenta uma biblioteca Jellyfin como uma loja de aluguer dos anos 90, cada uma no seu próprio hostname e protegida pelo seu próprio login. A regra da secção de segurança continua válida: o proxy controla a porta pública e o login, enquanto o Ollama permanece em localhost e a própria porta 8080 do Open WebUI continua protegida pela firewall.
Use o endpoint compatível com OpenAI a partir do seu código
Ollama disponibiliza um subconjunto da API de chat da OpenAI em /v1. Por isso, a maioria das bibliotecas cliente da OpenAI funciona depois de alterar duas coisas: o URL base e uma chave descartável.
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)A api_key é obrigatória para a biblioteca cliente, mas é ignorada pelo Ollama. Qualquer cadeia de caracteres funciona. model deve ser o nome de um modelo que já tenha obtido. Um nome desconhecido devolve model "x" not found, try pulling it first. Uma chamada simples com curl segue a mesma ideia:
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"}]}'Também é assim que liga o modelo a ferramentas de agentes e editores. Se já desenvolve nesse servidor, um modelo local pode executar scripts e plugins em conjunto com o Claude Code em execução no VPS dentro do tmux, mantendo o trabalho de elaboração privado e de baixo custo fora de uma API paga, enquanto o raciocínio mais exigente permanece num modelo alojado.
Modos de falha, com as strings exatas que verá
O processo é "Killed" durante a geração. Você inicia um modelo grande e o terminal exibe Killed, ou o log do servidor mostra llama runner process has terminated: signal: killed. O OOM killer do Linux interrompeu o processo porque o modelo precisava de mais RAM do que o servidor tem. Confirme a causa com sudo dmesg | grep -i oom, onde verá uma linha como Out of memory: Killed process ... (ollama). A correção é usar um modelo menor ou com quantização mais agressiva, llama3.2:3b em vez de um modelo 13B, ou adicionar swap para que uma carga que excede por pouco a RAM física sobreviva lentamente em vez de terminar. A swap transforma uma falha instantânea numa resposta lenta; ela não torna um modelo 70B viável em 4 GB. O encerramento é silencioso, a menos que você esteja monitorando o terminal. Por isso, num servidor consultado a partir de outro local, associar uma unidade OnFailure= a ollama.service, que envia uma notificação para um servidor ntfy que você hospeda para enviar alertas push, informa o momento exato em que o processo termina, em vez de deixar você descobrir isso apenas na próxima solicitação.
"Error: model requires more system memory". O Ollama recusa iniciar o modelo e apresenta Error: model requires more system memory (X GiB) than is available (Y GiB). Esta é a versão controlada da falha anterior: o Ollama fez os cálculos e parou, em vez de deixar o OOM killer interromper o processo. Também apresenta os dois valores. Escolha um modelo cujo requisito seja inferior à RAM livre (verifique com free -h), reduza o tamanho do contexto ou mude para um VPS maior. Nenhuma flag faz o modelo caber. A memória necessária é real.
O primeiro token demora muito, depois fica normal. Um modelo frio não imprime nada durante cinco a trinta segundos e, depois, transmite a resposta normalmente. Essa pausa ocorre porque os pesos são carregados do disco para a RAM pela primeira vez, e o armazenamento lento agrava o problema. Depois de carregado, o modelo permanece residente durante o período definido por OLLAMA_KEEP_ALIVE, por isso o segundo prompt recebe uma resposta instantânea. Se esse primeiro carregamento ultrapassar um timeout em algum ponto do caminho da chamada, ocorrerá um erro em vez de uma resposta lenta. Identificar qual camada reportou o erro context deadline exceeded permite saber se o cliente, o proxy ou o próprio carregamento ficou sem tempo de espera. Aumente esse valor se as pausas forem incómodas e use ollama ps para verificar se há um modelo carregado.
Tudo está simplesmente lento. Dez tokens por segundo ou menos, sem qualquer erro. Isso é a inferência em CPU a funcionar exatamente como esperado. ollama ps mostra 100% CPU, o que significa que não há GPU. Isto não é um bug e nenhuma definição o corrige, porque o limite é a largura de banda da memória, não uma configuração incorreta. Use um modelo menor, aceite a velocidade ou mude para uma instância com GPU. Meça a taxa real com --verbose antes de concluir que há uma falha. Quando a espera resulta do comprimento da resposta e não da taxa, limitar a resposta com num_predict impede que um modelo propenso a divagar passe minutos a gerar tokens que nunca iria ler.
Connection refused a partir de outra máquina. A partir do portátil, recebe curl: (7) Failed to connect to <ip> port 11434: Connection refused. Isto funciona conforme concebido: o Ollama associa-se apenas a localhost. Não tente "corrigir" o problema associando-o a 0.0.0.0, pois esse é precisamente o erro de exposição descrito acima. Aceda ao modelo através da VPN ou de um proxy com autenticação.
Expôs a porta 11434 à Internet. Se definiu OLLAMA_HOST=0.0.0.0, abriu a firewall e agora vê operações de pull de modelos que não iniciou ou a CPU fixada a 100% por clientes desconhecidos, o servidor foi encontrado e utilizado. Este é o erro principal, não um caso excecional. Volte a associar o serviço a 127.0.0.1 ou ao endereço da VPN, feche a porta 11434 na firewall e coloque a autenticação à frente do serviço. Parta do princípio de que qualquer serviço acessível nesse endereço enquanto a porta esteve aberta foi consultado por terceiros.
Backups e upgrades
Há pouco estado a perder. Os modelos podem ser descarregados novamente. Por isso, os únicos dados que vale a pena salvaguardar são o volume de dados do Open WebUI, as contas, o histórico de conversas, as definições e qualquer drop-in do systemd que tenha criado. Faça uma cópia de segurança do volume com um contentor temporário:
docker run --rm -v open-webui:/data -v "$PWD":/backup alpine \
tar czf /backup/open-webui.tgz -C /data .Atualize o Ollama executando novamente o script de instalação. Atualize o Open WebUI com docker pull ghcr.io/open-webui/open-webui:main e recrie o contentor. Não fixe versões a longo prazo. A qualidade dos modelos e o runtime evoluem rapidamente. Leia as notas de versão e repita os benchmarks no seu próprio servidor, em vez de confiar nos números do último trimestre.
FAQ
Posso realmente executar um LLM numa VPS apenas com CPU?
Sim, dentro de certos limites. Modelos pequenos quantizados, na faixa de 3B a 8B, funcionam em CPU e são úteis para redigir, resumir e classificar, mas de forma lenta: normalmente produzem apenas alguns tokens por segundo ou valores baixos de dois dígitos numa vCPU partilhada. Qualquer modelo de 13B ou superior será extremamente lento ou nem sequer caberá na RAM. Para obter velocidade real ou executar modelos maiores, precisa de uma instância com GPU.
De quanta RAM precisa cada modelo?
Uma regra aproximada para os modelos quantizados de 4 bits predefinidos é reservar cerca de 0.5 GB de RAM por mil milhões de parâmetros para os pesos, mais aproximadamente 1 GB de sobrecarga e um pouco mais para o contexto. Assim, um modelo de 3B precisa de cerca de 4 GB livres, um modelo de 7-8B de cerca de 8 GB e um modelo de 14B de cerca de 16 GB. Verifique a margem disponível com free -h e deixe espaço para o sistema operativo e para os restantes serviços do servidor.
A API do Ollama tem autenticação?
Não. O Ollama não tem autenticação integrada, chave de API nem limite de pedidos. Qualquer pessoa que consiga alcançar a porta 11434 tem controlo total sobre o serviço. É precisamente por isso que ele fica ligado a 127.0.0.1 por predefinição e que nunca deve expor a porta 11434 em 0.0.0.0 para a Internet. Aceda ao serviço localmente, através de uma VPN privada ou por meio de um reverse proxy que acrescente um início de sessão.
Como adiciono uma interface de chat web?
Execute o Open WebUI no Docker com --network=host para partilhar o loopback do anfitrião e alcançar o Ollama nativo em http://127.0.0.1:11434. Em seguida, coloque um reverse proxy TLS à frente da porta 8080 para permitir o acesso a partir do seu portátil. Mantenha 8080 fechada na firewall para que o proxy seja a única porta pública. A própria conta de administrador do Open WebUI fornece o início de sessão, e a palavra-passe é definida no primeiro arranque.
Como o chamo a partir da minha própria aplicação?
Use o endpoint compatível com OpenAI em http://127.0.0.1:11434/v1. Aponte qualquer SDK da OpenAI para esse URL base, forneça qualquer texto como chave de API, porque ela é ignorada, e defina model com o nome de um modelo que tenha descarregado. O código existente da OpenAI normalmente funciona sem alterações, exceto pelo URL base e pela chave.