Skip to content

🔐 推理 API 对外部署

模型跑起来了,怎么安全地让别人用?——限流、鉴权、反代一个不能少

部署架构

用户 → nginx(HTTPS) → 推理服务(HTTP)

      限流 + 鉴权 + 日志

推理服务(Ollama/vLLM/llama.cpp)默认跑 HTTP 且无鉴权,绝对不能直接暴露到公网。前面套一层 nginx 做反代是最佳实践。


nginx 反代配置

以 vLLM 端口 8000 为例:

nginx
# /etc/nginx/sites-available/inference
server {
    listen 443 ssl http2;
    server_name api.your-domain.com;

    ssl_certificate     /etc/nginx/ssl/your-domain-fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/your-domain-key.pem;

    # 限流:每秒最多 5 个请求
    limit_req_zone $binary_remote_addr zone=api_limit:10m rate=5r/s;
    limit_req zone=api_limit burst=10 nodelay;

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;

        # 超时设置(推理可能比较慢)
        proxy_read_timeout 300s;
        proxy_send_timeout 300s;

        # 流式传输支持
        proxy_buffering off;
    }
}

API Key 鉴权

三种方案,从简到严:

方案一:nginx 简单密码(最简)

nginx
location / {
    # 固定 API Key 校验
    if ($http_authorization != "Bearer your-secret-api-key-here") {
        return 401;
    }
    proxy_pass http://127.0.0.1:8000;
}

调用时带 Header:Authorization: Bearer your-secret-api-key-here

方案二:nginx auth_request(中等)

nginx
location / {
    auth_request /auth;
    proxy_pass http://127.0.0.1:8000;
}

location = /auth {
    internal;
    proxy_pass http://127.0.0.1:3000/verify;  # 自己的鉴权服务
    proxy_pass_request_body off;
    proxy_set_header Content-Length "";
    proxy_set_header X-Original-URI $request_uri;
}

方案三:在推理代码里做(最灵活)

python
from fastapi import FastAPI, HTTPException, Header
import os

app = FastAPI()
API_KEY = os.getenv("API_KEY", "change-me")

@app.middleware("http")
async def verify_key(request, call_next):
    if request.url.path != "/health":
        auth = request.headers.get("Authorization", "")
        if auth != f"Bearer {API_KEY}":
            return HTTPException(status_code=401, detail="Invalid API Key")
    return await call_next(request)

访问控制

IP 白名单

nginx
location / {
    allow 192.168.1.0/24;    # 内网
    allow 你的固定IP;
    deny all;

    proxy_pass http://127.0.0.1:8000;
}

防火墙兜底

bash
# 推理端口不开公网,只允许本地 nginx 访问
sudo ufw allow from 127.0.0.1 to any port 8000
sudo ufw deny 8000

请求限制

nginx 限流

nginx
# 按 IP 限流
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=5r/s;

# 按 API Key 限流(如果有鉴权)
limit_req_zone $http_authorization zone=key_limit:10m rate=20r/s;

Token 消耗限制

在推理层限制单次请求的 max_tokens:

python
# vLLM 参数
--max-model-len 4096  # 限制上下文长度

监控与日志

nginx
# 记录请求日志
log_format inference '$remote_addr - $remote_user [$time_local] '
                     '"$request" $status $body_bytes_sent '
                     '"$http_authorization" $request_time';

access_log /var/log/nginx/inference-access.log inference;

分析日志看:谁在调、调了多少次、平均耗时多久。


最小安全清单

  • [x] 推理服务只监听 127.0.0.1,不暴露公网端口
  • [x] 公网入口走 nginx HTTPS
  • [x] 配置 API Key 鉴权
  • [x] 设置请求频率限制
  • [x] 限制单次请求 token 数(防滥用)
  • [x] 记录访问日志
  • [ ] 定期检查日志,关注异常 IP

🎯 本章要点

  • 推理服务绝对不能裸跑公网——前面必须套 nginx 做反代+HTTPS
  • API Key 鉴权三方案:nginx 简单校验 / auth_request / 代码内中间件
  • 限流分两层:nginx 按 IP 限速 + 推理层限制 max_tokens
  • 防火墙兜底:推理端口只开 127.0.0.1
加载练习题中...

有问题或补充?欢迎留言