简介:面向Ubuntu运维与AI部署人员,该资源包围绕Ollama v0.3.12的离线安装与大模型私有化部署场景给出完整解决方案,适用于无外网或内网隔离环境。包内共24个文件,总大小2.91MB,以2份Markdown文档、1份shell脚本、1份Modelfile和19张流程截图为主:文档分别介绍离线安装步骤和基于Ollama离线部署llama3.1-70b模型的完整流程,脚本可自动完成安装,Modelfile用于构建模型,截图则对应关键操作界面,便于对照。由于示例中提到DeepSeek同样适用,因此该资源对当前主流的开源大模型私有化部署具有普遍参考价值。读者借助脚本和指南可快速搭建Ollama服务,再按示例构建并运行70B级大模型,有效降低离线部署门槛。目前已获得601人学习,适合需要在内网服务器上部署大模型的技术人员直接使用。
1. ollama-v0.3.12 离线安装脚本:为什么 Ubuntu 内网服务器绕不开它
官方那条 curl 在线安装命令一到隔离网段就失效,手动去官网拖 tgz 又经常撞上“ollama下载慢”;就算找到可用的镜像源,也不一定覆盖得了每个部署现场。给 ubuntu 做一份 ollama-v0.3.12 离线安装脚本,本质是把依赖判断、目录规划和服务注册一次性固化下来,这是私有化交付的必备工序。
锁住 0.3.12 这个版本,是因为 0.3.x 时期对 Ubuntu 20.04/22.04 的兼容性最稳,大量离线部署文档都以这个版本线为基线。版本钉死之后,脚本、服务配置和踩坑经验才有沉淀价值,升级时再另走一套验证流程。
这篇面向 Ubuntu 服务器管理员和内网做私有大模型部署的开发者,按“准备离线包 → 跑脚本 → 导模型 → 排坑”的顺序落地,每一步都有可抄的参数和命令,可以直接照做。
2. 离线安装前的准备:依赖清单、架构判断与安装包获取
在写脚本之前,先把三件事定死:目标机是什么架构、依赖是否齐全、安装包从哪来。这一步偷懒,后面脚本跑起来就像开盲盒,报错千奇百怪。
2.1 用 uname 判断目标机架构,别用想当然
ollama 官方 Linux 离线包按架构分别发布,x86_64 和 arm64 是两个互不通用的包。把 amd64 的包放到 ARM 服务器上,执行时直接报 “Exec format error”,现场的人容易原地懵掉。判断架构只需要一条命令:
uname -m输出x86_64表示要下载 amd64 包,输出aarch64表示要 arm64 包。我一般还会再用脚本确认一次:
[ "$(uname -m)" = "x86_64" ] && echo amd64 || echo arm64有人习惯用arch命令,它和uname -m的输出基本一致。确认好架构之后,把它记下来,后面下载包和脚本里的ARCH变量都按这个值来。
为什么值得单独强调?因为 0.3.12 时代的教程大多默认 x86,ARM 的适配是后面才多起来的。交接时只说“把包拷过去”,现场很可能抓错包。所以我写的安装脚本里会强制跑架构自检,架构不匹配直接退出,不留侥幸空间。
2.2 在联网机器上准备离线包与依赖检查
离线部署的常规路径是:先用一台能联网、系统版本与目标机接近(最好大版本一致)的 Ubuntu 机器,把 ollama 的 Linux tgz 包下载下来。下载页给的文件名一般是ollama-linux-amd64.tgz这种;我存档时会重命名成ollama-v0.3.12-linux-amd64.tgz,避免时间一长被新包覆盖。
拿到包之后别急着拷走,先验一遍文件内容。解压到临时目录,检查结构和依赖:
mkdir -p /tmp/check-ollama tar -xzf ollama-v0.3.12-linux-amd64.tgz -C /tmp/check-ollama ls -R /tmp/check-ollama | head -30 ldd /tmp/check-ollama/bin/ollama解压后你会看到典型结构:bin/ollama是可执行文件,lib/ollama下是配套动态库(通常还带 CUDA 相关子目录)。ldd列出它链接的系统库,常见依赖是libc.so.6、libstdc++.so.6、libgcc_s.so.1。
然后对着目标机查这些基础库是否存在:
dpkg -l | grep -E 'libc6|libstdc\+\+6|libgcc-s1'正常的 Ubuntu 20.04 或 22.04 桌面版、服务器版里这些默认都在;但如果你拿到的是被裁剪过的精简容器或最小化安装,可能缺libstdc++6。缺了也别慌,在联网机器上下载对应的 .deb 包,一并带到现场做离线安装。
提示:离线包建议用 sha256 校验。现场没法重新下载,文件坏了就是拆机级别的折腾。
模型文件也要在联网阶段提前准备:无论你要部署 qwen2.5 还是其他开源模型,在线机器先把 GGUF 文件下载好。这一步常被忽略,到了现场才发现模型没带,整个部署直接卡死。
2.3 目录规划:程序、模型、日志三分离
离线安装不只是“能跑”,还要“好维护”。我的习惯是把程序本体、模型存储、日志三块分开:
| 路径 | 用途 | 建议 |
|---|---|---|
/usr/local/lib/ollama/ | 可执行文件与动态库 | root:root,权限 755 |
/usr/local/bin/ollama | 对外命令软链 | 指向上面 |
/data/ollama/models | 模型文件目录 | 选容量最大的分区 |
/data/ollama/logs | 日志目录 | 方便集中收集 |
为什么程序本体放/usr/local/lib/ollama而不是直接扔/usr/local/bin?因为 ollama 运行时要找同目录下的动态库。如果可执行文件在/usr/local/bin,库却在另一个目录,启动时就会报 “cannot open shared object file”。放到同一个目录里,再软链到bin,PATH 能找到命令,程序自己也能找到库。
模型目录单独放/data/ollama/models还有一个现实原因:一个 7B 量化模型接近 4-5GB,13B 以上直接上 8GB。默认塞进/root/.ollama/models的话,主分区很容易满,到时候 systemd、日志、临时文件跟着一起炸。我在离线环境里见过太多no space left on device导致进程反复重启的现场,所以上来就把这个坑规避掉。
关于部署形态,常见的选择还有用 docker 部署 ollama 模型。docker 的好处是环境隔离,镜像一到内网就能跑;缺点是容器镜像体积大,离线导入模型还要额外处理 volume 权限。我的原则是:目标机只装 ollama 一个服务时,直接二进制加 systemd,路径清晰,排查方便;如果现场已经有容器编排体系,才考虑 docker 方案。下面的脚本以二进制方式为准。
3. 手写 ollama-v0.3.12 离线安装脚本:逐段拆解与环境变量设计
这一章是核心,给出我交付项目里常用的脚本骨架,分四段拆开讲。可以整段抄走,也可以按需裁剪。
3.1 脚本骨架:参数定义与架构自检
脚本第一步是把变量都定义出来,并做架构自检:
#!/usr/bin/env bash set -euo pipefail OLLAMA_VERSION="0.3.12" OLLAMA_PKG_DIR="/opt/pkgs" OLLAMA_LIB_DIR="/usr/local/lib/ollama" OLLAMA_BIN_LINK="/usr/local/bin/ollama" OLLAMA_ENV_FILE="/etc/ollama/ollama.env" MODEL_HOME="/data/ollama/models" ARCH=$(uname -m) case "$ARCH" in x86_64) OLLAMA_ARCH="amd64" ;; aarch64) OLLAMA_ARCH="arm64" ;; *) echo "不支持的架构: $ARCH" >&2; exit 1 ;; esacset -euo pipefail的效果是:脚本中任何命令失败立即退出,变量没定义直接报错,管道中前面的命令失败也能被捕获。离线安装最怕“半成功”状态——前面失败后面还继续跑,最后也不知道装没装上。
变量集中定义让升级版本时只改一处。OLLAMA_PKG_DIR是安装包存放目录,可以改成/tmp或 U 盘挂载点。架构自检那段把后面所有引用OLLAMA_ARCH的地方统一了,杜绝拿错包。
3.2 解压、安装与软链:最小核心步骤
接下来是核心安装动作:
PKG=$(ls "$OLLAMA_PKG_DIR"/ollama-${OLLAMA_VERSION}-linux-${OLLAMA_ARCH}.tgz 2>/dev/null | head -1) if [ -z "$PKG" ]; then echo "找不到 $OLLAMA_PKG_DIR/ollama-${OLLAMA_VERSION}-linux-${OLLAMA_ARCH}.tgz" >&2 exit 1 fi WORK_DIR=$(mktemp -d) tar -xzf "$PKG" -C "$WORK_DIR" mkdir -p "$OLLAMA_LIB_DIR" # 以 tgz 解压后的结构为准,bin/ 下是主程序,lib/ 下是配套动态库 install -m 755 "$WORK_DIR/ollama/bin/ollama" "$OLLAMA_LIB_DIR/ollama" if [ -d "$WORK_DIR/ollama/lib/ollama" ]; then cp -a "$WORK_DIR/ollama/lib/ollama/." "$OLLAMA_LIB_DIR/" fi ln -sf "$OLLAMA_LIB_DIR/ollama" "$OLLAMA_BIN_LINK" rm -rf "$WORK_DIR"先解释ls那行:我的离线包命名是ollama-0.3.12-linux-amd64.tgz。如果下载回来不是这个命名,把模板改一下,或者在下载阶段统一重命名。找不到包就退出,比后面 tar 报错更友好。
解压用mktemp -d生成临时目录,避免污染当前目录。install -m 755负责复制并强制设置可执行权限,比cp更可控。cp -a保留目录里的符号链接和权限。最后ln -sf建立软链,-f允许覆盖已有链接。
很多人翻车在只复制bin/ollama而漏掉lib/ollama下的动态库,运行时报找不到共享库。所以脚本里加了if [ -d ... ]判断,把库目录整体拷过去。执行完ls $OLLAMA_LIB_DIR,看到的应该是一个可执行文件加一批 .so 文件。
3.3 环境变量与 systemd 服务注册
ollama 默认行为有几处要改:对外监听地址、模型存储路径、连接保持时间。这些通过环境变量控制。
mkdir -p "$(dirname "$OLLAMA_ENV_FILE")" cat > "$OLLAMA_ENV_FILE" <<EOF OLLAMA_HOST=0.0.0.0:11434 OLLAMA_MODELS=$MODEL_HOME OLLAMA_KEEP_ALIVE=5m EOF cat > /etc/profile.d/ollama.sh <<EOF export OLLAMA_HOST="0.0.0.0:11434" export OLLAMA_MODELS="$MODEL_HOME" export OLLAMA_KEEP_ALIVE="5m" EOF cat > /etc/systemd/system/ollama.service <<EOF [Unit] Description=Ollama Offline Service After=network-online.target Wants=network-online.target [Service] EnvironmentFile=$OLLAMA_ENV_FILE ExecStart=$OLLAMA_LIB_DIR/ollama serve Restart=on-failure RestartSec=5s User=ollama Group=ollama WorkingDirectory=$MODEL_HOME [Install] WantedBy=multi-user.target EOF useradd -r -s /usr/sbin/nologin -d "$MODEL_HOME" ollama 2>/dev/null || true mkdir -p "$MODEL_HOME"/{models,logs} chown -R ollama:ollama "$MODEL_HOME" systemctl daemon-reload systemctl enable --now ollama为什么要写/etc/profile.d/ollama.sh?因为系统服务只读不带export的ollama.env,而手工执行ollama create、ollama run时,登录 shell 会从 profile.d 拿到同样三个环境变量。两套配置保持一致,命令行和 systemd 的行为才不会打架。
特别注意:systemd 的EnvironmentFile不支持export前缀,所以ollama.env里只写KEY=value;带export的是给 bash 登录 shell 用的。经常有人把两份文件混用,结果 systemd 解析失败但又不报错,服务起来后监听地址不对,排查半天。
服务跑在专用用户ollama下,不用 root。-r创建系统用户,-s /usr/sbin/nologin禁止登录,-d指定家目录为模型目录,保证它有权限写模型文件。Restart=on-failure加RestartSec=5s,应对启动瞬间的资源争抢,让服务自己缓过来。
OLLAMA_KEEP_ALIVE=5m这个参数值得细说:它表示模型加载后保持 5 分钟再卸载。设太短,频繁对话时每次都重新加载,响应慢;设太长,多个模型积压会吃满显存。离线环境一般只跑一两个模型,5 分钟是个平衡值。
3.4 示例:一条命令完成部署
把上面三段拼到一个文件后,执行:
sudo bash install_ollama_offline.sh脚本跑完,我习惯立刻做一次自检:
systemctl is-active ollama /usr/local/bin/ollama --version curl -s http://127.0.0.1:11434/api/version && echois-active返回active,ollama --version回显 0.3.12,/api/version返回一段带版本号的 JSON,说明服务已经起来。如果前面某一步失败,set -e会让脚本停在出错点,不会继续往下做——这也是我推荐离线安装脚本必须带这个参数的原因。
到这里,安装环节结束。接下来进入最有价值的部分:在没有外网的情况下,怎么把模型灌进去跑起来。
4. 离线运行示例:从服务自启到 GGUF 模型导入
安装脚本只解决二进制和服务注册,真正决定能不能上线的是“模型能不能导入、对话能不能通”。这一章用 qwen2.5 举例,演示完整的离线模型导入流程。
4.1 确认服务与 API 都活着
先看服务状态:
systemctl status ollama --no-pager journalctl -u ollama -n 30 --no-pagerstatus显示服务是否 active,并给出主进程 PID。journalctl看最近 30 行日志,正常会看到 ollama 正在监听 11434 的提示。然后请求 API:
curl -s http://127.0.0.1:11434/api/version | python3 -m json.tool能返回 JSON 说明 HTTP 层正常。这是所有后续操作的前提;连不上就先别灌模型,先解决网络和服务问题。
一个容易被忽略的点:如果服务是开机自启的,但你又手工执行ollama serve,两个实例会抢同一个端口,后者报address already in use。排查时先执行ss -lntp | grep 11434看谁在监听,不要盲目重启 systemd。
4.2 离线导入 GGUF:Modelfile + ollama create
联网阶段准备好 GGUF 文件后,放到目标机上。这里注意:手工执行 ollama 命令时不会自动读取 systemd 的 EnvironmentFile,先手动导出模型路径:
export OLLAMA_MODELS=/data/ollama/models mkdir -p /data/ollama/incoming # 把 qwen2.5-7b-instruct-q4_k_m.gguf 放到 /data/ollama/incoming cd /data/ollama/incoming cat > Modelfile <<'EOF' FROM ./qwen2.5-7b-instruct-q4_k_m.gguf EOF ollama create qwen2.5:7b -f ModelfileFROM ./xxx.gguf让 ollama 用本地这个 GGUF 文件作为权重来源。ollama create会在模型目录里生成 manifest 等元数据,并复制或链接权重文件。创建成功的标志是输出success。
这里有个版本差异要提醒:0.3.12 还没有ollama import这种从 safetensors 直接导入的流程,通用做法是先把模型权重用 llama.cpp 那套工具量化为 GGUF,再走 Modelfile。手上只有 PyTorch 的 safetensors 文件,0.3.12 直接吃不了;先在联网机器完成转换。
创建完成后,跑一次对话测试:
ollama run qwen2.5:7b "你好,请用一句话介绍你自己"首次加载会慢,因为要从磁盘读几 GB 文件;等到出现流式输出,链路就通了。
如果模型创建时提示校验和失败,多半是 GGUF 传输出问题。离线拷贝大文件容易坏,这个亏我吃过。拷贝到现场后先sha256sum xxx.gguf和源文件比对,再执行 create。
4.3 修改模型存储路径与多用户共用
在线装过 ollama、并且已经拉过模型的人,改OLLAMA_MODELS之后会遇到一个经典问题:ollama list里什么都看不到。原因是旧模型还在~/.ollama/models,而新路径是空的。
处理办法是把旧模型目录整体迁过去:
sudo mv ~/.ollama/models /data/ollama/models sudo chown -R ollama:ollama /data/ollama/models如果不想停服务迁移,也可以给新路径做软链:
ln -s /data/ollama/models /root/.ollama/models路径修改还有一个常见场景是 docker 部署 ollama 模型。容器里 ollama 默认写/root/.ollama,离线部署时用 volume 把宿主机目录挂进去,比如-v /data/ollama/models:/root/.ollama。注意权限要和容器用户匹配,否则模型目录创建失败。
交接给团队时,我习惯在 README 里注明“改OLLAMA_MODELS后必须重启 systemd 服务”。环境变量只在服务启动时读取一次,运行中改 env 文件不重启是不生效的,这个很多人栽过。
5. 离线安装避坑排查:依赖缺位、架构不匹配与服务端口玄学
这一章全部来自真实交付和测试里的踩坑记录,每条按“现象 → 原因 → 解决”写,遇到问题可直接对照。
5.1 现象:启动时报 cannot open shared object file,或 GLIBC_XX not found
ollama文件存在,但执行ollama --version报:
error while loading shared libraries: libggml.so: cannot open shared object file或者:
/lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.34' not found原因有两类:第一,只拷了bin/ollama,没有把同包lib/ollama下的动态库一起装进/usr/local/lib/ollama;第二,系统基础库太老,ollama 二进制要求的 glibc 版本高于系统自带。
解决:先补库文件,重新执行第 3.2 节的完整安装逻辑,而不是只拷贝单个文件;再确认系统版本,Ubuntu 20.04 的 glibc 是 2.31,若对不上就换兼容的 ollama 版本,或提高系统基线。不要试图用LD_LIBRARY_PATH硬指一套不存在的库,那是给自己埋雷。
5.2 现象:tar 解压后执行报 Exec format error
在国产化 ARM 平台或树莓派上很常见:
bash: /usr/local/bin/ollama: cannot execute binary file: Exec format error原因只有一个:安装包架构和目标机不一致。amd64 的包放到 aarch64 系统,或者反过来。uname -m的输出和安装包命名里的架构字段是一一对应的,但离线交接时很容易拿错。
解决:按 2.1 的判断重下对应安装包。见过整台机器搬到现场才发现 arm64 包没带的案例,所以脚本里的前置架构校验一定要保留,别为省事跳过。
5.3 现象:systemd 服务 active,但 11434 端口不通
systemctl status ollama显示active (running),可curl http://127.0.0.1:11434/api/version一直超时,ss -lntp | grep 11434也看不到监听记录。
原因通常是环境变量没被 systemd 读到。常见误用是把带export的文件路径写在EnvironmentFile=后面;systemd 解析失败但不报错,ollama 还是默认只监听 localhost。另一种原因是机器有 ufw 或 firewalld,服务起来了但外部访问被拦。
解决:先把EnvironmentFile指向格式正确的/etc/ollama/ollama.env,每行必须是KEY=value;再执行systemctl daemon-reload && systemctl restart ollama。外部访问不通时查防火墙,放行 11434。自己排查时可以直接手工起一次服务,用export OLLAMA_HOST=0.0.0.0:11434后再跑/usr/local/lib/ollama/ollama serve,能快速区分环境变量问题还是 systemd 问题。
5.4 现象:ollama run qwen2.5 报 500 internal server error: llama-server process terminated
这是高频问题。模型 create 成功,但一ollama run就报:
error: 500 internal server error: llama-server process terminated原因按概率排:一是物理内存或显存不够,加载大模型时 OOM,进程直接被杀;二是 GGUF 文件损坏或上下文长度参数不匹配;三是模型正在加载时又来了新请求,进程被提前卸载。
解决:先看内存和系统日志:
free -h dmesg -T | grep -i -E 'oom|killed' | tail如果确认 OOM,就降低加载负载:设OLLAMA_NUM_PARALLEL=1,并减少OLLAMA_MAX_LOADED_MODELS。再校验 GGUF 的 sha256;最后测一次单一请求,避免并发干扰。如果以上都无效,回归检查 0.3.12 与模型的兼容性,换一个量化格式再试。
5.5 现象:导入后 ollama list 有模型,但 run 卡在 loading 或提示锁文件
模型列表里能看到名字,ollama run却长时间停在 loading,或提示:
error: failed to load model: file does not exist原因可能是模型存储目录位于 NFS 或低速机械盘,IO 跟不上;也可能是之前异常退出留下锁文件,新进程一直在等锁。模型加载对 IO 延迟敏感,网络存储在这种场景下表现不稳定,经常给人“玄学”的错觉。
解决:确认模型目录在本地 SSD;如果必须走网络存储,至少保证带宽充足和低延迟。锁文件直接清理后重启服务:
find /data/ollama/models -name '*.lock' -delete systemctl restart ollama这类“卡一半”的问题用journalctl -u ollama -f看实时日志最直接。日志里会写明是 IO 超时还是锁等待,找到关键字再对症下药,比反复重启省时间。
6. 把离线安装脚本做成可复用交付工具:参数化改造与最小验证清单
6.1 用环境变量把脚本改成交付模板
现场交付时不可能每次打开脚本改路径。我的一般做法是在脚本外层包一层配置:
export OLLAMA_PKG_DIR="${OLLAMA_PKG_DIR:-/opt/pkgs}" export OLLAMA_VERSION="${OLLAMA_VERSION:-0.3.12}" export OLLAMA_MODEL_HOME="${OLLAMA_MODEL_HOME:-/data/ollama/models}"这样交付人员只需要source config.sh或预先 export,脚本主体一行都不用动。架构自检继续保留,架构错就直接拒绝执行。脚本末尾的验证步骤也不要省,部署现场最缺的就是明确反馈。
我自己还有一个习惯:重复执行脚本不破坏已有模型目录。create或mv这类破坏性操作放进独立参数里,脚本默认幂等。给团队用的时候,没人想因为重跑脚本把已经灌好的模型清掉。
6.2 最小验证清单:换一台干净机器也能照做
交付时在文档里放这张表,照着勾一遍:
| 检查项 | 命令 | 期望结果 |
|---|---|---|
| 版本 | ollama --version | v0.3.12 |
| 服务状态 | systemctl is-active ollama | active |
| 端口监听 | ss -lntp | 0.0.0.0:11434 |
| API 探测 | curl -s http://127.0.0.1:11434/api/version | JSON 输出 |
| 模型导入 | ollama create qwen2.5:7b -f Modelfile | 输出 success |
| 单轮对话 | ollama run qwen2.5:7b "hi" | 正常返回 |
| 重启存活 | reboot后systemctl is-active ollama | active |
重启存活这一项我很看重。离线环境下交付完就撤,如果机器重启后 ollama 没自动起来,等于给客户留了个雷。验证时直接重启一次,别怕麻烦。
我个人的教训是:离线部署最容易出问题的不在脚本本身,而在分发链路。安装包、GGUF、依赖 deb、sha256 校验文件,只要其中一环出错,现场就多耗半天。所以我现在会把所有文件归档进一个带校验清单的内网目录,文件名里带版本号,每次出发前花五分钟做一次完整演练。希望上面这些脚本、参数和踩坑记录能帮你少走一段弯路,祝你在 ubuntu 上把 ollama-v0.3.12 离线部署一次跑通。
本文还有配套的精品资源,点击获取