本文图文并茂,记录安装 Ollama过程,下载大模型,启动ollama大模型服务,然后通过nginx代理外部请求访问,实现一个前端问答效果
准备工作
- 一台服务器,操作系统 Ubuntu,版本大于等于 20.04,笔者的是 Ubuntu 22.04 64 bit
- 当然了 有域名最好
- 一个图形可视化化链接服务器软件,笔者推荐 winscp
- 一架梯子,笔者用的是,clash小猫
效果图

效果演示地址
请点击一下:ashuai.site/reactExampl...
第一步,试试ollama官方提供的命令
ollama官方:ollama.com/download/li...
第二步,网络不行,ollama下载不下来

文件太大了,有一个G多
第三步,到github上找对应ollama安装包资源,下载,再上传到乌班图服务器上
地址如下:github.com/ollama/olla...
然后,在浏览器中下载
下载完毕以后,在用winscp将其移动到服务器上
ollama安装包上传完毕
第四步,解压对应的这个文件
1. 解压 .tgz
压缩包并统一路径管理
当前我们是已在 /var/selfDownload
目录(通过 ls
能看到 ollama-linux-amd64.tgz
),直接执行解压命令即可。.tgz
是 .tar.gz
的简写,需用 tar
命令解压:
bash
tar -zxvf ollama-linux-amd64.tgz
-
命令说明:
z
:处理 gzip 压缩格式(对应.gz
/.tgz
);x
:执行 "解压" 操作;v
:显示解压过程(可选,方便查看文件是否正常解压);f
:指定要解压的文件名(必须放在命令最后,这里是ollama-linux-amd64.tgz
)。
解压成功 得到两个新的文件夹

在winscp中也能直观看到
把对应的文件移动走到对应位置,统一管理,注意下图的路径

然后跑起来服务
2. 安装大模型,使用curl命令进行对话

ollama服务 默认运行的端口是11434端口
然后,使用curl命令,在服务器内部的命令行中,发送给ollama发请求,调用通义千文大模型试试
js
curl http://localhost:11434/api/generate -d '{
"model": "qwen2.5:0.5b",
"prompt": "你是什么模型",
"stream": false
}'

- 我们发现跑通了,至此,乌班图服务器上,安装Ollama就全部完成了
- 但是,单单只有Ollama的上安装的模型服务还不太够,效果不明显
- 接下,我们要让服务器上的大模型服务能够在外部调用
3. nginx代理外部请求到ollama
- 笔者服务器上安装nginx,以便于代理外部的请求,而后把外部请求转发到服务器上的ollama的大模型服务
- 以/ollama开头的请求,转到ollama这里使用11434端口上
bash
# ollama服务
location /ollama/ {
# 允许所有来源访问
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization' always;
add_header 'Access-Control-Max-Age' 1728000 always;
# 代理到 Ollama
proxy_pass http://localhost:11434/;
# 完全清理所有头,只保留必要的
proxy_pass_request_headers off;
# 手动设置最基本的头信息 ollama的响应头过于复杂可能导致403报错
proxy_set_header Host localhost;
proxy_set_header Content-Type application/json;
proxy_set_header Content-Length $content_length;
proxy_set_header Connection close;
}
第五步,在外部访问请求服务器上的ollama大模型接口
写一个react页面,直接发请求即可
效果图
交互效果

接口请求返回
react代码
即分为对话区和输入区,前端代码倒是很简单
js
import { useState } from 'react'
import axios from 'axios'
import { Input } from 'antd'
import styles from './Ollama.module.css'
export default function Ollama() {
const [messages, setMessages] = useState([]) // 存储对话数据
const [inputValue, setInputValue] = useState('') // 输入框内容
const [isLoading, setIsLoading] = useState(false) // 加载状态
// 发请求
const sendApiRequest = () => {
if (!inputValue.trim()) return // 如果输入为空,不发送请求
const userMessage = inputValue.trim()
setIsLoading(true)
// 添加用户消息到对话数据
setMessages(prev => [...prev, { type: 'user', content: userMessage }])
setInputValue('') // 清空输入框
axios.post('/ollama/api/generate', {
model: "qwen2.5:0.5b",
prompt: userMessage,
stream: false
}).then((response) => {
const { response: aiResponse } = response.data
// 添加AI回复到对话数据
setMessages(prev => [...prev, { type: 'ai', content: aiResponse }])
setIsLoading(false)
}).catch((error) => {
setMessages(prev => [...prev, { type: 'error', content: JSON.stringify(error) }])
setIsLoading(false)
})
}
// 处理输入框按键事件
const handleKeyPress = (e) => {
if (e.key === 'Enter' && !isLoading) {
sendApiRequest()
}
}
return (
<div>
<h3>Ollama调用大模型</h3>
{/* 对话区 */}
<div className={styles.chatContainer}>
<div className={styles.messages}>
{messages.length === 0 ? (
<div className={styles.emptyMessage}>
暂无数据,请开始与AI对话吧!🤔🤔🤔
</div>
) : (
messages.map((message, index) => (
<div
key={index}
className={`${styles.message} ${styles[message.type]}`}
>
<div className={styles.messageContent}>
{message.content}
</div>
</div>
))
)}
</div>
</div>
{/* 输入区 */}
<Input
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
onPressEnter={handleKeyPress}
placeholder="输入问题,回车发送"
disabled={isLoading}
/>
</div>
)
}
样式css代码
css
.chatContainer {
border: 1px solid #dee2e6;
border-radius: 8px;
height: 400px;
margin-bottom: 20px;
overflow-y: auto;
background-color: #fafafa;
}
.messages {
padding: 15px;
}
.message {
margin-bottom: 15px;
display: flex;
}
/* 用户输入的在右侧,ai回复的在左侧,报错居中 */
.user { justify-content: flex-end; }
.ai { justify-content: flex-start; }
.error { justify-content: center; }
.messageContent {
max-width: 70%;
padding: 10px 15px;
word-wrap: break-word;
}
.user .messageContent {
background-color: #1890ff;
color: white;
border-radius: 18px 18px 4px 18px;
}
.ai .messageContent {
background-color: #f0f0f0;
color: #333;
border-radius: 18px 18px 18px 4px;
}
.error .messageContent {
background-color: #fff2f0;
color: #ff4d4f;
border: 1px solid #ffccc7;
border-radius: 8px;
}
.emptyMessage {
text-align: center;
color: #999;
font-style: italic;
padding: 40px;
}
完整github代码地址
创造不易,感谢关注、点赞、评论支持 🙏🙏🙏
A good memory is better than a bad pen. Record it down...