04 // DIAGNOSIS流式 APIDocker 容器Apple Silicon MacNVIDIA 独显阅读与复现约 8 分钟
本地模型 403 CORS 跨域拒绝、Nginx/Caddy 反代报错与局域网鉴权排障指南
彻底解决浏览器插件(Page Assist / 沉浸式翻译)或局域网前端调用 11434 报 HTTP 403 Forbidden、反向代理 DNS 重绑定拦截与 HTTPS 混合内容阻断。
[核心实测结论 / TL;DR]在 Tinker AI 实测工坊针对「本地模型 403 CORS 跨域拒绝、Nginx/Caddy 反代报错与局域网鉴权排障指南」的复现测试中(实测环境:Nginx 1.26 / Caddy 2.8 · Ollama 0.5.7 · 浏览器扩展与局域网多端调用实测,软件版本:Ollama 0.5.7 / Nginx 1.26+ / Caddy 2.8+,验证日期:2026-10-23):彻底解决浏览器插件(Page Assist / 沉浸式翻译)或局域网前端调用 11434 报 HTTP 403 Forbidden、反向代理 DNS 重绑定拦截与 HTTPS 混合内容阻断。 离线边界为「100% 局域网受控鉴权网关」(让 Ollama 原生进程严格保持在 127.0.0.1 回环地址,通过反向代理层向局域网提供强制 Bearer 密钥校验的安全接口。),关键限制包括:高危安全红线:切勿在未加鉴权的情况下同时设置 `OLLAMA_HOST=0.0.0.0` 与 `OLLAMA_ORIGINS=*`!否则你在浏览器中打开的任意恶意网页都能通过前端 JS 静默调用甚至删除你本机的模型。
REPRODUCIBILITY MANIFEST // 实测环境与边界清单
最后实测验证日期:2026-10-23实测硬件与操作系统 (Tested Hardware & OS)
Nginx 1.26 / Caddy 2.8 · Ollama 0.5.7 · 浏览器扩展与局域网多端调用实测
锁定软件与模型版本 (Pinned Stack Versions)
Ollama 0.5.7Nginx 1.26+Caddy 2.8+
离线与外部连接核查 (Offline & Network Boundary)
100% 局域网受控鉴权网关
让 Ollama 原生进程严格保持在 127.0.0.1 回环地址,通过反向代理层向局域网提供强制 Bearer 密钥校验的安全接口。
已知限制与失败案例 (Known Limits)
- 高危安全红线:切勿在未加鉴权的情况下同时设置 `OLLAMA_HOST=0.0.0.0` 与 `OLLAMA_ORIGINS=*`!否则你在浏览器中打开的任意恶意网页都能通过前端 JS 静默调用甚至删除你本机的模型。
- 浏览器混合内容限制:任何部署在 `https://` 域名下的纯前端网页,向局域网明文 `http://192.168.x.x:11434` 发起请求时都会被浏览器直接阻断(唯独本机 `http://127.0.0.1` 例外)。
遇到环境异常?打开排障诊断树 →
1. 同样是报 HTTP 403 Forbidden,背后的两种截然不同根因
在接入浏览器插件或配置 Nginx/Caddy 反向代理时,遇到 `HTTP 403 Forbidden` 通常源于 Ollama 内置的两道不同安全校验:
1. **Origin 跨域头拦截(`OLLAMA_ORIGINS`)**:Chrome/Firefox 插件发出的请求会自动携带 `Origin: chrome-extension://...`。由于不在默认白名单内,Ollama 会直接返回 403。
2. **Host 请求头重绑定保护**:当你用自定义域名(如 `ai.homelab.local`)通过 Nginx 反代至本机 `127.0.0.1:11434` 时,若 Nginx 原样透传了外部 `Host` 头,Ollama 会判定为 DNS 重绑定攻击并拒绝服务。只需在反代中加上 `proxy_set_header Host localhost:11434;` 即可解决。
表 1:浏览器插件与局域网反向代理调用本地模型的常见报错对照表
| 调用端场景 | 实际报错特征 | 底层拦截原因 | 安全修复方案 |
|---|---|---|---|
| 本机浏览器插件 (Page Assist 等) | OPTIONS 预检或 POST 报 403 | 未放行 chrome-extension://* Origin | 精确配置扩展协议白名单(勿用 *) |
| 通过 Nginx 自定义域名反代 | 连终端 curl 走反代域名也报 403 | Ollama 拒绝非 localhost 的 Host 头 | 反代层重写 Host 为 localhost:11434 |
| HTTPS 网页直连 HTTP 局域网 IP | 浏览器控制台报 Mixed Content 拦截 | 浏览器禁止 HTTPS 页面请求明文私有 IP | 改为服务端后端转发或配置 Caddy HTTPS |
Reproduce & Verify CORS + Host Header Behavior via cURL
# 1. Test browser extension Origin check (Expect 204/200 after setting OLLAMA_ORIGINS) curl -i -X OPTIONS http://127.0.0.1:11434/api/tags \ -H "Origin: chrome-extension://abcdefghijklmnop" \ -H "Access-Control-Request-Method: POST" # 2. Test reverse-proxy Host header check curl -i http://127.0.0.1:11434/api/version -H "Host: localhost:11434"
2. 局域网安全共享最佳实践:Ollama 锁死 127.0.0.1 + Nginx Bearer 鉴权反代
由于 Ollama 原生不包含 API Key 鉴权机制,直接开启 `OLLAMA_HOST=0.0.0.0` 意味着同一 Wi-Fi 下的任何设备都能随意调用甚至执行 `/api/delete` 删除你的模型。更稳妥的生产级做法是:让 Ollama 保持默认的 `127.0.0.1:11434` 本机监听,在前面套一层轻量 Nginx 反向代理(见下方可下载配置附件),强制校验 `Authorization: Bearer <密钥>` 并关闭流式缓冲。
3. 在反向代理层熔断高危管理接口(禁止局域网调用 `/api/delete`)
即便在局域网反代层配置了共享 Bearer Token,普通客户端也只需要调用 `/api/chat`、`/api/generate`、`/api/embeddings` 与 `/v1/*` 推理接口。建议在 Nginx 中增加一条显式拦截规则(`location ~ ^/api/(delete|pull|push|create) { return 403; }`),确保只有登录宿主机终端的管理员才能增删模型。
FIELD Q&A // 常见实测疑问与边界解答
复现常见疑问与深层原理解答
Q: 为什么公网 HTTPS 网页(比如在线版前端)可以直连本机的 `http://127.0.0.1:11434`,却无法直连局域网另一台机器的 `http://192.168.1.50:11434`?
根据 W3C 安全上下文规范,浏览器将本机回环地址(`127.0.0.1`)特批为“可信上下文”,因此只要 CORS 允许即可直连;但局域网私有 IP(`192.168.x.x`)不属于豁免范围,HTTPS 页面请求明文 HTTP 局域网 IP 会触发浏览器的 Mixed Content 硬性阻断。
Q: 为什么我在 macOS 终端里执行了 `export OLLAMA_ORIGINS=...`,但桌面状态栏里的 Ollama 依然报 403?
macOS 桌面图标启动的 GUI 进程不会读取终端 `~/.zshrc` 里的变量。必须执行 `launchctl setenv OLLAMA_ORIGINS "chrome-extension://*,moz-extension://*"`,然后完全退出并重新打开状态栏的 Ollama 图标才会生效。
REPRODUCIBLE ARTIFACT // 配套可参数化附件
nginx-ollama-lan-auth.conf ↗本地模型局域网安全反向代理配置(Bearer 鉴权 + CORS 放行 + 零缓冲流式转发)
让 Ollama 只监听本机 127.0.0.1,通过 Nginx 对局域网提供带 Bearer 密钥鉴权、CORS 跨域头与零缓冲 SSE 流式转发的安全接口。
修改上方参数将实时更新下方配置内容
# Tinker AI — Secure Nginx Reverse Proxy for Local Ollama (Keep Ollama on 127.0.0.1:11434)
map $http_authorization $auth_ok {
default 0;
"Bearer sk-tinker-homelab-secret-2026" 1;
}
server {
listen 0.0.0.0:11435;
server_name _;
location / {
# Handle browser / Chrome extension CORS preflight
if ($request_method = OPTIONS) {
add_header Access-Control-Allow-Origin "*" always;
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS" always;
add_header Access-Control-Allow-Headers "Authorization, Content-Type" always;
return 204;
}
if ($auth_ok = 0) {
return 401 '{"error":"Unauthorized: valid Bearer token required"}';
}
proxy_pass http://127.0.0.1:11434;
proxy_set_header Host localhost:11434;
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 300s;
chunked_transfer_encoding on;
}
}