如何在 VPS 上安全部署 Ollama 和本地大模型
7B 模型约需 8 GB RAM,CPU 速度约为每秒 4 到 10 个 token。本文介绍如何在 VPS 部署 Ollama,通过 127.0.0.1:11434/v1 调用,并保持 11434 端口关闭。
构建内容
在您拥有的服务器上运行一个单一的开放权重语言模型,通过 HTTP API 提供响应;如果需要,也可以在浏览器中使用聊天页面。Ollama 负责下载模型、将模型加载到内存,并在 http://127.0.0.1:11434 上提供请求服务。安装只需执行一条命令。真正复杂的部分在其他地方:选择 VPS 实际能够装入 RAM 的模型,并避免将没有身份验证的推理服务器意外发布到整个互联网。
先说明两点。仅使用 CPU 的 VPS 运行小型模型时速度较慢,而且 API 完全没有内置身份验证。下文会详细说明这两点,因为它们都是最容易造成问题的地方。
用简单数字核对资源需求
模型的内存占用大致等于模型文件大小,加上约 1 GB 的运行时开销,再加上上下文窗口所需的额外内存。大多数热门 Ollama 模型的默认标签(包括 llama3.2:3b、llama3.1:8b 和 mistral:7b)使用 4-bit 量化(标记为 Q4_K_M),每 10 亿个参数约占 0.5 GB RAM。并非所有默认标签都是 Q4:smollm2:135m 等小型模型以 16-bit 发布,因此在计算前应查看模型库页面上的量化信息。计算方法很简单,而且它决定了模型是否能运行。最后一项由您设置:将 num_ctx 调高到 Ollama 的较小默认值以上可以容纳更长的提示词,但会增加 RAM 中的 KV 缓存,因此应先确定上下文长度,再判断模型是否适合运行。
llama3.2:3b 等 3B 模型的下载大小约为 2 GB,运行时需要约 4 GB 可用 RAM。mistral:7b 或 llama3.1:8b 等 7B 或 8B 模型在磁盘上约占 5 GB,需要约 8 GB RAM;若要运行得更稳定,建议使用 16 GB。13B 或 14B 模型大约需要 16 GB。30B 到 70B 范围内的模型需要大内存服务器,或者更现实地说,需要 GPU。在 CPU VPS 上,这类模型可能无法装入内存,或者响应速度慢到无法使用。
接下来是速度,因为这部分经常被低估。CPU 推理受内存带宽限制,而不是受时钟频率限制;共享 vCPU VPS 的内存带宽通常不高。预计速度为个位数到十几 tokens/秒:7-8B Q4 模型可能达到 4 到 10 tokens/秒,3B 模型可能达到 10 到 25 tokens/秒。GPU 的速度大约快一个数量级。这些数字有意保持粗略;更可靠的做法是测量您自己的服务器,下面的运行步骤会说明具体方法。请相信您的 eval rate,不要相信任何文章中的数字,包括本文的数字。
实际结论是:如果您能够接受相应速度,CPU 上的小型量化模型确实适合用于起草、摘要和分类。对于更大或更快的模型,应为 GPU 实例预留预算。如果您希望查看针对某个具体模型的完整计算过程,在 VPS 上运行 Nemotron 3.5 Lightning一节会说明应拉取哪个标签、实际需要多少 RAM,以及仅使用 CPU 是否能满足速度要求。
要评估某个具体模型在某台具体服务器上的适配情况,请在此估算其内存占用:
安装 Ollama
有两种简洁的安装方式。在裸 VPS 上,官方脚本最简单:
curl -fsSL https://ollama.com/install.sh | sh该脚本会创建名为 ollama 的系统用户,将二进制文件安装到 /usr/local/bin/ollama,并注册名为 ollama.service 的 systemd 服务。该服务会在系统启动时启动,并绑定到 127.0.0.1:11434。确认服务已启动:
systemctl status ollama
ollama --version如果您已经运行 Docker,也可以使用容器:
docker run -d --name ollama \
-p 127.0.0.1:11434:11434 \
-v ollama:/root/.ollama \
--restart always \
ollama/ollama请注意端口映射中的 127.0.0.1: 前缀。它只会将端口绑定到 localhost。改为 -p 11434:11434 会将端口发布到所有网络接口,这正是安全章节警告的错误配置。请选择一种安装方式;不要同时运行脚本和容器,否则两个进程会争用同一个端口。
拉取并运行您的第一个模型
ollama pull llama3.2:3b
ollama run llama3.2:3bpull会将模型层下载到磁盘(此模型约占 2 GB)。run会将这些层加载到内存,并显示 >>>提示符。输入问题。权重从磁盘加载到 RAM 时,第一个 token 可能需要等待几秒,之后答案会以流式方式输出。输入 /bye退出聊天;Ollama 会继续在后台运行。
查看已加载的内容及其占用情况:
ollama psPROCESSOR列显示实际情况。100% CPU表示未使用 GPU,这正是运行缓慢的原因。使用 verbose 标志测量实际速度:
ollama run --verbose llama3.2:3b "Write two sentences about Linux."末尾输出的 eval rate行表示此硬件上的每秒 token 数。这就是规划时应采用的数值。
模型存放位置及磁盘容量规划
由脚本安装并作为服务运行时,模型存放在 ollama 用户的主目录中:
sudo du -sh /usr/share/ollama/.ollama/models以您自己的用户身份交互运行时,模型存放在 ~/.ollama/models 中。在容器中,模型存放在名为 ollama 的卷中。这一点很重要,因为量化权重会快速占用磁盘空间:3B 模型约占 2 GB,7-8B 模型约占 5 GB,14B 模型约占 9 GB。拉取 4 个模型进行比较后,可能不知不觉就占用了 20 GB。请根据计划保留的模型规划磁盘容量,并使用 ollama rm <model> 删除其余模型。如果同一 VPS 还运行着自身占用大量空间的服务,例如 存储照片库的 PhotoPrism 或 Immich,应先从可用空间中扣除这部分占用,再将剩余空间作为实际的模型容量预算。
将其作为受控服务运行
安装脚本已经注册了 ollama.service,因此系统启动时会自动重启,无需额外操作。值得调整的设置是模型在内存中的驻留时间;在某些环境中,还需要调整绑定地址。这两项设置都应写入 systemd drop-in 文件,这样升级 Ollama 时不会覆盖它们:
sudo systemctl edit ollama.service在编辑器显示的 [Service] 标题下添加以下内容:
[Service]
Environment="OLLAMA_KEEP_ALIVE=30m"OLLAMA_KEEP_ALIVE 表示模型在最后一次请求后继续保留在内存中的时间(默认 5 分钟)。如果服务器全天都要处理查询,可以延长该时间,避免每次都重新加载权重;如果服务器内存紧张,可以将其设为 0,让请求完成后立即释放 RAM。如果希望模型永久驻留,而不是仅在固定时间窗口内驻留,请参阅让 Ollama 模型永久保持加载,其中介绍了每次请求的 keep_alive 字段,以及如何让权重在重启后重新预热,而不是等到第一次请求时才进行缓慢加载。systemctl edit 会自动重新加载 unit 文件,因此需要重启服务才能应用更改:
sudo systemctl restart ollama最重要的安全要点
默认情况下,Ollama 绑定在 127.0.0.1:11434,因此只有 VPS 本机上的进程可以访问它。这个默认设置是正确的。请保持不变。
API 没有身份验证。完全没有。它没有 API 密钥、登录功能或速率限制。它唯一的允许列表 OLLAMA_ORIGINS 只控制哪些浏览器来源可以调用 API(CORS);它无法阻止 curl 或其他计算机上的脚本。任何能够访问 11434 端口的人,都可以运行你已拉取的任意模型、拉取新模型、删除模型,并让 CPU 或 GPU 长时间满负载运行。Shodan 等扫描器会按千计地索引开放的 Ollama 实例,暴露在公网的实例通常会在数小时内被发现并滥用。
因此,绝对不要犯这个错误:不要设置 OLLAMA_HOST=0.0.0.0,也不要在防火墙中开放 11434 端口。这样会将未经身份验证的推理服务器发布到整个互联网。无论如何配置,直接通过 0.0.0.0 暴露 11434 都不安全,因为 Ollama 文档列出的设置中没有任何一项可以为本地 API 添加身份验证,而来源允许列表也不是登录机制。这条规则针对的是这个特定服务,并不表示任何端口都不能开放:用于远程桌面的自托管 RustDesk 中继必须接受公网流量才能正常工作,并且它通过自身的基于密钥的身份验证以及一份简短、明确记录的端口列表来保证安全;Ollama 完全没有这些机制。
从其他位置访问该模型,有以下 3 种安全方式:
- 保持本地访问。如果唯一的调用方是同一 VPS 上的其他程序、cron 脚本、机器人或将工具连接到模型的 MCP 服务器,请将绑定地址保持为
127.0.0.1,并让该程序调用http://127.0.0.1:11434。这样不会暴露任何接口,也不需要其他配置。 - 通过私有隧道访问。将 VPS 加入你自行托管的 WireGuard VPN,将
OLLAMA_HOST设置为隧道地址(例如10.8.0.1,而不是0.0.0.0),这样只有 VPN 对等端可以连接。公网仍然无法看到 11434 端口。 - 在前面部署带身份验证的反向代理。在 nginx、Traefik 或 Caddy 上终止 TLS,并要求输入密码或令牌,然后将请求代理到
127.0.0.1:11434。Ollama 继续绑定 localhost;只有代理监听公网端口。这与在任意本地服务前面通过 nginx 配置 Let's Encrypt 证书的方式相同。
下一步的聊天界面正是采用反向代理方案,并附带真正的登录功能。
使用 Open WebUI 添加聊天界面,并置于 TLS 后
Open WebUI 是一个自托管聊天界面。将其运行在 Docker 中,并让它连接本地 Ollama:
docker run -d \
--name open-webui \
--network=host \
-e OLLAMA_BASE_URL=http://127.0.0.1:11434 \
-v open-webui:/app/backend/data \
--restart always \
ghcr.io/open-webui/open-webui:main在 Linux VPS 上,--network=host 标志非常重要。它会让容器使用主机的网络命名空间,因此容器内的 127.0.0.1 就是主机自身的回环地址,容器可以通过 127.0.0.1:11434 连接 Ollama,而无需让 Ollama 监听其他接口。其他位置介绍的桥接网络配置使用 --add-host=host.docker.internal:host-gateway 和 OLLAMA_BASE_URL=http://host.docker.internal:11434,在这里无法工作:该名称会解析为 Docker 桥接网关,而主机上绑定到 127.0.0.1 的服务无法通过桥接网络访问,因此 Open WebUI 只会持续报告无法连接 Ollama。
使用主机网络的代价是,Open WebUI 现在会在主机的所有接口上监听端口 8080;任何 -p 映射都会被丢弃,Docker 也会输出相应警告。因此,应在主机防火墙和云服务商防火墙上同时关闭 8080,并让 TLS 反向代理成为唯一的公网入口。首次访问 Open WebUI 时,系统会要求您创建管理员账户。该账户就是身份验证层,因此应设置强密码。
要通过 HTTPS 从笔记本电脑打开聊天界面,请在 127.0.0.1:8080 前面配置 TLS 反向代理。如果您已经在这台主机上为多个 Docker 应用配置路由,使用 Traefik 为多个应用自动配置 TLS 是最合适的方案:一个标签配置块即可申请证书,并将 chat.example.com 路由到 Open WebUI。相同的按应用配置标签的路由方式也适用于主机上的其他浏览器前端,无论是状态面板,还是更具娱乐性的应用,例如 Halcyon,它会将 Jellyfin 媒体库呈现为 90 年代的录像带租赁店;每个应用都使用独立主机名,并配置独立登录。安全性章节中的规则仍然适用:代理负责公网端口和登录,Ollama 保持监听 localhost,而 Open WebUI 自身的 8080 继续由防火墙阻止。
在代码中使用 OpenAI 兼容端点
Ollama 在 /v1 提供 OpenAI Chat API 的一个子集,因此大多数 OpenAI 客户端库只需修改两项内容即可使用:基础 URL 和临时密钥。
from openai import OpenAI
client = OpenAI(base_url="http://127.0.0.1:11434/v1", api_key="ollama")
resp = client.chat.completions.create(
model="llama3.2:3b",
messages=[{"role": "user", "content": "Name three Linux distributions."}],
)
print(resp.choices[0].message.content)客户端库要求提供 api_key,但 Ollama 会忽略它,因此可以使用任意字符串。model 必须是您已拉取的模型名称;如果名称未知,Ollama 会返回包含 model 'x' not found 的 404 响应。直接使用 curl 调用的原理相同:
curl http://127.0.0.1:11434/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model":"llama3.2:3b","messages":[{"role":"user","content":"Hello"}]}'将模型接入代理工具和编辑器工具时,也采用这种方式。如果您已经在这台服务器上进行开发,本地模型可以与 在 VPS 的 tmux 中运行的 Claude Code 一起为脚本和插件提供支持,将成本低且注重隐私的起草工作交给本地模型,同时将复杂推理交给托管模型。
故障模式,以及你将看到的确切字符串
进程在生成过程中显示 “Killed”。 启动大型模型后,终端会打印 Killed,或者服务器日志(journalctl -u ollama)会显示一行以 llama-server process has terminated 开头的内容。这是 Ollama 0.40.3 中使用的措辞,已于 12 October 2026 核对;旧版本显示的是 llama runner process has terminated: signal: killed。Linux OOM killer 终止了该进程,因为模型需要的 RAM 超过了服务器的实际容量。使用 sudo dmesg | grep -i oom 确认原因。你会看到类似 Out of memory: Killed process ... 的行。解决方法是改用更小或量化程度更高的模型,例如使用 llama3.2:3b,而不是 13B;也可以增加 swap。这样,刚好超出物理 RAM 的负载会缓慢完成,而不是直接退出。swap 会把立即崩溃变成缓慢响应;它不会让 70B 模型在 4 GB 内存上变得可用。除非你正好在观察终端,否则进程被终止时不会有明显提示。因此,在从其他位置查询的服务器上,将一个 OnFailure= 单元附加到 ollama.service,让它向 你托管的 ntfy 服务器发送推送告警,即可在进程退出时立即收到通知,而不是等到下次请求时才发现。
Ollama 拒绝加载模型。 请求会立即失败并返回错误,而不是导致进程崩溃;服务器日志会记录 model is too large for system memory(Ollama 0.40.3,已于 12 October 2026 核对)。旧版本会直接在提示符处显示 Error: model requires more system memory (X GiB) than is available (Y GiB)。这是上一个故障的主动处理版本:Ollama 先完成内存计算,然后停止,而不是等待 OOM killer 终止进程。选择内存需求低于可用 RAM 的模型(使用 free -h 检查),缩短上下文长度,或迁移到更大的 VPS。没有任何 flag 能让模型适应不足的内存;所需内存是实际存在的。
第一个 token 等待很久,之后运行正常。 冷启动的模型在前五到三十秒内不会输出内容,随后会正常流式输出。暂停期间,模型权重首次从磁盘加载到 RAM;存储速度较慢时,等待时间会更长。加载完成后,模型会在 OLLAMA_KEEP_ALIVE 的持续时间内保留在内存中,因此第二次提示会立即得到响应。如果首次加载时间超过调用链中的某个超时值,你会收到错误,而不是慢速响应。确定是哪一层报告 context deadline exceeded,可以判断是客户端、代理还是模型加载过程超时。若等待时间令人困扰,请提高该值,并使用 ollama ps 查看当前是否已加载模型。
所有操作都很慢。 每秒只能生成 10 个或更少的 token,且完全没有错误。这是 CPU 推理的正常表现。ollama ps 显示 100% CPU,表示没有 GPU。这不是 bug,也没有任何设置能将 CPU 变成 GPU,因为主要限制是内存带宽。不过,在 VM 上值得测试一个设置:Ollama 根据检测到的物理核心数选择线程数,而虚拟化管理程序可能会错误报告该数量。在 ollama run --verbose 会话中,尝试使用 /set parameter num_thread 4(或你的 vCPU 数量),重新运行相同的提示,并保留能提供最佳 eval rate 的值。除此之外,应改用更小的模型、接受当前速度,或迁移到 GPU 实例。在判断系统是否损坏之前,使用 --verbose 测量实际速率。如果等待时间来自回答长度而不是生成速率,使用 num_predict 限制回复长度,可避免模型花费数分钟生成你根本不会阅读的 token。
从另一台机器连接时被拒绝。 在笔记本电脑上,你会看到 curl: (7) Failed to connect to <ip> port 11434: Connection refused。这是预期行为:Ollama 仅绑定 localhost。不要通过绑定 0.0.0.0 来“修复”问题,因为这正是前文所述的暴露错误。应通过 VPN 或带身份验证的代理访问模型。
你已将 11434 暴露到互联网。 如果你设置了 OLLAMA_HOST=0.0.0.0、开放了防火墙,现在却发现有从未发起过的模型拉取操作,或 CPU 被未知客户端占用到 100%,说明服务器已经被发现并被利用。这是最严重的配置错误,不是边缘情况。重新绑定到 127.0.0.1 或 VPN 地址,在防火墙上关闭 11434,并在前面配置身份验证。应假设该地址开放期间,任何能够访问它的内容都已被陌生人查询。
备份与升级
需要保存的状态很少。模型可以重新下载,因此值得备份的只有 Open WebUI 的数据卷、账户、聊天记录、设置,以及您编写的任何 systemd drop-in。使用一次性容器备份数据卷:
docker run --rm -v open-webui:/data -v "$PWD":/backup alpine \
tar czf /backup/open-webui.tgz -C /data .重新运行安装脚本即可升级 Ollama;使用 docker pull ghcr.io/open-webui/open-webui:main,然后重新创建容器,即可升级 Open WebUI。关于 0.40 系列,还有一项磁盘注意事项:Ollama 0.40.2 开始在后台升级由早期版本下载的模型,并保留原始副本作为备份。因此,在删除这些副本前,它们会额外占用磁盘空间。0.40.3(11 October 2026)暂停了这项后台升级。升级后检查 df -h,并阅读发行说明,了解删除这些备份的命令。不要长期固定任何版本:模型质量和运行时都在快速变化,因此应阅读发行说明,并在您自己的设备上重新进行基准测试,不要依赖上一季度的数据。
FAQ
我确实可以在仅使用 CPU 的 VPS 上运行 LLM 吗?
可以,但有一定限制。3B 到 8B 范围内的小型量化模型可以在 CPU 上运行,并且确实适用于起草、摘要和分类,只是速度较慢。在共享 vCPU 上,速度通常只有每秒个位数到十几 token。13B 及以上的模型速度会慢得难以使用,甚至根本无法装入 RAM。若需要更高速度或更大的模型,则需要 GPU 实例。
每个模型需要多少 RAM?
对于大多数热门模型默认使用的 4-bit(Q4)量化标签,可以采用一个粗略规则:模型权重每 1B 参数约需 0.5 GB RAM,此外还需约 1 GB 开销,并为上下文预留更多空间。因此,3B 模型需要约 4 GB 可用内存,7-8B 模型需要约 8 GB,14B 模型需要约 16 GB。使用 free -h 检查剩余内存,并为操作系统和服务器上的其他程序预留空间。
Ollama API 是否经过身份验证?
没有。Ollama 没有内置身份验证、API key 或速率限制。任何能够访问 11434 端口的用户都可以完全控制它。它的 OLLAMA_ORIGINS 设置只限制允许调用它的浏览器来源,不限制哪些用户可以连接。这正是它默认绑定到 127.0.0.1 的原因,也是你绝不能将 0.0.0.0 上的 11434 暴露到互联网的原因。请通过本地连接、私有 VPN,或通过添加登录功能的反向代理访问它。
如何添加 Web 聊天界面?
在 Docker 中运行 Open WebUI,并使用 --network=host 让它共享主机的 loopback,从而访问原生 Ollama 的 http://127.0.0.1:11434。然后在其 8080 端口前配置 TLS 反向代理,以便从笔记本电脑访问。使用防火墙关闭 8080,确保反向代理是唯一的公网入口。Open WebUI 自带的管理员账户负责登录,你可以在首次启动时设置密码。
如何从自己的应用调用它?
使用 http://127.0.0.1:11434/v1 上与 OpenAI 兼容的端点。将任意 OpenAI SDK 指向该基础 URL,API key 可以填写任意字符串,因为它会被忽略;将 model 设置为你已拉取的模型名称。现有的 OpenAI 代码通常无需修改即可运行,只需调整基础 URL 和 key。