背景:
trim.hermes系统账号默认不在docker组、摸不到/var/run/docker.sock, 这是好事(防止它碰你其他所有 docker 服务)。但坏处是它连自己该管的三个本地模型 容器(qwen36 / qwen3-2507 / glm47)都启停不了,尤其是已停止的容器,靠ps aux完全看不到。本教程通过"白名单脚本 + 精确 sudoers 授权",只开一条窄门: Hermes 能且只能启停这三个指定容器,碰不了其他任何 docker 资源。
涉及到的容器名(以本机实际为准)
llama-qwen3-2507
llama-glm47
llama-qwen36
如果以后新增/更换模型容器,只需要改脚本里
ALLOWED_CONTAINERS这一个数组,其他步骤不用动。
第一步:创建白名单脚本
SSH 登录 fnOS 后,执行:
cat > /usr/local/bin/manage-model-containers.sh << 'EOF'
#!/bin/bash
set -euo pipefail
ALLOWED_CONTAINERS=("llama-qwen3-2507" "llama-glm47" "llama-qwen36")
ACTION="$1"
CONTAINER="${2:-}"
in_whitelist() {
local target="$1"
for c in "${ALLOWED_CONTAINERS[@]}"; do
[[ "$target" == "$c" ]] && return 0
done
return 1
}
case "$ACTION" in
start)
in_whitelist "$CONTAINER" || { echo "拒绝:容器 '$CONTAINER' 不在白名单内" >&2; exit 1; }
docker start "$CONTAINER"
;;
stop)
in_whitelist "$CONTAINER" || { echo "拒绝:容器 '$CONTAINER' 不在白名单内" >&2; exit 1; }
docker stop "$CONTAINER"
;;
switch)
in_whitelist "$CONTAINER" || { echo "拒绝:容器 '$CONTAINER' 不在白名单内" >&2; exit 1; }
echo "切换到 $CONTAINER,先停掉其他模型容器..."
for c in "${ALLOWED_CONTAINERS[@]}"; do
if [[ "$c" != "$CONTAINER" ]]; then
docker stop "$c" 2>/dev/null || true
fi
done
docker start "$CONTAINER"
echo "已切换到 $CONTAINER"
;;
status)
for c in "${ALLOWED_CONTAINERS[@]}"; do
state=$(docker inspect -f '{{.State.Status}}' "$c" 2>/dev/null || echo "not found")
echo "$c: $state"
done
;;
*)
echo "拒绝:只允许 start/stop/switch/status,不支持 '$ACTION'" >&2
exit 1
;;
esac
EOF
这个脚本支持 4 个动作:
无论哪个动作,只要容器名不在白名单数组里,一律直接拒绝,不会执行任何 docker 命令。
第二步:设置脚本权限
chmod 755 /usr/local/bin/manage-model-containers.sh
chown root:root /usr/local/bin/manage-model-containers.sh
目的:只有 root 能修改这个脚本内容,trim.hermes 账号只能"调用"它,不能"篡改"它(比如往白名单里偷偷加别的容器名)。
第三步:配置 sudoers,只放行这一个脚本
echo 'trim.hermes ALL=(root) NOPASSWD: /usr/local/bin/manage-model-containers.sh' | sudo tee /etc/sudoers.d/hermes-model-containers
chmod 440 /etc/sudoers.d/hermes-model-containers
关键点:
用独立文件
/etc/sudoers.d/hermes-model-containers,不要直接改/etc/sudoers主文件——万一写错语法,只影响这一个文件,不会把整个 sudo 体系搞坏NOPASSWD只对这一个固定路径的脚本生效,trim.hermes依然不能执行任何其他需要 sudo 的命令(包括原始的docker命令本身)
验证语法是否正确:
visudo -c
看到类似 /etc/sudoers: parsed OK 的提示,说明没写错。
第四步:手动测试
先用 trim.hermes 身份模拟 Hermes 的真实调用效果:
# 测试正常启停(应该成功)
sudo -u trim.hermes sudo /usr/local/bin/manage-model-containers.sh stop llama-qwen36
sudo -u trim.hermes sudo /usr/local/bin/manage-model-containers.sh start llama-qwen36
# 测试一键切换(应该自动停掉另外两个,启动目标)
sudo -u trim.hermes sudo /usr/local/bin/manage-model-containers.sh switch llama-qwen3-2507
# 测试查看状态
sudo -u trim.hermes sudo /usr/local/bin/manage-model-containers.sh status
# 测试白名单拦截(关键安全测试,这条必须被拒绝!)
sudo -u trim.hermes sudo /usr/local/bin/manage-model-containers.sh stop frigate
最后这条"停 frigate"的测试非常重要,正确结果应该是:
拒绝:容器 'frigate' 不在白名单内
并且 Frigate 监控容器不会真的被停掉。如果这条测试通过(即容器没被停),说明权限边界生效了,可以放心让 Hermes 使用。
第五步:告诉 Hermes 怎么用
回到网页 Hermes 对话框,直接用自然语言告诉它(建议写进 SOUL.md 或作为长期记忆,一次说清楚以后不用重复交代):
以后我让你切换本地模型时,请执行:
sudo /usr/local/bin/manage-model-containers.sh switch <容器名>容器名只能是以下三者之一:
llama-qwen3-2507、llama-glm47、llama-qwen36想查看当前哪个模型在跑,执行:
sudo /usr/local/bin/manage-model-containers.sh status除了这三个模型容器的启停/切换/查状态,不要对任何其他 docker 容器执行任何 docker 相关命令。
效果总结
核心原则:安全边界建立在系统权限层面(脚本白名单 + sudoers 精确授权),不依赖 Hermes"自觉遵守指示"——即使指示被绕过、被遗忘、或被恶意注入,权限系统本身也会拦住。
以后新增/更换模型容器怎么办
只需要改一处:
# 用文本编辑器打开脚本
nano /usr/local/bin/manage-model-containers.sh
# 找到这一行,加上新容器名
ALLOWED_CONTAINERS=("llama-qwen3-2507" "llama-glm47" "llama-qwen36" "新容器名")
保存后不需要改 sudoers 配置,脚本本身的改动会立即生效。
评论区