在家或公司内网访问 Ollama,改个监听地址就够;要让外网访问——出差时用手机调家里的模型、给朋友分享一个稳定的 API 入口、把内网机接到线上服务里——事情就变了:Ollama 的 API 没有账号密码机制,直接把 11434 端口甩到公网上等于把整个模型库裸奔给全网。这篇的方案是”本机监听不动,反代出门”,用 Nginx 反向代理加一层访问控制,再补上 HTTPS 与跨域配置。

解决什么问题

目标架构一句话:Ollama 只听 127.0.0.1:11434(默认即是,不动它),Nginx 监听 443 端口对外服务,请求经 TLS 加密、密码校验后才转发给本机的 Ollama。

这样分层有三个理由。第一,安全边界收在反代上:访问控制、限速、日志都在这一层做,Ollama 本体不暴露。第二,TLS 在反代终结:Ollama 服务本身不终结 HTTPS,证书挂到 Nginx 上即可。第三,接口行为零改变:转发后的 API 与本机完全一致,调用方式照着Ollama API 调用:REST 与 OpenAI 兼容模式写就行。

局域网内共享(手机、平板连电脑)是更简单的场景,先看Ollama 局域网共享:OLLAMA_HOST 配置;这篇处理的是跨公网的那一段。

环境与版本

  • 一台有公网入口的 Linux 服务器(云主机,或家里有公网 IP/IPv6 的机器),Ollama 已装好并能本地 ollama run,版本【待补:ollama —version 实测输出】;
  • Nginx 已安装,版本【待补:nginx -v 实测输出】;
  • 一个解析到服务器的域名,TLS 证书由 certbot 或云厂商签发【待补:实际证书路径与签发方式】;
  • 服务器内存 8GB 以上、已拉好至少一个模型(7B 级 Q4 权重约 4.5GB),磁盘留 20GB 余量。

没有公网 IP 的环境(家庭宽带多为此情况)用内网穿透补位:Cloudflare Tunnel 或 frp 把本机 11434 挂到隧道上,本文思路同样适用——穿透出口仍要加访问控制。

分步骤

第一步:确认 Ollama 只监听本机

# 确认监听地址是 127.0.0.1:11434
ss -ltnp 'sport = :11434'
# 输出里 Peer 应为 127.0.0.1:11434 而不是 0.0.0.0:11434 或 *:11434

# 如果之前改过 OLLAMA_HOST=0.0.0.0,改回仅本机监听
sudo systemctl edit ollama
# [Service]
# Environment=OLLAMA_HOST=127.0.0.1:11434
sudo systemctl restart ollama

公网场景下 Ollama 保持默认监听是安全底线——所有对外的门都交给反代来开。

第二步:写 Nginx 反代配置

# /etc/nginx/conf.d/ollama.conf
server {
    listen 443 ssl;
    server_name ollama.example.com;   # 换成你的域名

    ssl_certificate     /etc/letsencrypt/live/ollama.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/ollama.example.com/privkey.pem;

    # 整站 Basic Auth(下一步生成密码文件)
    auth_basic           "ollama";
    auth_basic_user_file /etc/nginx/ollama.htpasswd;

    location / {
        proxy_pass http://127.0.0.1:11434;
        proxy_http_version 1.1;
        proxy_set_header Host              $host;
        proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;

        proxy_buffering off;     # 流式输出不缓冲,token 逐段到达
        proxy_read_timeout 600s; # 长回答不断流,默认值容易中途 504
    }
}

server {
    listen 80;
    server_name ollama.example.com;
    return 301 https://$host$request_uri;   # HTTP 全部跳 HTTPS
}

proxy_buffering offproxy_read_timeout 这两行别省:前者决定流式输出是一段段吐还是攒到最后一坨吐,后者决定生成 60 秒以上的长回答会不会被代理掐断——一次长回复超过默认超时是家常便饭。

第三步:生成访问凭证并收紧防火墙

# 生成 Basic Auth 密码文件(没有 htpasswd 就装 apache2-utils)
sudo htpasswd -c /etc/nginx/ollama.htpasswd tusky
sudo nginx -t && sudo systemctl reload nginx

# 防火墙:只放 443,绝不放 11434;有固定出口 IP 的话直接白名单
sudo ufw allow from <你的出口IP> to any port 443 proto tcp
sudo ufw deny 11434/tcp
# 云主机同时在控制台安全组里做同样的限制

Ollama 的 API 能做的事远不止对话:拉模型写满磁盘、删模型、消耗算力都可以通过接口完成,没有鉴权层兜底,这层门必须由反代来把守。

第四步:跨域与临时穿透(按需)

网页前端从 https://ollama.example.com 之外的其他域名页面调用 API 时,浏览器会拦跨域请求——Ollama 默认只放行本机来源。给服务加一条环境变量:

sudo systemctl edit ollama
# [Service]
# Environment=OLLAMA_ORIGINS=https://app.example.com
sudo systemctl restart ollama
# 【待补:如实际遇到 CORS 报错,补报错原文与最终生效的配置】

服务器没有公网 IP 时,Cloudflare Tunnel 五分钟出一条临时通道:

cloudflared tunnel --url http://localhost:11434
# 输出一个临时 https 域名,仍建议在前方加访问控制

第五步:外网验证

# 不带凭证:应被拦下(401)
curl -I https://ollama.example.com/api/tags

# 带凭证:返回模型列表 JSON
curl -u tusky:<> https://ollama.example.com/api/tags

# 流式对话走一遍完整链路
curl -N -u tusky:<> https://ollama.example.com/api/generate \
  -d '{"model":"qwen3:8b","prompt":"用一句话介绍你自己","stream":true}'

三条都符合预期(401 拦截、带凭证 200、流式逐段输出),链路就算通了【待补:实测响应记录与截图】。

常见坑

坑一:图省事直接 OLLAMA_HOST=0.0.0.0 加安全组全开。 这是把没有鉴权的 API 裸奔到公网——公开扫描引擎会持续探测常见端口,11434 上的服务被发现只是时间问题,别人可以随意用你的算力、删你的模型。正确姿势永远是”本机监听 + 反代出门”。

坑二:忘了 proxy_buffering off,流式变”假死”。 Nginx 默认缓冲上游响应,客户端看起来毫无输出,几十秒后一次性吐完全部内容,调用方还以为服务挂了。流式接口的前面必须有这条。

坑三:长回答中途 504。 反代默认读超时偏短,大模型一次长生成轻松超过 60 秒,代理直接掐断连接。把 proxy_read_timeout 调到 300~600 秒,客户端侧的超时也要同步放宽。

坑四:HTTPS 之后网页前端突然调不通 API。 浏览器混合内容策略不允许 HTTPS 页面调 HTTP 接口;换了新域名的页面还会撞上 CORS。前者靠全站 HTTPS 解决,后者用 OLLAMA_ORIGINS 放行来源域名。

最终效果

外网任何设备通过 https://域名 访问:无凭证一律 401,带凭证的请求经 TLS 加密转发到本机 Ollama,接口行为与本地调用完全一致;服务器上 11434 端口对外不可见,模型库和算力只对持有密码的人开放。

反代链路示意:客户端经 HTTPS 与鉴权到 Nginx,再转发到本机 Ollama

后续想换凭证或加用户,改 htpasswd 文件 reload 即可;想进一步限流、加 IP 白名单,都在 Nginx 这一层扩展。

相关阅读