给我的 Hermes Agent 安一个温柔的“脸”:Ubuntu 上用 Docker 部署 Open WebUI 全记录
本文最后更新于 69 天前,如有失效请评论区留言。

折腾是程序员的浪漫,踩坑是成长的代价。这篇文章记录了我在 Ubuntu 上把 Open WebUI 和 Hermes Agent 连起来的全过程,包括每一个「为什么这里会报错」的瞬间。

为什么是 Open WebUI

Hermes Agent 很强,但默认主要还是围绕命令行和网关模式使用。

它聪明、灵活、能做事,也很有“代理感”——不像传统聊天模型那样只是回答问题,它更像一个真的会帮你处理任务的小伙伴。只是,命令行终究还是命令行。对于喜欢终端的人来说,那种黑底白字当然很迷人;可有些时候,我还是会想,如果它能有一个更柔和一点、更直观一点、像 ChatGPT 一样的界面就好了。

Open WebUI 则更像是一个“壳”,一个足够体面的交互层。它的好处很直接:

  • 有可视化聊天界面,适合长期使用。

  • 支持多模型/多连接管理。

  • 支持 OpenAI 兼容 API,因此天然适合对接 Hermes API Server。

换句话说,Hermes 负责“脑子”和“执行”,Open WebUI 负责“脸”和“入口”。这套组合搭好以后,整个体验会从“我在调一个强大的 CLI 工具”,变成“我拥有了一个属于自己的智能工作台”。

这套方案的整体结构

在开始操作之前,我们先把整个调用链看清楚。理解结构,后面的坑会少很多。

浏览器

Open WebUI(Docker 容器)

Hermes API Server(Ubuntu 宿主机)

Hermes 内部配置的云端模型 API(或者本地部署的模型)

OpenAI / Anthropic / OpenRouter / 其他兼容模型服务

这里最关键的一点是:
Open WebUI 并不直接调用你的云模型(或者本地模型)。
它调用的是 Hermes 暴露出来的 API Server;再由 Hermes 去调用真正的模型 API。

这也意味着,Open WebUI 里填的那个 API Key,不是你的 OpenAI Key,也不是 Claude Key,而是你给 Hermes API Server 自己设的一把“门钥匙”。

开始之前,你需要准备什么

建议先确认下面几件事:

  • Ubuntu 系统已经可正常联网。

  • Hermes Agent 已经安装完成,并且底层模型已经能跑通。

  • 你有 sudo 权限。

  • 3000、8080、8642 这几个端口里,至少有一部分没有被占用。(ps:注意,不一定是这几个端口,只要是没被占用的端口其实都可以,看自己选择)

  • 你愿意接受:Docker、网络、权限、镜像源,这几个关键词总会有一个来折磨你一下。

如果你还没确认端口是否空闲,可以先检查一下:

ss -tlnp | grep -E "3000|8080|8642|9000"

没有输出,说明端口空闲;有输出,说明被占用了,需要换端口或者停掉对应进程。

查看所有正在监听的端口(了解全局)

ss -tlnp

在 Ubuntu 上安装 Docker

更新包索引并安装依赖

sudo apt update
sudo apt install -y ca-certificates curl gnupg
# 添加 Docker 官方 GPG 密钥
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
  sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg

添加 Docker 官方仓库

echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
  https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

安装 Docker Engine 和 Compose 插件

sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

把当前用户加入 docker 组

sudo usermod -aG docker $USER
newgrp docker

验证:

docker --version
docker compose version

确认 Hermes API Server 可以工作

这一部分是核心。
如果说 Open WebUI 是一个精致的前台,那么 Hermes API Server 就是后厨窗口。前台再漂亮,后厨窗口不开,也什么都送不出来。

Hermes 需要在 ~/.hermes/.env 中启用 API Server。

打开配置文件:

vim ~/.hermes/.env

加入下面几项(端口和api key 可以自己设计, 同时host ip地址也可以自己修改):

API_SERVER_ENABLED=true
API_SERVER_PORT=8642
API_SERVER_HOST=0.0.0.0
API_SERVER_KEY=你的hermes的api-key,自己设置一个,最好复杂一点

这些变量分别是什么意思:

变量作用
API_SERVER_ENABLED是否启用 Hermes 的 API Server
API_SERVER_PORTAPI Server 监听端口,常用 8642
API_SERVER_HOST监听地址,决定谁能访问它
API_SERVER_KEY你自己定义的一把门禁密钥,不是模型厂商的 Key

不是 OpenAI 的 API Key,也不是你接入云模型的 Key。它只是 Hermes 暴露 HTTP 接口时,用来验证“谁可以访问我”的一串密码。

你可以理解成这样:

Open WebUI 带着这串 Key 去敲门

Hermes 看一眼:哦,是你,进来吧

Hermes 再拿着它自己内部配置好的模型 Key 去请求真正的大模型

 

所以这串 Key 是你自己定的,只要 Open WebUI 那边填写同样的值即可。

为什么这里建议用 0.0.0.0,而不是 127.0.0.1

这是后面大部分网络问题的源头,所以我单独拎出来说。

  • 127.0.0.1 表示“只接受本机回环地址请求”。

  • 0.0.0.0 表示“监听所有网络接口”。

如果 Hermes 只监听 127.0.0.1,那么 Ubuntu 宿主机自己 curl localhost:8642 没问题,但 Docker 容器里的 Open WebUI 来访问时,很可能会被拒绝,因为容器并不是宿主机自己的回环接口。

所以,在 Docker 中的 Open WebUI 需要连接宿主机 Hermes 的场景里,最省心的做法就是:

API_SERVER_HOST=0.0.0.0

这是本文后面所有网络排障建议里的首选方案

127.0.0.1 和0.0.0.0 对于open webui的容器的配置要求是不一样的,如果是前者,那么端口映射宿主机必须是8080,后者可以自己定义。

启动 Hermes Gateway

启动命令很简单:

hermes gateway

开一个新终端,执行:

curl http://localhost:8642/health

如果返回:{“status”: “ok”, “platform”: “hermes-agent”}。

就说明 Hermes API Server 已经活了。

这是一个非常重要的检查点。
只要这一步没通,后面别急着配 Open WebUI。

编写 Docker Compose,部署 Open WebUI

新建目录:

mkdir -p ~/open-webui
cd ~/open-webui

创建 docker-compose.yml

services:
  open-webui:
    image: openwebui/open-webui:latest
    container_name: open-webui
    ports:
      - "3000:8080"
    volumes:
      - open-webui:/app/backend/data
    environment:
      # 指向宿主机上的 Hermes API Server
      - OPENAI_API_BASE_URL=http://host.docker.internal:8642/v1
      # 必须与 Hermes 的 API_SERVER_KEY 一致
      - OPENAI_API_KEY=你前面配置的hermes的api key
      # 持久化 Secret Key,防止容器重建后被登出
      - WEBUI_SECRET_KEY=your-webui-secret   # 用 openssl rand -hex 32 生成
    # Linux 无 Docker Desktop 时必须加这行,让容器能解析 host.docker.internal
    extra_hosts:
      - "host.docker.internal:host-gateway"
    restart: always

volumes:
  open-webui:

这里面有几个地方值得单独解释。

ports: “3000:8080” 是什么意思: Docker 里的端口映射格式是:宿主机端口:容器内部端口。

也就是说:

  • 左边 3000 是你在浏览器里访问的端口,可以改。

  • 右边 8080 是 Open WebUI 容器内部监听的端口,通常不要改。

比如你想改成 8000:

ports:
– “8000:8080”

那么浏览器就访问 http://localhost:8000

WEBUI_SECRET_KEY:每次登录 Open WebUI 后,系统会生成一个登录令牌(JWT),让你保持登录状态。WEBUI_SECRET_KEY 就是用来签名和验证这个令牌的”底层钥匙”。在终端输入:

openssl rand -hex 32

把得到的字符串填进去就好了。

如果在hermes 里面填写的地址是127.0.0.1 ,那么 docker-compose.yml 可以改为:

services:
  open-webui:
    image: ghcr.io/open-webui/open-webui:main
    container_name: open-webui
    network_mode: host          # 共享宿主机网络
    volumes:
      - open-webui:/app/backend/data
    environment:
      - OPENAI_API_BASE_URL=http://localhost:8642/v1   # 直接用 localhost
      - OPENAI_API_KEY=你前面配置的hermes的api key
      - WEBUI_SECRET_KEY=your-webui-secret
    restart: always

volumes:
  open-webui:

启动 Open WebUI

docker compose up -d

查看日志:

docker compose logs -f open-webui

如果日志正常滚动,并最终启动完成(需要一段时间),浏览器访问: http://localhost:3000。端口改为自己设定的那个。

首次注册的用户会成为管理员。进入后台后,你就可以在连接管理中看到对应的 OpenAI 兼容连接入口。

在 Open WebUI 里配置 Hermes 连接

如果环境变量已经正确注入,有时它会自动识别;但更稳妥的做法,还是在后台手动检查一遍。

进入:模型,选择连接,到设置部分。在外部连接里面,有 OpenAI 接口 选项,可以选择添加(一般已经自动添加好了)

填写:

  • URL:http://host.docker.internal:8642/v1

  • API Key:自定义的api key

如果验证通过,模型列表里通常会出现 Hermes 对应的模型入口或 agent 标识。

把 Hermes 做成 systemd 服务

先找到真实用户名和 hermes 路径:

whoami
which hermes

用 systemd 管理 Hermes gateway,避免手动启动:

sudo vim /etc/systemd/system/hermes.service

假设用户名分别是  name和 path,填入:

[Unit]
Description=Hermes Agent Gateway
After=network.target

[Service]
Type=simple
User=name  # 改为你的用户名
ExecStart=path gateway  # 改为你的hermes路径
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

在终端输入:

sudo systemctl daemon-reload
sudo systemctl enable hermes
sudo systemctl restart hermes
sudo systemctl status hermes

这样 Hermes 会随系统自动启动,Open WebUI Docker 容器也设置了 restart: always,两者重启后会自动恢复。

性能监控

# 监控容器资源使用
docker stats

# 查看特定容器日志
docker logs -f openwebui
docker logs -f hermes-agent

# 检查系统资源
top
htop

若出现问题:Open WebUI 里“验证连接”提示网络问题,模型列表为空

在 Open WebUI 后台连接配置里:

  • URL 填了 http://host.docker.internal:8642/v1

  • Key 也填对了

  • 但点击验证时提示网络问题

  • 或者验证过不去

  • 或者模型列表一直是空的

 

检查一:宿主机上的 Hermes 是否活着

curl http://localhost:8642/health

如果返回:{“status”: “ok”, “platform”: “hermes-agent”}说明 Hermes 没问题。

检查二:从容器里能不能访问宿主机 Hermes

docker exec open-webui curl -s http://host.docker.internal:8642/health

如果这里没输出,或者访问失败,那么问题就不在 Open WebUI 表单,而在 Docker 容器到宿主机 Hermes 的网络路径 上。

这个问题的根因:容器和宿主机不是一个 localhost。

  • 在宿主机里,localhost 指的是 Ubuntu 自己。

  • 在容器里,localhost 指的是容器自己。

所以如果 Hermes 绑定在:API_SERVER_HOST=127.0.0.1

那就等于说:
“我只接受我自己回环地址的连接。”

宿主机自己访问当然可以,但 Docker 容器来的请求就不一定进得来。

这个网络问题的三种解决方案

方案一:把 Hermes 监听地址改成 0.0.0.0(最推荐)

把:API_SERVER_HOST=127.0.0.1

改成:API_SERVER_HOST=0.0.0.0

然后重启:

hermes gateway

Open WebUI 这边保持:http://host.docker.internal:8642/v1

不变即可。

优点:

  • 逻辑最清楚。

  • 不需要改 Open WebUI 访问方式。

  • 对未来扩展也更友好。

缺点:

  • 暴露面比 127.0.0.1 大,所以一定要设置强一点的 API_SERVER_KEY

  • 如果你服务器有公网暴露,还需要配防火墙策略。

方案二:改用 Docker 网桥 IP 访问宿主机

先查看 Docker 网桥地址:

ip route | grep docker0

很多机器会显示:

172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1

然后把 Open WebUI 中配置的 URL 改成:

http://172.17.0.1:8642/v1

不用 host.docker.internal 这个别名,直接走 Docker 默认桥接网络的宿主机地址。

优点:

  • 简单直接。

  • 某些 host.docker.internal 解析不稳定的环境下很好用。

缺点:

  • IP 依赖环境,不够通用。

  • 如果 Docker 网桥被改过,地址可能不是 172.17.0.1

  • 如果 Hermes 还是绑定 127.0.0.1,这个方案也可能失败。

方案三:让 Open WebUI 直接使用 host 网络模式

修改 Compose:

services:
  open-webui:
    image: ghcr.io/open-webui/open-webui:main
    container_name: open-webui
    network_mode: host
    volumes:
      - open-webui:/app/backend/data
    environment:
      - OPENAI_API_BASE_URL=http://localhost:8642/v1
      - OPENAI_API_KEY=自定义的hermes api key
      - WEBUI_SECRET_KEY=自定义的webui-secret
    restart: always

volumes:
  open-webui:

注意:

  • 用了 network_mode: host 后,要删掉 ports:

  • 一般也不再需要 extra_hosts:

  • 此时 Open WebUI 自己会直接占用宿主机端口,默认访问通常是 http://localhost:8080

原理:既然容器网络绕来绕去总出问题,那就不隔离了,直接让容器共享宿主机网络栈。

优点

  • 最简单粗暴,成功率很高。

  • 完全避开 bridge 网络和 hostname 解析问题。

缺点

  • 容器网络隔离减弱。

  • 端口冲突更直接。

  • 对初学者来说,后面排查“哪个服务占了哪个端口”会稍微乱一点。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇