先说结论:Ollama 本身不提供内置的认证机制。但这不代表你不能给 API 加认证。
这一章我们聊聊几种常见的认证方案,以及如何实现。
默认安装的 Ollama,API 是没有任何认证的:
curl http://localhost:11434/api/version
任何人只要能访问这个地址,就能调用所有 API。
这在本地开发时没问题,但如果要部署到生产环境,就需要考虑安全性了。
几个常见的安全风险:
数据泄露
API 暴露在公网,任何人都能调用你的模型,消耗你的算力。
滥用风险
没有限制,可能被用来生成垃圾内容、刷量等。
合规问题
某些场景下,需要记录谁在什么时候调用了什么接口。
最简单的方式,限制谁能访问。
只监听本地回环地址:
OLLAMA_HOST=127.0.0.1:11434 ollama serve
这样只有本机的程序能访问 API。
限制在内网范围:
OLLAMA_HOST=10.0.0.1:11434 ollama serve
配合防火墙规则:
# 只允许特定 IP 访问
sudo ufw allow from 10.0.0.0/8 to any port 11434
通过 VPN 或 SSH 隧道访问:
# SSH 隧道
ssh -L 11434:localhost:11434 user@server
然后本地连接:
curl http://localhost:11434/api/version
这是最常用的方案。在 Ollama 前面加一层反向代理,由代理负责认证。
最简单的 HTTP Basic 认证:
server {
listen 80;
server_name ollama.example.com;
location / {
auth_basic "Ollama API";
auth_basic_user_file /etc/nginx/.htpasswd;
proxy_pass http://127.0.0.1:11434;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
创建密码文件:
sudo htpasswd -c /etc/nginx/.htpasswd admin
# 输入密码
调用时带上认证信息:
curl -u admin:password http://ollama.example.com/api/version
更灵活的方式,用 API Key:
server {
listen 80;
server_name ollama.example.com;
location / {
if ($http_x_api_key != "your-secret-key") {
return 401;
}
proxy_pass http://127.0.0.1:11434;
}
}
调用时在 Header 中传递:
curl -H "X-API-Key: your-secret-key" http://ollama.example.com/api/version
如果需要给不同用户分配不同的 Key,可以用 Lua 或外部认证服务:
# 使用 auth_request 模块
location / {
auth_request /auth;
proxy_pass http://127.0.0.1:11434;
}
location = /auth {
internal;
proxy_pass http://auth-service:8080/validate;
proxy_pass_request_body off;
proxy_set_header X-Original-URI $request_uri;
proxy_set_header X-API-Key $http_x_api_key;
}
在你的应用代码中实现认证逻辑。
from fastapi import FastAPI, Header, HTTPException
import httpx
app = FastAPI()
VALID_KEYS = {"key-1", "key-2", "key-3"}
@app.api_route("/{path:path}", methods=["GET", "POST", "DELETE"])
async def proxy(path: str, x_api_key: str = Header(None)):
if x_api_key not in VALID_KEYS:
raise HTTPException(status_code=401, detail="Invalid API Key")
async with httpx.AsyncClient() as client:
response = await client.request(
method=request.method,
url=f"http://localhost:11434/{path}",
content=await request.body(),
)
return response.json()
const express = require('express');
const { createProxyMiddleware } = require('http-proxy-middleware');
const app = express();
const validKeys = new Set(['key-1', 'key-2', 'key-3']);
app.use((req, res, next) => {
const apiKey = req.headers['x-api-key'];
if (!validKeys.has(apiKey)) {
return res.status(401).json({ error: 'Invalid API Key' });
}
next();
});
app.use('/', createProxyMiddleware({
target: 'http://localhost:11434',
changeOrigin: true
}));
app.listen(3000);
对于需要对接现有认证系统的场景,可以用 OAuth 2.0 或 JWT。
# 需要 nginx-plus 或 openresty
# 这里展示思路
location / {
access_by_lua_block {
local jwt = require "resty.jwt"
local token = ngx.var.http_authorization
if not token then
ngx.exit(401)
end
local jwt_obj = jwt:verify("secret-key", token)
if not jwt_obj.verified then
ngx.exit(401)
end
}
proxy_pass http://127.0.0.1:11434;
}
认证信息如果不加密传输,等于没有。生产环境务必启用 HTTPS。
sudo certbot --nginx -d ollama.example.com
测试环境可以用自签名证书:
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout /etc/nginx/ollama.key \
-out /etc/nginx/ollama.crt
Nginx 配置:
server {
listen 443 ssl;
server_name ollama.example.com;
ssl_certificate /etc/nginx/ollama.crt;
ssl_certificate_key /etc/nginx/ollama.key;
location / {
auth_basic "Ollama API";
auth_basic_user_file /etc/nginx/.htpasswd;
proxy_pass http://127.0.0.1:11434;
}
}
| 方案 | 复杂度 | 适用场景 |
|---|---|---|
| 网络层限制 | 低 | 内网、个人使用 |
| Basic Auth | 低 | 小团队、简单场景 |
| API Key | 中 | 多用户、需要区分身份 |
| OAuth/JWT | 高 | 企业级、对接现有系统 |
不要硬编码密钥
把密钥放在环境变量或配置文件中:
export OLLAMA_API_KEY="your-secret-key"
定期轮换密钥
定期更换 API Key,降低泄露风险。
记录访问日志
记录谁在什么时候调用了什么接口:
log_format api_log '$remote_addr - $http_x_api_key [$time_local] '
'"$request" $status $body_bytes_sent';
access_log /var/log/nginx/ollama.log api_log;
限制请求频率
防止滥用:
limit_req_zone $http_x_api_key zone=api_limit:10m rate=10r/s;
location / {
limit_req zone=api_limit burst=20 nodelay;
proxy_pass http://127.0.0.1:11434;
}