Ollama API sin contraseña: riesgos y tres soluciones
Ollama no incluye autenticación: cualquiera con acceso al puerto 11434 puede ejecutar, descargar y eliminar modelos. Conoce las tres soluciones, en orden.
La API de Ollama no tiene contraseña
La API de Ollama no tiene autenticación. El servidor que ejecuta no tiene ningún usuario, contraseña, comprobación de clave ni lista de permitidos. Cualquier sistema que pueda abrir una conexión TCP al puerto 11434 puede enumerar sus modelos, ejecutarlos, descargar otros y eliminar los que ya tiene.
La documentación oficial lo indica claramente: «No se requiere autenticación al acceder localmente a la API de Ollama mediante http://localhost:11434». La palabra localmente define todo el modelo de seguridad. Ollama se enlaza a 127.0.0.1 de forma predeterminada, por lo que, en un portátil, la interfaz de loopback controla el acceso. Si mueve ese listener a una dirección pública, el control de acceso desaparece porque no hay ningún mecanismo que lo sustituya.
Por eso esto es importante en un VPS (servidor privado virtual). La configuración predeterminada es segura. El primer cambio que suele hacerse, abrir el listener para que una segunda máquina pueda usar el modelo, es precisamente el cambio que elimina todas las protecciones de una vez.
Qué expone un puerto abierto 11434
Todos los endpoints. No hay un modo de solo lectura ni un puerto de administración independiente. Estas son las peticiones reales, dirigidas a la dirección del servidor en lugar de a localhost:
# List every model on the box
curl http://SERVER_IP:11434/api/tags
# See what is loaded into memory right now
curl http://SERVER_IP:11434/api/ps
# Run a prompt on your hardware
curl http://SERVER_IP:11434/api/generate -d '{"model":"llama3.2","prompt":"Why is the sky blue?"}'
# Write several gigabytes to your disk
curl http://SERVER_IP:11434/api/pull -d '{"model":"llama3.2"}'
# Remove a model
curl -X DELETE http://SERVER_IP:11434/api/delete -d '{"model":"llama3.2"}'Desde el punto de vista operativo, se producen cuatro problemas:
- Tu CPU o GPU ejecuta inferencias para otra persona. En un plan con una cuota de CPU de uso razonable, una carga sostenida consume tu cuota por parte de un tercero, y mantener bajo control los costes de las cargas de trabajo de IA en un VPS resulta mucho más difícil cuando no eres el único cliente.
/api/pullescribe en tu disco. Cada modelo ocupa entre dos y cuarenta gigabytes. Una secuencia de descargas llena el volumen, y un disco lleno interrumpe todos los demás servicios del servidor, no solo Ollama.- Las peticiones llegan a tu proceso y se registran. Con el nivel de registro predeterminado, Ollama solo registra metadatos: el endpoint, el estado, la latencia y la dirección del cliente, no el texto del prompt. Aun así, queda un registro de quién usó tu servidor y para qué, almacenado en tu journal, sin que hayas elegido recopilarlo.
/api/deleteelimina modelos. Para recuperarlos hay que descargarlos de nuevo usando tu propio ancho de banda.
Nada de esto requiere un exploit. Es la API documentada funcionando exactamente como está diseñada.
La clave Ed25519 no es un mecanismo de control de acceso
Si busca "Ollama API key", encontrará dos cosas diferentes. Ninguna es una contraseña para su servidor. Distinguirlas elimina la mayor parte de la confusión.
La primera es el par de claves de identidad. Ollama genera un par de claves Ed25519 en el primer arranque. En Linux, el script de instalación crea un usuario del sistema llamado ollama, con el directorio personal en /usr/share/ollama. Por tanto, el par se encuentra aquí:
/usr/share/ollama/.ollama/id_ed25519
/usr/share/ollama/.ollama/id_ed25519.pubEsta clave se utiliza para conexiones salientes. ollama signin registra la mitad pública en su cuenta de ollama.com. También autoriza el envío de un modelo al registro o la descarga de un modelo privado. Identifica su máquina ante ollama.com. No solicita nada a los clientes que se conectan a su máquina. Eliminarla, cambiarla o no crearla no modifica quién puede llamar a su API.
La segunda es OLLAMA_API_KEY. Esta variable contiene una clave que usted crea en https://ollama.com/settings/keys. Su cliente la envía como Authorization: Bearer $OLLAMA_API_KEY al llamar a la API alojada en https://ollama.com/api. Es una credencial para su servicio, que usted utiliza como cliente. Su propio ollama serve nunca la lee. Definir OLLAMA_API_KEY en su VPS no añade una contraseña a su VPS.
Por tanto, no hay ninguna opción que activar. Las tres defensas siguientes funcionan de la misma forma: mantenga el puerto inaccesible y coloque delante algo que sí compruebe las solicitudes.
Compruebe en qué direcciones está escuchando el servidor ahora
sudo ss -tlnp | grep 11434El resultado seguro muestra la dirección de loopback:
LISTEN 0 4096 127.0.0.1:11434 0.0.0.0:* users:(("ollama",pid=812,fd=3))El resultado expuesto muestra todas las interfaces:
LISTEN 0 4096 0.0.0.0:11434 0.0.0.0:* users:(("ollama",pid=812,fd=3))0.0.0.0 significa todas las direcciones IPv4 del equipo, incluida la pública. *:11434 y [::]:11434 significan lo mismo, pero con IPv6 incluida.
Ahora confirme el acceso desde fuera. Ejecute esto en su portátil, no en el servidor:
curl -m 5 http://YOUR_SERVER_IP:11434/api/versioncurl: (28) Connection timed out after 5001 milliseconds es la respuesta que busca, al igual que curl: (7) Failed to connect ... Connection refused. Un objeto JSON que contenga un campo version significa que cualquier persona puede acceder a toda la API. Probar con curl en el propio servidor no demuestra nada, porque loopback siempre responde.
La exposición suele producirse de una de estas dos formas. La primera es una modificación deliberada, porque alguien necesitaba que un segundo equipo accediera al modelo:
sudo systemctl edit ollama.service[Service]
Environment="OLLAMA_HOST=0.0.0.0:11434"Esa única línea es toda la exposición. La segunda forma es Docker, y no requiere editar nada. Tiene su propia sección más adelante.
Defensa 1: mantenerlo en localhost y acceder mediante un túnel
Empiece por esta opción. No requiere instalar software nuevo ni crea credenciales que puedan filtrarse. El puerto nunca existe en una interfaz pública, por lo que los escaneos no pueden encontrarlo.
Establezca explícitamente la dirección de escucha en lugar de depender del valor predeterminado:
sudo systemctl edit ollama.service[Service]
Environment="OLLAMA_HOST=127.0.0.1:11434"Esto escribe /etc/systemd/system/ollama.service.d/override.conf. Aplique el cambio y compruébelo:
sudo systemctl daemon-reload
sudo systemctl restart ollama
sudo ss -tlnp | grep 11434ss ahora debería mostrar 127.0.0.1:11434. Si sigue mostrando 0.0.0.0, otro archivo drop-in tiene prioridad. Ejecute systemctl cat ollama.service para enumerar la unidad y todos los drop-in con sus rutas, y elimine el archivo obsoleto.
Para usar el modelo desde su portátil, reenvíe el puerto mediante SSH:
ssh -N -L 11434:127.0.0.1:11434 you@your-server-L 11434:127.0.0.1:11434 abre el puerto 11434 en su portátil y envía todo lo que llegue allí a 127.0.0.1:11434 tal como se ve desde el servidor. -N indica a SSH que no ejecute ningún comando remoto, de modo que el proceso sólo mantiene abierto el túnel. Mientras esté en ejecución, esto funciona en su portátil:
curl -s http://localhost:11434/api/tagsEncontrará dos fallos habituales. bind [127.0.0.1]:11434: Address already in use significa que su portátil está ejecutando su propio Ollama en ese puerto, así que elija otro puerto local con -L 11500:127.0.0.1:11434 y dirija el cliente a 11500. Una respuesta vacía a través de un túnel que se conectó correctamente significa que SSH funciona, pero Ollama no está escuchando en el servidor. Compruebe allí ss antes de modificar el comando SSH.
Para varias máquinas cliente, una red privada es mejor que un túnel por persona. Conecte las máquinas mediante WireGuard o Tailscale y, después, vincule Ollama a su dirección en esa red en lugar de a 0.0.0.0:
[Service]
Environment="OLLAMA_HOST=10.8.0.1:11434"El puerto sólo existirá en una interfaz a la que sea necesario acceder con una clave. Esto también protege frente a un error del firewall, porque una regla que permita accidentalmente el acceso desde Internet no puede exponer un servicio de escucha que no esté disponible en la interfaz pública.
Defensa 2: un proxy inverso que comprueba un bearer token
Cuando algo en Internet público deba llamar al modelo, mantenga Ollama en loopback y coloque un proxy delante. El proxy termina TLS (seguridad de la capa de transporte) y rechaza las solicitudes que no incluyan la cabecera correcta. Ollama sigue aceptando conexiones sólo desde 127.0.0.1, por lo que el proxy es la única vía de acceso.
Genere primero un token real. No lo invente manualmente:
openssl rand -base64 36Un sitio de nginx que lo comprueba:
map $http_authorization $ollama_ok {
default 0;
"Bearer PASTE_YOUR_GENERATED_TOKEN_HERE" 1;
}
server {
listen 443 ssl;
server_name llm.example.com;
ssl_certificate /etc/letsencrypt/live/llm.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/llm.example.com/privkey.pem;
location = /api/pull { return 403; }
location = /api/delete { return 403; }
location = /api/push { return 403; }
location / {
if ($ollama_ok = 0) { return 401; }
proxy_pass http://127.0.0.1:11434;
proxy_set_header Host 127.0.0.1:11434;
proxy_buffering off;
proxy_read_timeout 600s;
}
}Cinco líneas hacen aquí el trabajo real. Cada una evita un fallo que, de otro modo, encontraría.
if dentro de un bloque location suele ser una mala idea en nginx, pero un cuerpo de exactamente return es una de las dos formas cuyo comportamiento es predecible, por lo que este uso es seguro.
location = /api/pull es una coincidencia exacta. nginx da prioridad a las coincidencias exactas sobre el prefijo location /, por lo que esos tres endpoints se rechazan antes de comprobar el token. Un token válido permite ejecutar inferencias, pero no llenar el disco.
proxy_set_header Host 127.0.0.1:11434; es importante porque Ollama inspecciona las cabeceras Host y Origin entrantes. Pasar directamente el nombre de host público del proxy puede producir un 403 Forbidden generado por Ollama en lugar de nginx, lo que dificulta el diagnóstico. OLLAMA_ORIGINS es el otro ajuste, para un cliente de navegador que necesite permitir un origen específico.
proxy_buffering off; es importante porque Ollama transmite la respuesta token a token. Con el almacenamiento en búfer activado, nginx retiene el flujo y lo entrega completo al final, por lo que el cliente parece bloqueado durante toda la generación.
proxy_read_timeout 600s; es importante porque nginx tiene un valor predeterminado de 60 segundos. Una generación larga en la CPU puede superar ese tiempo fácilmente; el cliente recibe 504 Gateway Time-out y /var/log/nginx/error.log registra upstream timed out (110: Connection timed out) while reading response header from upstream. La solicitud seguía procesándose. nginx la abandonó.
Recargue la configuración y pruebe ambas rutas:
sudo nginx -t && sudo systemctl reload nginx
curl -s -o /dev/null -w '%{http_code}\n' https://llm.example.com/api/tags
curl -s -H "Authorization: Bearer YOUR_TOKEN" https://llm.example.com/api/tagsLa primera debería mostrar 401. La segunda debería mostrar la lista de modelos. Si la primera también devuelve la lista de modelos, el bloque map está en el ámbito incorrecto. Debe estar en el nivel http, así que colóquelo en un archivo bajo /etc/nginx/conf.d/ o por encima del bloque server, nunca dentro de server.
Caddy hace el mismo trabajo con autenticación básica en cuatro líneas, lo que resulta más adecuado para un cliente de navegador que un bearer token:
llm.example.com {
basic_auth {
apiuser PASTE_BCRYPT_HASH_HERE
}
reverse_proxy 127.0.0.1:11434
}Ejecute caddy hash-password para generar el hash bcrypt que espera. Hay una diferencia de nombres que debe tener en cuenta: la directiva era basicauth antes de Caddy v2.8 y ahora es basic_auth. Por eso, una configuración copiada de una guía antigua no se carga y Caddy indica el nombre de la directiva que no reconoce.
Independientemente del proxy que elija, se trata de un secreto compartido por todos los clientes. Todos los clientes que lo posean tendrán el mismo acceso. Revocarlo implica editar la configuración y actualizar todos los clientes al mismo tiempo.
Defensa 3: una gateway que emite claves por cliente
Cuando más de una persona o aplicación llama al modelo, un token compartido deja de ser suficiente. No puede saber qué cliente causó la carga ni bloquear a uno sin bloquearlos a todos. Una gateway ocupa el lugar del proxy, utiliza la misma API compatible con OpenAI, emite una clave independiente para cada cliente y registra el uso de cada clave. Una gateway LiteLLM autohospedada suele ser la opción habitual. Además del control de acceso, añade presupuestos por clave y registros de solicitudes.
La regla de la defensa 1 no cambia. Ollama se enlaza a 127.0.0.1, la gateway es el único proceso que se comunica con él y la gateway es el único servicio con un puerto público a la escucha. Una gateway en un equipo cuyo puerto 11434 sigue abierto a Internet es sólo decorativa, porque los clientes pueden evitarla fácilmente.
La trampa del firewall: un puerto de contenedor publicado evita UFW
Esta es la razón por la que existen instancias expuestas en servidores cuyos administradores configuraron correctamente el firewall.
UFW (uncomplicated firewall) escribe sus reglas en la cadena INPUT de la tabla filter del kernel, y INPUT gestiona los paquetes dirigidos al propio host. La opción -p de Docker escribe una regla de NAT de destino (network address translation) en la cadena PREROUTING de la tabla nat, que el kernel evalúa antes de decidir adónde se dirige el paquete. Cuando se toma la decisión de enrutamiento, el destino ya se ha reescrito a la dirección del contenedor, por lo que el paquete se reenvía en lugar de entregarse localmente y atraviesa FORWARD en vez de INPUT. Las reglas INPUT de UFW nunca se consultan, por lo que el paquete rodea el firewall en lugar de atravesarlo.
Por eso esta secuencia deja el puerto 11434 abierto a Internet:
sudo ufw default deny incoming
sudo ufw enable
docker run -d -v ollama:/root/.ollama -p 11434:11434 --name ollama ollama/ollamay sudo ufw status sigue mostrando que el firewall está activo con una política predeterminada de denegación. Ambas lecturas son correctas al mismo tiempo. Precisamente por eso se suele confiar en la lectura equivocada. Puede ver la regla responsable:
sudo iptables -t nat -L DOCKER -nLa solución consiste en indicar una dirección en la opción de publicación:
docker rm -f ollama
docker run -d -v ollama:/root/.ollama -p 127.0.0.1:11434:11434 --name ollama ollama/ollama-p 11434:11434 es una forma abreviada de -p 0.0.0.0:11434:11434. Al especificar 127.0.0.1, el lado del host del mapeo queda vinculado a loopback. De este modo, el túnel SSH y el proxy inverso siguen teniendo acceso, pero Internet no. Recrear el contenedor es seguro en este caso porque los modelos están en el volumen con nombre ollama, no dentro del contenedor.
Confirme que ambas vistas coinciden:
docker port ollama
sudo ss -tlnp | grep 11434docker port ollama debería mostrar 11434/tcp -> 127.0.0.1:11434. Si muestra 0.0.0.0:11434, el servicio sigue expuesto. Comprenda este mecanismo una vez y podrá aplicarlo a cualquier contenedor que publique en el futuro: por qué los puertos publicados de Docker evitan UFW explica la cadena DOCKER-USER y las reglas que permanecen después de reiniciar Docker. Si todavía está construyendo la política del host, las reglas de UFW que necesita un VPS nuevo explica la base sobre la que se apoya esta configuración. En Rocky o AlmaLinux no hay UFW que configurar, así que la misma política base escrita en firewalld es el punto de partida adecuado.
Quién ejecuta el proceso
El script de instalación de Linux crea una cuenta dedicada y ejecuta el servicio con ella:
useradd -r -s /bin/false -U -m -d /usr/share/ollama ollamaLa unidad en /etc/systemd/system/ollama.service establece User=ollama y Group=ollama. No modifique esa configuración. Un ollama serve iniciado manualmente en una terminal se ejecuta con la cuenta del usuario que inició sesión. Si esa cuenta es root, una API sin autenticación puede escribir archivos como root. Compruebe cuál es el caso:
ps -o user= -C ollamaLa respuesta debe ser ollama. Cualquier otro resultado indica que hay un proceso iniciado manualmente ejecutándose junto a la unidad o en lugar de ella. El mismo criterio se aplica a cada daemon que añada más adelante, y ejecutar servicios con usuarios con privilegios mínimos permite configurarlo correctamente.
Cómo comprobar que el endpoint de la API de Ollama es seguro
Independientemente de la opción elegida, una prueba lo confirma y debe ejecutarse desde otra máquina:
curl -m 5 http://YOUR_SERVER_IP:11434/api/version
curl -m 5 http://YOUR_SERVER_IP:11434/api/tagsAmbas rutas deben agotar el tiempo de espera o ser rechazadas. Si configuró un proxy, las mismas dos rutas en el nombre de host del proxy deben devolver 401 sin credenciales y JSON válido con ellas.
Después, revise una vez el registro de acceso, porque indica si alguien encontró el puerto mientras estuvo abierto:
journalctl -u ollama --since "-30 days" | grep GIN | grep -v 127.0.0.1Ollama escribe una línea por solicitud e incluye la dirección del cliente:
[GIN] 2026/08/12 - 14:01:10 | 200 | 103.965898ms | 127.0.0.1 | POST "/api/generate"Todas las líneas deben mostrar 127.0.0.1 una vez que Ollama esté enlazado a la interfaz de loopback, porque esa es la única dirección desde la que puede llegar una conexión. Una dirección pública en esa columna indica una solicitud externa, y la marca de tiempo indica cuándo ocurrió. El resultado que busca es que ese comando no muestre ninguna salida. Si esta parte relacionada con los modelos es nueva para usted, ejecutar Ollama en un VPS explica la instalación, el dimensionamiento del modelo y los límites de memoria que determinan qué se cargará realmente.
FAQ
¿Ollama tiene una clave de API o una contraseña?
No. El servidor que ejecuta no tiene ningún tipo de autenticación, y la documentación oficial indica que no se requiere autenticación para acceder a la API. Los dos elementos denominados "Ollama API key" indican lo contrario. El par Ed25519 de /usr/share/ollama/.ollama/ demuestra la identidad de su máquina ante ollama.com para que pueda subir modelos y descargar modelos privados. OLLAMA_API_KEY es una credencial que su cliente envía a la API alojada en https://ollama.com/api. Su propio ollama serve no lee ninguno de los dos, por lo que el control de acceso debe proceder de la red o de un proxy situado delante.
¿Es seguro OLLAMA_HOST=0.0.0.0 si tengo un firewall?
Sólo mientras ningún otro componente escriba reglas de firewall en ese equipo. 0.0.0.0 significa que el listener existe realmente en la interfaz pública y que confía únicamente en el firewall para impedir el acceso. Esa confianza se rompe en cuanto Docker publica un puerto, porque la regla DNAT que Docker añade a la tabla nat se evalúa antes de que el paquete llegue a la cadena INPUT, donde funciona UFW; por tanto, el paquete se reenvía y UFW nunca lo ve. Enlazar con 127.0.0.1 o con una dirección de túnel privada elimina el listener de la interfaz pública, de modo que un error del firewall ya no tiene nada que exponer.
¿Cómo compruebo si mi puerto de Ollama está abierto a Internet?
Ejecute sudo ss -tlnp | grep 11434 en el servidor y curl -m 5 http://YOUR_SERVER_IP:11434/api/version desde otra máquina. Si ss muestra 127.0.0.1:11434 y el curl remoto agota el tiempo de espera, esas son las dos respuestas que busca. Si ss muestra 0.0.0.0:11434 o *:11434 mientras el curl remoto devuelve JSON, significa que se puede acceder a la API completa. No haga la prueba con curl en el propio servidor, porque loopback responde independientemente de cuál sea la dirección de enlace.
¿Puedo cambiar el puerto de 11434 por uno aleatorio?
No, y conviene explicar el motivo. Un puerto diferente no ralentiza nada salvo un escaneo de un único puerto. Los escáneres recorren todo el rango, y una petición a /api/tags identifica el servicio independientemente del puerto al que haya llegado. Cambiar el puerto también rompe los valores predeterminados de todos los clientes y dificulta comprender su propia configuración más adelante. Enlace con loopback, que elimina el listener en lugar de trasladarlo.
Alguien accedió a mi Ollama abierto. ¿Qué debo comprobar?
Enlácelo con 127.0.0.1 y reinicie primero el servicio, para detener la exposición antes de iniciar la investigación. Después, ejecute journalctl -u ollama --since "-30 days" | grep GIN | grep -v 127.0.0.1 para ver qué direcciones externas llamaron a qué endpoints y cuándo. Compare ollama list con los modelos que pretendía tener, porque /api/pull no requiere autenticación y un modelo que no descargó representa tanto uso de disco como una evidencia. Compruebe el espacio libre con df -h. Ollama no registra el texto de los prompts con el nivel de registro predeterminado, por lo que tendrá un registro de quién hizo la petición y para qué modelo, pero no de lo que se generó.