vault backup: 2026-10-09 21:27:26

This commit is contained in:
2026-10-09 21:27:26 +03:00
parent f09b1ef1c6
commit ea9b7bacd0
12 changed files with 820 additions and 29 deletions
@@ -0,0 +1,6 @@
Описание на Habr:
AI провайдер: polza.ai
API: `pza_emOW7E0WsoXli4c85T5t_j2q1_Nk2dIT`
+452
View File
@@ -0,0 +1,452 @@
# Гайд: Установка Hermes Agent на LXC Debian и подключение с Windows Desktop
> Схема: Debian LXC (сервер Hermes) ↔ Windows ПК (Hermes Desktop)
---
## 1. Подготовка LXC контейнера
### 1.1. Создать LXC (если ещё нет)
На **хосте PVE**:
```bash
pveam update
pveam available | grep debian
pveam download local debian-12-standard_12.7-1_amd64.tar.zst
pct create 300 local:vztmpl/debian-12-standard_12.7-1_amd64.tar.zst \
--hostname hermes-server \
--storage local-lvm \
--memory 4096 \
--cores 4 \
--net0 name=eth0,bridge=vmbr0,ip=dhcp \
--password \
--start
pct enter 300
```
### 1.2. Настроить внутри контейнера
```bash
# Стандартное обновление
apt update && apt upgrade -y
# Зависимости Hermes
apt install -y git curl build-essential python3 python3-pip python3-venv
# uv (менеджер Python для Hermes)
curl -fsSL https://astral.sh/uv/install.sh | bash
source ~/.bashrc
```
---
## 2. Установка Hermes Agent из GitHub
### 2.1. Ручной clone + установка (рекомендуется для сервера)
```bash
cd /opt
git clone --recurse-submodules https://github.com/NousResearch/hermes-agent.git
cd hermes-agent
# Создать venv через uv
uv venv venv --python 3.11
export VIRTUAL_ENV="$(pwd)/venv"
# Установить со всеми extras
uv pip install -e ".[all,dev]"
# Опционально: browser tools
npm install
```
> **Альтернатива (проще, но через инсталлятор):**
> ```bash
> curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash
> ```
> После этого репозиторий лежит в `~/.hermes/hermes-agent/`. Этот вариант тоже устанавливает `hermes` команду.
### 2.2. Создать конфигурацию
```bash
# Создать структуру директорий
mkdir -p ~/.hermes/{cron,sessions,logs,skills}
# Если ставили вручную — симлинк для `hermes` команды
mkdir -p ~/.local/bin
ln -sf /opt/hermes-agent/venv/bin/hermes ~/.local/bin/hermes
export PATH="$HOME/.local/bin:$PATH"
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
# Базовая конфигурация
cp /opt/hermes-agent/cli-config.yaml.example ~/.hermes/config.yaml
# API-ключи
cat >> ~/.hermes/.env <<'EOF'
# Минимум — один LLM провайдер:
OPENROUTER_API_KEY=sk-or-v1-xxxxxxxxxxxx
# Опционально:
# ANTHROPIC_API_KEY=sk-ant-...
# OPENAI_API_KEY=sk-...
EOF
chmod 600 ~/.hermes/.env
```
### 2.3. Проверка установки
```bash
hermes doctor
hermes chat -q "Привет, проверка связи"
# Если работает — всё ок, выйти через /exit
```
---
## 3. Запуск Hermes как сервера (hermes serve)
### 3.1. Настройка аутентификации
В `~/.hermes/.env` добавить:
```bash
cat >> ~/.hermes/.env <<'EOF'
# Учётные данные для подключения Desktop
HERMES_DASHBOARD_BASIC_AUTH_USERNAME=admin
HERMES_DASHBOARD_BASIC_AUTH_PASSWORD=придумайте-надёжный-пароль
# Стабильный ключ — чтобы сессии сохранялись после перезапуска
HERMES_DASHBOARD_BASIC_AUTH_SECRET=$(openssl rand -base64 32)
EOF
chmod 600 ~/.hermes/.env
```
### 3.2. Запуск вручную (проверка)
```bash
hermes serve --host 0.0.0.0 --port 9119
```
Должно запуститься без ошибок. Проверить:
```bash
# Из контейнера
curl -s http://127.0.0.1:9119/api/status
# С другого узла в сети (PVE, Windows)
curl -s http://<IP LXC>:9119/api/status
```
> **Примечание:** `hermes serve` — это головной backend, к которому подключается Desktop. Если нужны также Telegram/Discord — их gateway запускается отдельно (`hermes gateway start`).
### 3.3. systemd-сервис для автозапуска
```bash
cat > /etc/systemd/system/hermes-serve.service <<'EOF'
[Unit]
Description=Hermes Agent Serve Backend
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=root
Group=root
WorkingDirectory=/root
ExecStart=/root/.local/bin/hermes serve --host 0.0.0.0 --port 9119
Restart=always
RestartSec=10
Environment=HERMES_HOME=/root/.hermes
# Timeout для graceful shutdown
TimeoutStopSec=30
[Install]
WantedBy=multi-user.target
EOF
```
> Если ставили через официальный инсталлятор, путь к `hermes` может быть другим. Проверить:
> ```bash
> which hermes
> # или
> find / -name hermes -type f 2>/dev/null
> ```
Активация:
```bash
systemctl daemon-reload
systemctl enable hermes-serve
systemctl start hermes-serve
systemctl status hermes-serve
```
Логи:
```bash
journalctl -u hermes-serve -f
```
### 3.4. Запуск Dashboard (веб-интерфейс)
Если нужен ещё и веб-интерфейс для администрирования, запустить отдельно:
```bash
hermes dashboard --host 0.0.0.0 --port 9120 --no-open
# Доступно: http://<IP LXC>:9120
```
Тоже можно под systemd (аналогично `hermes-serve`, только ExecStart поменять).
---
## 4. Подключение NFS-шары OMV к LXC
Чтобы конфигурация, сессии и навыки сохранялись даже после пересоздания контейнера — хранить `~/.hermes/` на NFS.
### 4.1. Монтирование NFS в LXC
Внутри **LXC-контейнера**:
```bash
# Установить NFS-клиент
apt install -y nfs-common
# Создать точку монтирования
mkdir -p /mnt/hermes-data
# Проверить монтирование
mount -t nfs 192.168.1.73:/export/hermes-data /mnt/hermes-data \
-o rw,vers=4,hard,timeo=600,no_root_squash
ls -la /mnt/hermes-data/
```
### 4.2. Перенос данных на NFS
```bash
# Если в ~/.hermes/ уже есть данные
cp -a ~/.hermes/* /mnt/hermes-data/
# Или если NFS шара пустая — просто создать структуру
mkdir -p /mnt/hermes-data/{cron,sessions,logs,skills}
```
### 4.3. Переместить HERMES_HOME на NFS
```bash
# Переместить домашнюю директорию Hermes
mv ~/.hermes ~/.hermes.bak
ln -s /mnt/hermes-data ~/.hermes
# Проверить
ls -la ~/.hermes
hermes doctor
```
**Или** без симлинка — через переменную окружения:
```bash
echo 'HERMES_HOME=/mnt/hermes-data' >> ~/.bashrc
source ~/.bashrc
# + обновить systemd unit
# Environment=HERMES_HOME=/mnt/hermes-data
```
### 4.4. Автомонтирование NFS (fstab)
В `/etc/fstab` LXC:
```bash
192.168.1.73:/export/hermes-data /mnt/hermes-data nfs4 rw,hard,timeo=600,rsize=1048576,wsize=1048576,_netdev 0 0
```
**Внимание:** если NFS не смонтируется — `hermes serve` не запустится. Можно сделать `After=mnt-hermes-data.mount` в systemd unit, но проще сделать startup script, который ждёт mount.
---
## 5. Установка Hermes Desktop на Windows
### 5.1. Скачать и установить
**Способ 1 (рекомендуется):**
1. Скачать установщик с [hermes-agent.nousresearch.com/desktop](https://hermes-agent.nousresearch.com/desktop) (MSIX/App Installer)
2. Запустить, пройти установку
**Способ 2 (через PowerShell):**
```powershell
iex (irm https://hermes-agent.nousresearch.com/install.ps1)
```
### 5.2. Первый запуск
1. Запустить Hermes Desktop
2. Пропустить Onboarding / Choose provider later
3. Открыть **Settings → Gateways**
### 5.3. Подключение к серверу в LXC
**Settings → Gateways → Connection mode → Remote gateway**
| Поле | Значение |
|------|---------|
| Remote URL | `http://<IP-LXC>:9119` (например `http://192.168.1.200:9119`) |
| Имя соединения | `hermes-server` (произвольно) |
Нажать **Connect / Sign in** → ввести:
- **Username:** `admin` (из `HERMES_DASHBOARD_BASIC_AUTH_USERNAME`)
- **Password:** (из `HERMES_DASHBOARD_BASIC_AUTH_PASSWORD`)
После успешного входа — Desktop подключён к удалённому серверу. Профили, сессии, скиллы — всё с сервера.
> **Проблема с HTTP:** если сервер без HTTPS, Desktop может ругаться на небезопасное соединение. Решения:
> - Обернуть через Tailscale (см. раздел 7)
> - Использовать SSH-туннель (раздел 6)
> - Включить разрешение HTTP в настройках Windows Desktop (Settings → Advanced → Allow insecure connections)
---
## 6. SSH-туннель (альтернатива прямому HTTP)
Если не хотите открывать порт 9119 наружу или HTTPS нет:
### На Windows (PowerShell или WSL2)
```bash
# SSH-туннель: локальный порт 9119 → LXC:9119
ssh -L 9119:localhost:9119 root@<IP-LXC> -N
```
После этого в Desktop указать `http://127.0.0.1:9119`. Трафик идёт через SSH.
### Автоматизация через systemd на Windows (WSL)
Создать скрипт `/etc/systemd/system/hermes-tunnel.service`:
```ini
[Unit]
Description=SSH tunnel to Hermes LXC
After=network.target
[Service]
ExecStart=/usr/bin/ssh -L 9119:localhost:9119 root@<IP-LXC> -N -o ExitOnForwardFailure=yes
Restart=always
RestartSec=10
User=<ваш-user>
```
---
## 7. Tailscale вариант (рекомендуется)
Если Tailscale уже настроен — просто используйте Tailscale IP вместо локального.
```bash
# Установить Tailscale на LXC
curl -fsSL https://tailscale.com/install.sh | sh
tailscale up
# На Windows — установить Tailscale, войти в ту же сеть
```
В Desktop указать: `http://<Tailscale-IP-LXC>:9119`
Tailscale даёт:
- **Автоматический HTTPS** (магически, через `https://<machine>.ts.net`)
- **Zero-trust сеть** — порт не нужно открывать в локальной сети
- **Постоянные IP**, даже если LXC пересоздаётся
> После Tailscale можно использовать HTTPS: `https://<machine>.ts.net:9119` — Desktop не будет ругаться на небезопасное соединение.
---
## 8. Полная проверка
### 8.1. На LXC
```bash
# Сервер работает?
systemctl status hermes-serve
# Порт открыт?
ss -tlnp | grep 9119
# NFS смонтирована?
df -h | grep nfs
ls -la ~/.hermes/
```
### 8.2. С Windows
```bash
# Проверить TCP-доступность
Test-NetConnection -ComputerName <IP-LXC> -Port 9119
# Или через curl (если есть)
curl http://<IP-LXC>:9119/api/status
```
### 8.3. В Desktop
1. Открыть чат — должна появиться сессия на сервере
2. Отправить сообщение — должен прийти ответ от агента
3. Файлы перетаскиваются через Desktop → загружаются на LXC
4. Скиллы, настройки, сессии — все на сервере
---
## 9. Типовые проблемы и решения
| Проблема | Причина | Решение |
|----------|---------|---------|
| `hermes serve` не запускается | Нет API-ключа в `.env` | Проверить `~/.hermes/.env`, добавить `OPENROUTER_API_KEY` |
| Desktop: "Connection refused" | Порт 9119 не открыт / LXC не доступен | `systemctl status hermes-serve`, проверить firewall на PVE |
| Desktop: "Unauthorized" | Неверный логин/пароль | Проверить `HERMES_DASHBOARD_BASIC_AUTH_USERNAME/PASSWORD` в `.env` |
| После перезапуска LXC всё сбросилось | `HERMES_HOME` на локальной FS | Переместить на NFS (раздел 4), проверить fstab |
| Desktop: "Cannot connect to insecure backend" | HTTP без HTTPS | Использовать Tailscale HTTPS или `Allow insecure connections` |
| LXC не может смонтировать NFS | OMV NFS шара без `no_root_squash` | Включить `no_root_squash` в настройках NFS на OMV |
| `hermes doctor` ругается на зависимости | Часть пакетов не установлена | `apt install -y build-essential git curl python3 python3-pip` |
| Медленная загрузка файлов через Desktop | Rsize/wsize малые | В fstab на LXC: `rsize=1048576,wsize=1048576` |
| Desktop обновляется, а сервер нет | Разные версии | `hermes update` на LXC, потом перезапустить `systemctl restart hermes-serve` |
---
## 10. Структура сервера (итог)
```
LXC Debian (192.168.1.xxx)
├── /opt/hermes-agent/ — исходники (git clone)
├── /opt/hermes-agent/venv/ — виртуальное окружение Python
├── /root/.local/bin/hermes — симлинк на исполняемый файл
├── ~/.hermes/ → /mnt/hermes-data/ — конфиг, сессии, скиллы на NFS
├── /etc/systemd/system/hermes-serve.service — сервис автозапуска
└── systemd: hermes-serve (порт 9119)
OMV (192.168.1.73)
├── NFS export: /export/hermes-data → LXC /mnt/hermes-data
Windows ПК
└── Hermes Desktop → remote gateway: http://<LXC_IP>:9119
```
## 11. Команды для быстрого старта (шпаргалка)
```bash
# LXC — установка
git clone --recurse-submodules https://github.com/NousResearch/hermes-agent.git /opt/hermes-agent
cd /opt/hermes-agent && uv venv venv --python 3.11
export VIRTUAL_ENV="$(pwd)/venv" && uv pip install -e ".[all,dev]"
ln -sf /opt/hermes-agent/venv/bin/hermes ~/.local/bin/hermes
# LXC — конфиг
echo 'OPENROUTER_API_KEY=sk-or-v1-...' >> ~/.hermes/.env
echo 'HERMES_DASHBOARD_BASIC_AUTH_USERNAME=admin' >> ~/.hermes/.env
echo 'HERMES_DASHBOARD_BASIC_AUTH_PASSWORD=my-password' >> ~/.hermes/.env
chmod 600 ~/.hermes/.env
# LXC — запуск сервера
hermes serve --host 0.0.0.0 --port 9119
# Desktop (Windows) — Settings → Gateways → Remote → http://<LXC_IP>:9119
```
+76
View File
@@ -0,0 +1,76 @@
# Подключение Hermes Desktop (Windows) к серверу
Общая схема:
[Windows] --LAN--> [Сервер 192.168.1.44:9119]
Hermes Desktop Hermes Dashboard
(тот же агент, что в этом сеансе)
---
## 1. Что уже сделано на сервере
- Dashboard запущен на `0.0.0.0:9119` (слушает все интерфейсы)
- Basic auth включена: логин `admin`, пароль `agent`
- Dashboard **автоматически стартует при загрузке сервера** (systemd-сервис `hermes-dashboard.service`)
- При падении перезапускается автоматически через 10 секунд
Проверить статус можно с сервера:
curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:9119/api/health
# → 200
systemctl status hermes-dashboard.service
# → active (running)
---
## 2. Подключение из Hermes Desktop (Windows)
1. Открой Hermes Desktop на Windows
2. Нажми `Ctrl+K` (Cmd+K на Mac) — откроется палитра команд
3. Набери **Remote Gateway** и выбери `Connect to Remote Gateway...` (или найди в Settings → Gateway → Remote)
4. Введи данные:
- **URL сервера:** `http://192.168.1.44:9119`
- **Логин:** `admin`
- **Пароль:** `agent`
5. После подключения в левой панели появится серверный профиль — можно выбирать его и общаться как обычно.
> Если Windows подключён через VPN или из другой подсети — IP может отличаться.
> Узнать текущий IP сервера: `hostname -I`
---
## 3. Управление сервисом (на сервере)
Сервис уже установлен и активен. Команды управления:
| Действие | Команда |
|----------|---------|
| Статус | `systemctl status hermes-dashboard.service` |
| Стоп | `systemctl stop hermes-dashboard.service` |
| Старт | `systemctl start hermes-dashboard.service` |
| Рестарт | `systemctl restart hermes-dashboard.service` |
| Отключить автозапуск | `systemctl disable hermes-dashboard.service` |
| Логи (свежие) | `journalctl -u hermes-dashboard.service -n 50` |
| Логи (хвост) | `journalctl -u hermes-dashboard.service -f` |
---
## 4. Безопасность
- Доступ к dashboard возможен из **любого устройства в той же LAN** (подсеть 192.168.1.0/24), кто знает логин/пароль
- За пределами LAN dashboard **недоступен** — сервер не торчит в интернет
- Пароль хранится в `/root/.hermes/config.yaml` — не свети этот файл
- Для доступа из интернета — облачный relay (Nous Portal) или VPN/SSH-туннель
---
## 5. Что если не работает
| Симптом | Решение |
|---------|---------|
| Desktop пишет "Connection refused" | Сервис не запущен → `systemctl start hermes-dashboard.service` |
| 401 Unauthorized | Неправильный логин или пароль — проверь в `config.yaml` секцию `basic_auth` |
| Desktop видит сервер, но не отвечает | `hermes doctor` на сервере — проверить модель и соединение |
| Нет соединения после ребута сервера | Сервис включён в автозапуск, проверь статус `systemctl status hermes-dashboard.service` |
+74
View File
@@ -0,0 +1,74 @@
import time, os
from luma.core.interface.serial import i2c
from luma.oled.device import ssd1306
from PIL import Image, ImageDraw, ImageFont
serial = i2c(port=1, address=0x3C)
device = ssd1306(serial)
font = ImageFont.truetype('/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf', 10)
font_big = ImageFont.truetype('/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf', 16)
device.cleanup = lambda: None
def get_cpu():
with open('/proc/loadavg') as f:
parts = f.read().split()
load = float(parts[0])
cores = os.cpu_count() or 4
percent = (load / cores) * 100
return min(percent, 100), load
def get_ram():
with open('/proc/meminfo') as f:
lines = f.readlines()
mem_total = int([l for l in lines if 'MemTotal' in l][0].split()[1])
mem_avail = int([l for l in lines if 'MemAvailable' in l][0].split()[1])
used = mem_total - mem_avail
return used / mem_total * 100, used // 1024, mem_total // 1024
def get_temp():
try:
with open('/sys/class/thermal/thermal_zone0/temp') as f:
return int(f.read()) / 1000
except:
return 0
while True:
cpu_pct, load = get_cpu()
ram_pct, used_mb, total_mb = get_ram()
temp = get_temp()
img = Image.new('1', device.size, 'black')
draw = ImageDraw.Draw(img)
draw.rectangle((0, 0, 127, 63), outline='white', fill='black')
bar_w = 90
bar_h = 12
# CPU bar
draw.rectangle((32, 4, 32 + bar_w, 4 + bar_h), outline='white', fill='black')
fill_w = int(bar_w * cpu_pct / 100)
if fill_w > 0:
draw.rectangle((32 + 1, 4 + 1, 32 + fill_w, 4 + bar_h - 1), fill='white')
draw.text((2, 5), 'CPU', font=font, fill='white')
draw.text((32 + bar_w + 4, 3), f'{cpu_pct:.0f}%', font=font_big, fill='white')
draw.text((2, 20), f'Load: {load:.2f}', font=font, fill='white')
# RAM bar
draw.rectangle((32, 36, 32 + bar_w, 36 + bar_h), outline='white', fill='black')
fill_w2 = int(bar_w * ram_pct / 100)
if fill_w2 > 0:
draw.rectangle((32 + 1, 36 + 1, 32 + fill_w2, 36 + bar_h - 1), fill='white')
draw.text((2, 38), 'RAM', font=font, fill='white')
draw.text((32 + bar_w + 4, 36), f'{ram_pct:.0f}%', font=font_big, fill='white')
# Temp and PID at bottom
draw.text((2, 52), f'Temp: {temp:.1f}C', font=font, fill='white')
draw.text((72, 52), f'PID: {os.getpid()}', font=font, fill='white')
device.display(img)
time.sleep(1)