Alojar Ollama en un VPS de forma segura
Un modelo 7B necesita 8 GB de RAM y ofrece 4 a 10 tokens por segundo en CPU. Usa Ollama en un VPS mediante 127.0.0.1:11434/v1 sin abrir ese puerto.
Qué va a configurar
Un único modelo de lenguaje de pesos abiertos que se ejecuta en un servidor propio, responde mediante una API HTTP y, si lo desea, ofrece una página de chat en el navegador. Ollama descarga el modelo, lo carga en memoria y atiende las peticiones en http://127.0.0.1:11434. La instalación requiere un solo comando. La parte compleja está en otro sitio: elegir un modelo que el VPS pueda mantener realmente en la RAM y no publicar por accidente un servidor de inferencia sin autenticación en toda Internet.
Primero, dos advertencias importantes. Un VPS que sólo usa CPU ejecuta los modelos pequeños con lentitud y la API no incluye autenticación integrada. A continuación se explican ambos problemas en detalle, porque son los principales riesgos de esta configuración.
Comprobación del dimensionamiento con cifras sencillas
El consumo de memoria de un modelo es, aproximadamente, el tamaño de su archivo, más cerca de 1 GB de sobrecarga en tiempo de ejecución y algo más para la ventana de contexto. Las etiquetas predeterminadas de la mayoría de los modelos populares de Ollama, incluidos llama3.2:3b, llama3.1:8b y mistral:7b, están cuantizadas a 4 bits (etiquetadas como Q4_K_M), lo que consume cerca de medio gigabyte de RAM por cada mil millones de parámetros. No todos los valores predeterminados usan Q4: los modelos pequeños, como smollm2:135m, se distribuyen con 16 bits. Consulte la línea de cuantización en la página de la biblioteca del modelo antes de hacer los cálculos. La aritmética es sencilla y determina todo. El último término lo establece usted: aumentar num_ctx por encima del valor predeterminado reducido de Ollama permite usar prompts más largos, pero aumenta la caché KV en la RAM. Por eso, fije la longitud de contexto antes de decidir si el modelo cabe.
Un modelo 3B, como llama3.2:3b, requiere una descarga de aproximadamente 2 GB y alrededor de 4 GB de RAM libre para ejecutarse. Un modelo 7B u 8B, como mistral:7b o llama3.1:8b, ocupa aproximadamente 5 GB en disco y necesita unos 8 GB de RAM; con 16 GB funcionará con mayor margen. Un modelo 13B o 14B necesita aproximadamente 16 GB. Cualquier modelo del rango de 30B a 70B requiere un equipo con mucha RAM o, de forma realista, una GPU. En una VPS con CPU, no cabrá o responderá tan despacio que resultará inútil.
Ahora, la velocidad, porque este es el aspecto que más se suele subestimar. La inferencia en la CPU está limitada por el ancho de banda de memoria, no por la frecuencia de reloj, y una vCPU compartida de una VPS tiene un ancho de banda moderado. Espere entre unos pocos tokens por segundo y unas pocas decenas: un modelo Q4 de 7-8B puede alcanzar entre 4 y 10 tokens por segundo, y uno de 3B, entre 10 y 25. Una GPU es aproximadamente un orden de magnitud más rápida. Estas cifras son deliberadamente aproximadas. Lo adecuado es medir su propio equipo; el paso de ejecución siguiente muestra cómo hacerlo. Confíe en eval rate, no en una cifra de ningún artículo, incluido este.
La conclusión práctica es la siguiente: los modelos pequeños cuantizados en la CPU son realmente útiles para redactar, resumir y clasificar si puede aceptar ese ritmo. Para cualquier tarea más grande o rápida, reserve presupuesto para una instancia con GPU. Si prefiere ver estos cálculos aplicados de principio a fin a un modelo concreto, ejecutar Nemotron 3.5 Lightning en una VPS explica qué etiqueta descargar, cuánta RAM necesita realmente y si el uso exclusivo de la CPU ofrece un rendimiento suficiente.
Para comparar un modelo concreto con un equipo concreto, estime aquí su consumo de memoria:
Instalar Ollama
Hay dos formas limpias de hacerlo. El script oficial es la opción más sencilla en un VPS sin configuración previa:
curl -fsSL https://ollama.com/install.sh | shEsto crea un usuario del sistema llamado ollama, instala el binario en /usr/local/bin/ollama y registra un servicio de systemd llamado ollama.service que se inicia durante el arranque y escucha en 127.0.0.1:11434. Confirme que está activo:
systemctl status ollama
ollama --versionSi ya usa Docker, utilice el contenedor:
docker run -d --name ollama \
-p 127.0.0.1:11434:11434 \
-v ollama:/root/.ollama \
--restart always \
ollama/ollamaObserve el prefijo 127.0.0.1: en la asignación de puertos. Esto enlaza el puerto sólo con localhost. Si escribe -p 11434:11434, lo publica en todas las interfaces. Ese es el error que advierte la sección de seguridad. Elija un solo método de instalación. No ejecute el script y el contenedor al mismo tiempo porque dos procesos intentarán usar el mismo puerto.
Descargue y ejecute su primer modelo
ollama pull llama3.2:3b
ollama run llama3.2:3bpull descarga las capas del modelo al disco (aproximadamente 2 GB en este caso). run las carga en memoria y muestra un indicador >>>. Escriba una pregunta. El primer token puede tardar varios segundos mientras los pesos se cargan del disco a la RAM. Después, la respuesta se muestra progresivamente. Escriba /bye para salir del chat. Ollama sigue ejecutándose en segundo plano.
Compruebe qué está cargado y cómo se distribuye:
ollama psLa columna PROCESSOR muestra la situación real. 100% CPU significa que no se utiliza ninguna GPU. Esa es la causa de la lentitud. Mida la velocidad real con la opción verbose:
ollama run --verbose llama3.2:3b "Write two sentences about Linux."La línea eval rate que aparece al final indica los tokens por segundo en este hardware. Ese es el valor que debe usar como referencia.
Dónde se almacenan los modelos y cuánto espacio de disco comprar
Instalados por el script y ejecutados como el servicio, los modelos se almacenan en el directorio personal del usuario ollama:
sudo du -sh /usr/share/ollama/.ollama/modelsSi se ejecutan de forma interactiva con su propio usuario, se almacenan en ~/.ollama/models. En el contenedor se almacenan en el volumen con nombre ollama. Esto es importante porque los pesos cuantizados ocupan espacio rápidamente: un modelo 3B ocupa aproximadamente 2 GB, uno 7-8B ocupa aproximadamente 5 GB y uno 14B ocupa aproximadamente 9 GB. Si descarga cuatro modelos para compararlos, habrá ocupado 20 GB sin darse cuenta. Dimensione el disco para los modelos que vaya a conservar y elimine los demás con ollama rm <model>. Si el mismo VPS ya ejecuta otro servicio con un consumo elevado de espacio, como PhotoPrism o Immich con una biblioteca de fotos, reste primero ese espacio del espacio libre y considere lo que quede como su presupuesto real para modelos.
Ejecutarlo como un servicio bajo su control
El script de instalación ya registró ollama.service, por lo que se reinicia durante el arranque sin que tenga que hacer nada más. La configuración que merece la pena cambiar es cuánto tiempo permanece cargado un modelo y, en algunas configuraciones, la dirección de enlace. Ambos valores se definen en una extensión de systemd para que una actualización de Ollama no los sobrescriba:
sudo systemctl edit ollama.serviceAñada esto bajo el encabezado [Service] que muestra el editor:
[Service]
Environment="OLLAMA_KEEP_ALIVE=30m"OLLAMA_KEEP_ALIVE indica cuánto tiempo permanece un modelo en memoria después de la última solicitud (5 minutos de forma predeterminada). Auméntelo en un equipo al que envía consultas durante todo el día para evitar volver a cargar los pesos cada vez. Establézcalo en 0 en un equipo con poca memoria para liberar la RAM en cuanto termine una solicitud. Si quiere que un modelo permanezca cargado indefinidamente en lugar de durante un intervalo fijo, mantener un modelo de Ollama cargado permanentemente explica el campo keep_alive por solicitud y cómo volver a cargar los pesos después de un reinicio, en lugar de hacerlo con la primera solicitud lenta. systemctl edit vuelve a cargar los archivos de unidad, por lo que debe reiniciar el servicio para aplicar el cambio:
sudo systemctl restart ollamaEl aspecto de seguridad más importante
De forma predeterminada, Ollama se enlaza a 127.0.0.1:11434, por lo que sólo los procesos del propio VPS pueden acceder a él. Este valor predeterminado es correcto. Manténgalo.
La API no tiene autenticación. Ninguna. No hay clave de API, inicio de sesión ni límite de tasa. La única lista de permitidos que tiene, OLLAMA_ORIGINS, sólo controla qué orígenes del navegador pueden llamarla (CORS); no impide que curl o un script de otra máquina la utilicen. Cualquiera que pueda acceder al puerto 11434 puede ejecutar cualquier modelo que haya descargado, descargar otros, eliminarlos y mantener la CPU o la GPU al 100 % de carga indefinidamente. Los escáneres como Shodan indexan miles de instancias de Ollama abiertas, y una instancia expuesta se encuentra y se utiliza de forma indebida en cuestión de horas.
Por tanto, hay un único error que nunca debe cometer: no establezca OLLAMA_HOST=0.0.0.0 ni abra el puerto 11434 en el firewall. Eso publica un servidor de inferencia sin autenticación en toda Internet. Ninguna configuración hace seguro exponer directamente 11434 en 0.0.0.0, porque ninguna de las opciones documentadas de Ollama añade autenticación a la API local, y una lista de permitidos por origen no es un inicio de sesión. Esta regla se aplica a este servicio concreto, no prohíbe abrir puertos en cualquier circunstancia: un relay de RustDesk autohospedado para escritorio remoto debe aceptar tráfico público para funcionar, y lo hace mediante su propia autenticación basada en claves y una lista breve y documentada de puertos, elementos de los que Ollama carece.
Hay tres formas seguras de acceder al modelo desde otro lugar:
- Mantenerlo local. Si el único cliente es otro programa del mismo VPS, un script de
cron, un bot o un servidor MCP que conecta sus herramientas con el modelo, deje el enlace en127.0.0.1y haga que ese programa llame ahttp://127.0.0.1:11434. No se expone nada más y no hace falta ninguna configuración adicional. - Acceder mediante un túnel privado. Conecte el VPS a una VPN de WireGuard autohospedada, establezca
OLLAMA_HOSTcomo dirección del túnel (por ejemplo,10.8.0.1, no0.0.0.0), y sólo los pares de la VPN podrán conectarse. Internet sigue sin poder ver nada en 11434. - Colocar un proxy inverso con autenticación delante. Termine TLS y exija una contraseña o un token en nginx, Traefik o Caddy; después, envíe las peticiones a
127.0.0.1:11434. Ollama mantiene el enlace en localhost; el proxy es el único proceso que escucha en el puerto público. Es la misma estructura que colocar un certificado de Let's Encrypt en nginx delante de cualquier servicio local.
La opción del proxy inverso es exactamente la que ofrece a continuación la interfaz de chat, con un inicio de sesión real.
Añadir una interfaz de chat con Open WebUI detrás de TLS
Open WebUI es una interfaz de chat autoalojada. Ejecútela en Docker y configúrela para usar la instancia local de 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:mainEl indicador --network=host es el detalle importante en un VPS Linux. Coloca el contenedor en el espacio de nombres de red del host, por lo que 127.0.0.1 dentro del contenedor es el propio loopback del host y el contenedor accede a Ollama mediante 127.0.0.1:11434 sin que Ollama escuche en ninguna otra interfaz. La receta de red bridge que verá en otra sección, --add-host=host.docker.internal:host-gateway con OLLAMA_BASE_URL=http://host.docker.internal:11434, no funciona aquí: ese nombre se resuelve en la gateway del bridge de Docker, y un servicio enlazado a 127.0.0.1 en el host no es accesible a través del bridge. Por eso Open WebUI se limita a informar de que no puede conectarse a Ollama.
La contrapartida de usar la red del host es que Open WebUI ahora escucha en el puerto 8080 del host en todas las interfaces. Cualquier asignación -p se descarta y Docker muestra una advertencia que lo indica. Por tanto, cierre 8080 tanto en el host como en el firewall del proveedor, y haga que el reverse proxy TLS sea el único punto de acceso público. En la primera visita, Open WebUI le pide que cree una cuenta de administrador. Esa cuenta es su capa de autenticación, así que elija una contraseña segura.
Para abrir el chat desde su portátil mediante HTTPS, coloque un reverse proxy TLS delante de 127.0.0.1:8080. Si ya encamina varias aplicaciones Docker en el servidor, Traefik con TLS automático para varias aplicaciones es la opción más adecuada: un único bloque de etiquetas emite el certificado y encamina chat.example.com a Open WebUI. El mismo encaminamiento basado en etiquetas por aplicación se usará para cualquier otra interfaz web del servidor, ya sea un panel de estado o algo más informal como Halcyon, que presenta una biblioteca de Jellyfin como un videoclub de los años 90, cada una con su propio nombre de host y su propio inicio de sesión. La regla de la sección de seguridad sigue siendo válida: el proxy controla el puerto público y el inicio de sesión, mientras Ollama permanece en localhost y el propio 8080 de Open WebUI permanece protegido por el firewall.
Usar el endpoint compatible con OpenAI desde el código
Ollama implementa un subconjunto de la API de chat de OpenAI en /v1, por lo que la mayoría de las bibliotecas cliente de OpenAI funcionan después de cambiar dos elementos: la URL base y una clave desechable.
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)La api_key es obligatoria para la biblioteca cliente, pero Ollama la ignora, por lo que puede ser cualquier cadena. model debe ser un nombre que ya haya descargado; un nombre desconocido devuelve un error 404 con model 'x' not found. Una llamada directa con curl sigue la misma idea:
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"}]}'Esta es también la forma de integrar el modelo en herramientas de agentes y editores. Si ya desarrolla en el servidor, un modelo local puede ejecutar scripts y complementos junto con Claude Code ejecutándose en el VPS dentro de tmux, de modo que las tareas de redacción económicas y privadas no dependan de una API de pago, mientras el razonamiento complejo se mantiene en un modelo alojado.
Modos de fallo, con las cadenas exactas que verá
El proceso aparece como "Killed" durante la generación. Inicia un modelo grande y el terminal muestra Killed, o el registro del servidor (journalctl -u ollama) contiene una línea que comienza por llama-server process has terminated. Ese es el texto que usa Ollama 0.40.7, comprobado el 21 de octubre de 2026; las versiones anteriores mostraban llama runner process has terminated: signal: killed. El OOM killer de Linux detuvo el proceso porque el modelo necesitaba más RAM de la disponible en el servidor. Confirme la causa con sudo dmesg | grep -i oom. Allí verá una línea como Out of memory: Killed process .... La solución es usar un modelo más pequeño o con una cuantización más agresiva, llama3.2:3b en lugar de uno de 13B, o añadir swap para que una carga que apenas supera la RAM física disponible termine lentamente en lugar de fallar. La swap convierte un fallo inmediato en una respuesta lenta. No hace viable un modelo de 70B con 4 GB. El proceso termina sin aviso salvo que esté observando el terminal. En un servidor que consulta desde otro equipo, asociar una unidad OnFailure= a ollama.service para publicar avisos en un servidor ntfy propio para recibir alertas push le informa en el momento del fallo, en lugar de obligarle a descubrirlo en la siguiente petición.
Ollama se niega a cargar el modelo. La petición falla de inmediato con un error en lugar de provocar un fallo del proceso, y el registro del servidor contiene model is too large for system memory (Ollama 0.40.7, comprobado el 21 de octubre de 2026). Las versiones anteriores mostraban Error: model requires more system memory (X GiB) than is available (Y GiB) directamente en el indicador de comandos. Esta es la versión controlada del fallo anterior: Ollama calculó los requisitos y se detuvo, en lugar de dejar que actuara el OOM killer. Elija un modelo cuyos requisitos estén por debajo de la RAM libre disponible (compruébela con free -h), reduzca la longitud del contexto o migre a un VPS más grande. Ninguna opción permite que el modelo quepa si la memoria necesaria no está disponible.
El primer token tarda mucho y después todo funciona con normalidad. Un modelo que no está cargado no muestra nada durante cinco a treinta segundos y después transmite la respuesta con normalidad. Esa pausa se debe a que los pesos se cargan del disco a la RAM por primera vez. El almacenamiento lento la prolonga. Una vez cargado, el modelo permanece en memoria durante el tiempo indicado por OLLAMA_KEEP_ALIVE, por lo que la segunda petición responde de inmediato. Si esa primera carga supera el tiempo de espera de algún punto de la ruta de la petición, recibirá un error en lugar de una respuesta lenta. Determinar qué capa informó de que se superó el plazo del contexto permite saber si el cliente, el proxy o la propia carga agotaron el tiempo de espera. Aumente ese valor si las pausas resultan molestas y use ollama ps para comprobar si hay un modelo cargado.
Todo funciona simplemente despacio. Diez tokens por segundo o menos, sin ningún error. Eso es la inferencia mediante CPU funcionando como suele hacerlo. ollama ps muestra 100% CPU, lo que significa que no hay GPU. No es un error y ninguna configuración convierte una CPU en una GPU, porque el límite principal es el ancho de banda de memoria. Sin embargo, merece la pena probar una configuración en una VM: Ollama elige el número de hilos a partir de los núcleos físicos que detecta, y un hipervisor puede informar de ellos de forma incorrecta. En una sesión de ollama run --verbose, pruebe /set parameter num_thread 4 (o el número de vCPU), vuelva a ejecutar la misma petición y conserve el valor que proporcione el mejor eval rate. Después de eso, use un modelo más pequeño, acepte la velocidad o migre a una instancia con GPU. Mida la velocidad real con --verbose antes de concluir que algo está averiado. Si la espera se debe a la longitud de la respuesta y no a la velocidad, limitar la respuesta con num_predict evita que un modelo propenso a extenderse dedique minutos a generar tokens que no iba a leer.
La conexión se rechaza desde otro equipo. Desde el portátil, una versión actual de curl (8.23.0, comprobada el 21 de octubre de 2026) muestra curl: (7) Failed to connect to <ip>:11434 after <n> ms: Could not connect to server, y la versión curl 8.5.0 incluida en Ubuntu 24.04 muestra curl: (7) Failed to connect to <ip> port 11434 after <n> ms: Couldn't connect to server. Las palabras "Connection refused" sólo aparecen si añade -v, en una línea con connect to <ip> port 11434 from ... failed: Connection refused. El comportamiento es el esperado: Ollama sólo se enlaza a localhost. No lo «solucione» enlazándolo a 0.0.0.0, porque ese es precisamente el error de exposición descrito arriba. Acceda al modelo mediante la VPN o a través del proxy con autenticación.
Ha expuesto 11434 a Internet. Si configuró OLLAMA_HOST=0.0.0.0, abrió el firewall y ahora observa descargas de modelos que no inició o la CPU al 100 % debido a clientes desconocidos, terceros han localizado el servicio y lo están utilizando. Este es el error principal, no un caso excepcional. Vuelva a enlazarlo a 127.0.0.1 o a la dirección de la VPN, cierre 11434 en el firewall y coloque la autenticación delante del servicio. Suponga que cualquier servicio accesible en esa dirección mientras estuvo expuesto fue consultado por personas ajenas.
Copias de seguridad y actualizaciones
Hay poco estado que preservar. Los modelos se pueden volver a descargar, por lo que sólo merece la pena hacer copias de seguridad del volumen de datos de Open WebUI, las cuentas, el historial de chats, la configuración y cualquier drop-in de systemd que haya creado. Haga una copia del volumen con un contenedor temporal:
docker run --rm -v open-webui:/data -v "$PWD":/backup alpine \
tar czf /backup/open-webui.tgz -C /data .Actualice Ollama volviendo a ejecutar el script de instalación. Actualice Open WebUI con docker pull ghcr.io/open-webui/open-webui:main y vuelva a crear el contenedor. Una consideración de disco para la línea 0.40: Ollama 0.40.2 empezó a actualizar en segundo plano los modelos descargados con versiones anteriores y conserva las copias originales como copias de seguridad. Por tanto, ocupan espacio de disco adicional hasta que se eliminan. Ollama 0.40.3 (11 October 2026) pausó esa actualización en segundo plano. Compruebe df -h después de una actualización y consulte las notas de la versión para conocer el comando que elimina esas copias de seguridad. No fije versiones a largo plazo: tanto la calidad de los modelos como el runtime cambian rápidamente. Consulte las notas de la versión y vuelva a medir el rendimiento en su propio servidor en lugar de confiar en las cifras del último trimestre.
FAQ
¿Realmente puedo ejecutar un LLM en un VPS que sólo tenga CPU?
Sí, con limitaciones. Los modelos cuantizados pequeños, de 3B a 8B, funcionan en CPU y son realmente útiles para redactar, resumir y clasificar, aunque funcionan despacio: alcanzan entre un dígito y pocas decenas de tokens por segundo en una vCPU compartida. Cualquier modelo de 13B o superior funciona con mucha lentitud o directamente no cabe en la RAM. Para obtener más velocidad o usar modelos más grandes, necesita una instancia con GPU.
¿Cuánta RAM necesita cada modelo?
Como regla aproximada para las etiquetas de 4 bits (Q4) que usan de forma predeterminada los modelos más populares: calcule unos 0.5 GB de RAM por cada mil millones de parámetros para los pesos, más aproximadamente 1 GB de sobrecarga y algo más para el contexto. Por tanto, un modelo de 3B necesita unos 4 GB libres, uno de 7-8B unos 8 GB y uno de 14B unos 16 GB. Compruebe el margen disponible con free -h y deje espacio para el sistema operativo y el resto de servicios del servidor.
¿La API de Ollama está autenticada?
No. Ollama no incluye autenticación, API key ni límite de tasa. Cualquiera que pueda alcanzar el puerto 11434 tiene control total sobre ella. Su configuración OLLAMA_ORIGINS sólo limita qué orígenes del navegador pueden llamarla, no quién puede conectarse. Por eso se enlaza a 127.0.0.1 de forma predeterminada y nunca debe exponer 11434 a Internet mediante 0.0.0.0. Acceda a ella localmente, mediante una VPN privada o a través de un reverse proxy que añada un inicio de sesión.
¿Cómo añado una interfaz web de chat?
Ejecute Open WebUI en Docker con --network=host para que comparta el loopback del host y alcance Ollama nativo en http://127.0.0.1:11434. Después, coloque un reverse proxy TLS delante de su puerto 8080 para acceder desde su portátil. Mantenga 8080 cerrado en el firewall para que el proxy sea el único punto de acceso público. La propia cuenta de administrador de Open WebUI proporciona el inicio de sesión. Establezca su contraseña durante el primer arranque.
¿Cómo lo llamo desde mi propia aplicación?
Use el endpoint compatible con OpenAI en http://127.0.0.1:11434/v1. Apunte cualquier SDK de OpenAI a esa URL base, pase cualquier cadena como API key porque se ignora y establezca model con el nombre de un modelo que haya descargado. El código existente de OpenAI normalmente funciona sin cambios, salvo por la URL base y la key.