DEV Community

Cover image for Rodando um LLM localmente no Linux: Ollama, Open WebUI e os perrengues com NVIDIA
Marcos Faneli
Marcos Faneli

Posted on

Rodando um LLM localmente no Linux: Ollama, Open WebUI e os perrengues com NVIDIA

Nos últimos tempos, tenho estudado bastante sobre LLMs e resolvi fazer uma experiência relativamente simples: rodar um modelo de linguagem completamente local na minha máquina.

A ideia era entender melhor o que existe por trás de ferramentas como ChatGPT, Claude e Gemini, mas sem depender de uma API externa.

O objetivo inicial parecia simples:

Instalar um LLM, abrir uma interface parecida com o ChatGPT e começar a conversar com ele.

Na prática, a experiência acabou sendo muito mais interessante.

Passei por Ollama, Docker, Open WebUI, problemas de rede entre container e host, configuração de driver NVIDIA, CUDA, CPU/GPU offloading e, finalmente, uma demonstração prática de por que VRAM importa tanto quando falamos de LLMs locais.

Este artigo conta esse caminho.


O ambiente

A máquina que eu uso não é exatamente o suprassumo da computação:

CPU: Intel Core i7-7500U @ 2.70 GHz
Cores: 2
Threads: 4

GPU integrada:
Intel HD Graphics 620

GPU dedicada:
NVIDIA GeForce 940MX
VRAM: 2 GB

Sistema:
Linux Mint
Enter fullscreen mode Exit fullscreen mode

O modelo que escolhi inicialmente foi:

Qwen3 8B
Quantização: Q4_K_M
Tamanho em disco: ~5.2 GB
Enter fullscreen mode Exit fullscreen mode

Primeiro passo: Ollama

Para executar o modelo localmente, eu escolhi o Ollama.

Para baixá-lo, fui direto no site, na opção de download para Linux, e recebi o seguinte comando:

curl -fsSL https://ollama.com/install.sh | sh
Enter fullscreen mode Exit fullscreen mode

Depois da instalação, baixei e executei o modelo:

ollama run qwen3:8b
Enter fullscreen mode Exit fullscreen mode

Finalizado o download, apareceu o prompt, então fiz uma pergunta.

Funcionou! Mas nesse momento, já havia algo bem legal acontecendo:

Fluxo local: prompt, Ollama, Qwen3 8B e processamento em CPU/GPU

Tudo local, sem precisar enviar o prompt para uma API externa.

Para confirmar os modelos instalados:

ollama list
Enter fullscreen mode Exit fullscreen mode

No meu caso:

NAME        SIZE
qwen3:8b    5.2 GB
Enter fullscreen mode Exit fullscreen mode

Também é possível verificar diretamente a API do Ollama:

curl http://localhost:11434/api/tags
Enter fullscreen mode Exit fullscreen mode

O Ollama expõe uma API HTTP local na porta 11434, isso significa que, além de usar o terminal, uma aplicação Java, Python, JavaScript ou qualquer outro cliente HTTP pode conversar diretamente com o modelo.

Mas eu queria algo mais confortável, queria uma interface parecida com o ChatGPT.


Entrando o Open WebUI

Para isso, eu precisava de uma interface amigável de interação, escolhi o Open WebUI.

A arquitetura seria:

Browser, Open WebUI e Ollama conectados localmente

Eu coloquei o Open WebUI em Docker, a interface abriu normalmente, só havia um pequeno problema, nenhum modelo aparecia.. O Ollama funcionava pelo terminal, a API funcionava, o modelo estava instalado, mas o Open WebUI não encontrava nada.


O primeiro problema: localhost não é sempre localhost

Foi aí que apareceu uma característica importante do Docker, o Ollama estava executando diretamente no Linux:

Ollama no host Linux e Open WebUI no container têm localhosts diferentes

Enquanto o Open WebUI estava dentro de um container Docker.

Inicialmente, parecia natural configurar:

http://localhost:11434
Enter fullscreen mode Exit fullscreen mode

Mas havia um detalhe fundamental, para o Open WebUI executando dentro do container, localhost significa o próprio container e não o host Linux.

Então eu tentei acessar o host usando:

http://host.docker.internal:11434
Enter fullscreen mode Exit fullscreen mode

E adicionei:

--add-host=host.docker.internal:host-gateway
Enter fullscreen mode Exit fullscreen mode

ao container.

O DNS funcionou, testando assim:

docker exec open-webui getent hosts host.docker.internal
Enter fullscreen mode Exit fullscreen mode

retornando algo como:

172.17.0.1 host.docker.internal
Enter fullscreen mode Exit fullscreen mode

Mas ainda assim a conexão com o Ollama dava timeout.


Verificando onde o Ollama estava escutando

Eu configurei o serviço do Ollama para escutar em todas as interfaces:

0.0.0.0:11434
Enter fullscreen mode Exit fullscreen mode

Para isso:

sudo systemctl edit ollama
Enter fullscreen mode Exit fullscreen mode

Eu adicionei:

[Service]
Environment="OLLAMA_HOST=0.0.0.0:11434"
Enter fullscreen mode Exit fullscreen mode

Depois reiniciei o serviço:

sudo systemctl daemon-reload
sudo systemctl restart ollama
Enter fullscreen mode Exit fullscreen mode

Mesmo assim, ainda havia problemas de comunicação pela bridge do Docker, foi então que eu simplifiquei a arquitetura.


Docker usando a rede do host

Como tudo estava rodando na mesma máquina e o objetivo era estudo, eu executei o Open WebUI usando:

--network=host
Enter fullscreen mode Exit fullscreen mode

O container ficou assim:

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

Agora eu podia testar a comunicação de dentro do container:

docker exec open-webui \
  curl http://127.0.0.1:11434/api/tags
Enter fullscreen mode Exit fullscreen mode

E finalmente recebi:

{
  "models": [
    {
      "name": "qwen3:8b"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

Open WebUI e Ollama estavam conversando, depois de ajustar a conexão do Open WebUI para:

http://127.0.0.1:11434
Enter fullscreen mode Exit fullscreen mode

o qwen3:8b apareceu na interface.

Problema resolvido ou pelo menos parecia.


O modelo demorava uma eternidade

Eu enviei a mesma pergunta pelo Open WebUI.

Esperei...

E esperei...

E esperei mais um pouco...

Nada!

Nesse momento, surgiu a dúvida:

O sistema está travado ou o modelo simplesmente é muito lento?

O Ollama tem um comando excelente para responder isso:

ollama ps
Enter fullscreen mode Exit fullscreen mode

O resultado foi:

NAME        SIZE      PROCESSOR    CONTEXT
qwen3:8b    5.9 GB    100% CPU     4096
Enter fullscreen mode Exit fullscreen mode

A resposta estava ali:

100% CPU.

O modelo não estava travado, ele estava calculando. O problema era que eu estava tentando executar um modelo de aproximadamente 8 bilhões de parâmetros usando um:

Intel Core i7-7500U
2 cores
4 threads
Enter fullscreen mode Exit fullscreen mode

Não exatamente o cenário ideal, mas havia uma NVIDIA na máquina.


E a GeForce 940MX?

O Linux detectava a placa:

lspci | grep -Ei 'VGA|3D|Display'
Enter fullscreen mode Exit fullscreen mode

Resultado:

Intel HD Graphics 620
NVIDIA GeForce 940MX
Enter fullscreen mode Exit fullscreen mode

Então por que o Ollama estava usando apenas CPU?

Eu rodei:

nvidia-smi
Enter fullscreen mode Exit fullscreen mode

E recebi:

NVIDIA-SMI has failed because it couldn't communicate
with the NVIDIA driver.
Enter fullscreen mode Exit fullscreen mode

Agora eu tinha outro problema, o hardware existia, mas o driver NVIDIA não estava funcionando corretamente.


Investigando o driver NVIDIA

Primeiro, eu verifiquei os drivers disponíveis:

ubuntu-drivers devices
Enter fullscreen mode Exit fullscreen mode

O sistema recomendava:

nvidia-driver-580
Enter fullscreen mode Exit fullscreen mode

Também verifiquei o kernel:

uname -r
Enter fullscreen mode Exit fullscreen mode

e o Secure Boot:

mokutil --sb-state
Enter fullscreen mode Exit fullscreen mode

O Secure Boot estava desabilitado, que segundo uma boa e velah pesquisa no Google é uma causa comum de módulos NVIDIA não carregarem. Instalei o driver, porém mesmo depois da instalação do driver ao executar o comando:

nvidia-smi
Enter fullscreen mode Exit fullscreen mode

continuava falhando, então eu fui um nível abaixo.

sudo modprobe nvidia
Enter fullscreen mode Exit fullscreen mode

E apareceu um erro curioso:

could not find module by name='off'
could not insert 'off'
Enter fullscreen mode Exit fullscreen mode

Essa mensagem foi uma pista importante, o sistema estava tentando resolver o módulo nvidia como off.

Em máquinas com gráficos híbridos Intel + NVIDIA, o PRIME pode manter a GPU NVIDIA desativada dependendo do perfil selecionado.

Eu verifiquei então:

prime-select query
Enter fullscreen mode Exit fullscreen mode

e ajustei o perfil NVIDIA.

Depois do reboot, finalmente:

nvidia-smi
Enter fullscreen mode Exit fullscreen mode

retornou:

NVIDIA GeForce 940MX
Driver Version: 580.173.02
CUDA Version: 13.0
VRAM: 2048 MiB
Enter fullscreen mode Exit fullscreen mode

A GPU estava funcionando.


Agora o Ollama vai voar, certo?

Não exatamente, eEu reiniciei o Ollama, carreguei novamente o Qwen3 e executei:

ollama ps
Enter fullscreen mode Exit fullscreen mode

Resultado:

PROCESSOR
95%/5% CPU/GPU
Enter fullscreen mode Exit fullscreen mode

E aqui veio talvez a parte mais interessante de todo o experimento, a GPU estava funcionando, o Ollama estava usando a GPU, mas apenas uma pequena parte do modelo estava sendo processada por ela.

Por quê?


VRAM: encontramos o próximo gargalo

A GeForce 940MX possui:

2 GB VRAM
Enter fullscreen mode Exit fullscreen mode

O Qwen3 8B estava ocupando aproximadamente:

6.2 GB
Enter fullscreen mode Exit fullscreen mode

Além disso, parte da VRAM já estava sendo utilizada pelo ambiente gráfico, portanto simplesmente não havia memória suficiente para colocar uma parte significativa do modelo na GPU. A situação era aproximadamente:

O modelo de aproximadamente 6 GB excede a VRAM de 2 GB e precisa de offloading para RAM e CPU

O resultado observado pelo Ollama:

95% CPU
5% GPU
Enter fullscreen mode Exit fullscreen mode

Ou seja: configurar corretamente a GPU melhorou o ambiente, mas não transformou uma GPU de 2 GB em uma GPU adequada para um modelo de 8B parâmetros.

E essa talvez tenha sido a melhor lição do experimento.


Ter uma NVIDIA não significa que o LLM rodará bem

Antes dessa experiência, seria fácil para mim resumir os requisitos como:

É melhor ter uma GPU NVIDIA porque LLM usa CUDA.

Isso está correto, mas é incompleto, para inferência local, eu preciso olhar pelo menos para:

GPU
│
├── arquitetura
├── suporte CUDA
├── driver
├── capacidade computacional
└── VRAM
Enter fullscreen mode Exit fullscreen mode

E VRAM rapidamente se torna um fator limitante, um modelo possui bilhões de parâmetros, esses parâmetros precisam estar em algum lugar durante a inferência. Quanto mais consigo manter na GPU, maior tende a ser o benefício da aceleração, quando o modelo não cabe, é possível realizar offloading parcial:

GPU ← algumas camadas
CPU ← restante
Enter fullscreen mode Exit fullscreen mode

Foi exatamente o que aconteceu comigo.


O que aprendi com o experimento

Eu comecei querendo apenas instalar um "ChatGPT local".

Acabei passando por:

LLM
 ↓
Ollama
 ↓
HTTP API
 ↓
Open WebUI
 ↓
Docker networking
 ↓
Linux networking
 ↓
systemd
 ↓
NVIDIA PRIME
 ↓
kernel modules
 ↓
CUDA
 ↓
GPU offloading
 ↓
VRAM
Enter fullscreen mode Exit fullscreen mode

E justamente por isso o experimento valeu muito mais do que simplesmente instalar uma aplicação pronta.

Hoje eu consigo enxergar melhor as diferentes responsabilidades:

Camadas da inferência local: Open WebUI, Ollama, Qwen3 e recursos de hardware

Quando uma resposta demora, o problema pode estar em qualquer uma dessas camadas.

E comandos simples como:

ollama ps
Enter fullscreen mode Exit fullscreen mode
nvidia-smi
Enter fullscreen mode Exit fullscreen mode
watch -n 1 nvidia-smi
Enter fullscreen mode Exit fullscreen mode
ss -lntp
Enter fullscreen mode Exit fullscreen mode
journalctl
Enter fullscreen mode Exit fullscreen mode
lspci
Enter fullscreen mode Exit fullscreen mode

acabam sendo extremamente úteis para descobrir onde está o gargalo.


Próximos passos

Agora que o laboratório está funcionando, existem várias experiências interessantes para continuar: embeddings, RAG, tool/function calling, agents, MCP e integração de LLMs com aplicações tradicionais.

Mas isso fica para os próximos experimentos.

O que começou como:

Quero instalar um LLM na minha máquina.

acabou sendo uma ótima introdução prática à infraestrutura necessária para realmente executar um modelo localmente e descobrir por que alguma coisa não funcionava foi, provavelmente, a parte em que mais aprendi.

Top comments (0)