Цифровой дворник

Практические заметки о сетях, self-hosting, виртуализации, мониторинге, автоматизации и локальном ИИ.

Telegram: @digclean

Обложка

Исходные данные

Две площадки — «дом» и «дача». Дом сидит за операторским CGNAT: белого IP нет, порты наружу не пробросить. У дачи белый адрес есть. Сервисы (Caddy, блог, мониторинг, файлы) живут на сервере за домом, а смотреть их хочется и с дачи, и с телефона из кафе.

Поэтому между площадками у меня самопальный WireGuard: один файл конфига, пир на пир, доведённый руками маршрут до локальной сети.

Работает. Но каждое новое устройство — это снова ключи, AllowedIPs и маршрут руками. А ещё оба конца за NAT — и тут начинаются вопросы, которые WG сам не решает.

Что такое mesh-VPN и почему про них вспоминают

Mesh-VPN делает то же самое — зашифрованная сеть между узлами, — но добавляет координатора, который сам знакомит узлы, пробивает NAT и подставляет relay, если напрямую не выходит.

Два самых популярных варианта:

  • Tailscale — под капотом тот же WireGuard. Управление в облаке провайдера, узлы сами находят друг друга, при неудачном прямом пути трафик идёт через их relay DERP, в том числе поверх TCP/443. Настройка — поставить клиент и залогиниться.
  • ZeroTier — виртуальный Ethernet-порт поверх P2P-сети: узлы видят друг друга как в одном свитче, с broadcast и multicast. Для поиска — публичные root-серверы, а если UDP режут — отдельный TCP-relay.

Как это ложится на нашу лабу

Собрал честную сравнительную табличку под наши вводные — «оба конца за NAT», «хочется с телефона», «ноль внешних зависимостей».

  • Самопал WG: полный контроль и никакого чужого облака. Но NAT-пробивание — на тебе: если один конец за симметричным NAT, прямой туннель может не подняться, а своего relay у WG нет. Каждое устройство — руками.

Команды, из которых у нас сейчас и состоит туннель:

wg setconf wg0 /etc/wireguard/wg0.conf
ip addr add 10.100.0.2/30 dev wg0
ip route add 10.0.0.0/24 dev wg0

На роутере — только пир и проброс в туннель:

/interface wireguard peers add interface=wg-lab allowed-address=10.100.0.2/32
/ip firewall nat add chain=dstnat protocol=tcp dst-port=443 action=dst-nat to-addresses=10.100.0.2
  • Tailscale: бесплатного личного тарифа хватает с запасом — до 6 пользователей, но число устройств не ограничено. Прямой путь — WireGuard, а если не пробилось — DERP через TCP/443, то есть туннель переживает сети, где душат UDP. Плата — контроль-плейн чужой; впрочем, его можно унести к себе через Headscale.
  • ZeroTier: бесплатный тариф урезали до 10 устройств и одной сети — для парка «телефоны + ноутбуки + домашние железки» это впритык. Зато модель L2: устройства реально в одном сегменте, что удобно для старого софта, который ждёт обычный Ethernet. Контроллер self-host возможен, но это уже отдельная поставка и лицензия.

Мораль

Mesh-VPN не отменяет понимания — он прячет от тебя NAT-пробивание, relay и координатора. Пока узлов два и они твои — WireGuard руками честнее и прозрачнее. Когда узлов десять, а сетей три, координатор начинает окупаться: ты платишь не только деньгами, но и внешней зависимостью.

Мы для двух площадок остались на самопале. А как только понадобилось «достать всё отовсюду с телефона» — mesh-VPN честнее, чем плодить ещё десяток туннелей.

#network #selfhosting

Боль – Запускаешь субагента — а в ответ тишина. Никаких ошибок, просто пустой content. Думаешь, «сломалось». А потом понимаешь: вся «жвачка для мозгов» улетела в скрытый reasoning, а на обычный текст токенов не осталось. – Вторая мина: OpenClaw парсит model ref по первому слэшу. Если у провайдера id модели с префиксом вроде ollama/..., без полного префикса провайдера OpenClaw радостно шлёт запрос на локальный ollama-хост, где такой модели нет. И ты дебажишь не то место.

Решение – Дать моделям дышать: maxtokens=16000 для «думающих» (qwen3, deepseek-r1 и т.п.). У GPT-5 — не путать maxtokens и maxcompletiontokens, плюс ставить reasoning_effort=low. – Указывать полный реф модели с провайдером: provL/ollama/..., а не просто ollama/.... Тогда resolvedProvider попадает куда нужно, и субагент оживает.

Что делал по шагам (и живые цифры)

1) Тест 21 модели на одном конфиге (06:10–06:50 UTC) – Конфиг: сокращённый экспорт MikroTik (14.5KB), один и тот же промпт: топология + 5 проблем + что пинговать. – 14 локальных (наш провайдер) + 7 облачных (GPT-5/4o/4o-mini, DeepSeek V4 Flash/Pro/Reasoner/Chat). – Результаты: 20/21 ответили, llama3.1 упал с 500. – Пьедестал: GPT-5 → DeepSeek V4 Pro → gemma3:latest (лучшая локальная). – Стоимость всего прогона: ~$0.23 (148K prompt + 70K completion). – Главный грабль: пустые ответы thinking-моделей ≠ поломка, а нехватка maxtokens. – qwen3:30b, qwen3-vl:8b, deepseek-r1:14b при лимите 2000–3000 возвращали пустой content (весь бюджет уходил в скрытый reasoning). – С maxtokens=16000 все заговорили. – GPT-5: нужен maxcompletiontokens (не maxtokens!) + reasoningeffort=low.

2) Проверка tools (08:08 UTC) – Прогнал function calling у 5 кандидатов через API нашего провайдера. – ✅ Все 5 поддерживают tools: gemma4:12b-p40, qwen3-coder:latest, qwen2.5:14b, gemma4:e4b, qwen3:30b. – Это критично для субагентов: без tools субагент не читает файлы и не выполняет команды.

3) Подключение к OpenClaw (08:10 UTC) – Добавил провайдера provL в ~/.openclaw/openclaw.json: – baseUrl: https://llm.example/v1 – api: openai-completions – 5 моделей: gemma4:12b-p40 (16k ctx), qwen3-coder:latest (131k), qwen2.5:14b (33k), qwen3:30b (131k), gemma4:e4b (16k) – maxTokens: 16000 (важно! иначе пустые ответы) – openclaw gateway restart — применил конфиг (hot reload тоже работает). – ✅ openclaw models list — модели видны, tools=yes.

4) Грабли с резолвом модели (ВАЖНО!) – У нашего провайдера id моделей с префиксом ollama/ (например ollama/gemma4:12b-p40). – Если спавнить субагента с model=ollama/gemma4:12b-p40, OpenClaw парсит по первому / как provider=ollama и шлёт на локальный ollama-хост, где модели нет. – Правильно: полный реф provL/ollama/gemma4:12b-p40 — провайдер provL, id модели ollama/gemma4:12b-p40. – Проверка: resolvedProvider=provL ✅

5) Тест субагента (08:11 UTC) – Спавн с model=provL/ollama/gemma4:12b-p40 — принят, resolvedProvider=provL ✅ – Первый спавн упал из‑за рестарта gateway — GatewayDrainingError, не из‑за модели. – ✅ Результат (08:15 UTC): субагент отработал — выполнил exec ping -c 1 внешний DNS, ответил «1 пакет, 0% потерь, 36.7 мс». Tools работают, модель подключена корректно.

Итоги, если по‑честному 1) Тест перед подключением — обязателен. Пустые ответы ≠ сломанная модель: проверь max_tokens. 2) Tools проверять отдельно. Документации мало — нужен реальный вызов. 3) Префикс провайдера в id — ловушка. Model ref парсится по первому /. Для провайдеров с префиксованными id (ollama/, openrouter/) используй полный реф provider/model. 4) Локальные модели через API нашего провайдера: по деньгам $0 (квота), но выжигают дневной лимит токенов.

Сколько стоило – Весь тест 21 модели: ~$0.23 – Локальные: $0 (квота провайдера) – GPT-5: $0.14 (из них ~$0.10 — неудачная первая попытка с max_tokens) – DeepSeek V4 Pro: $0.05

Что ещё проверить – [x] Субагент реально выполнил ping (✅ 08:15 UTC, 0% потерь) – [ ] Сравнить скорость: локальные (наш провайдер) vs облачные – [ ] Стабильность на длинных задачах (не только ping)

📊 Метрики поста: см. фактуру (токены/модели/проверки живьём) — ~Xk токенов, 2 модели (gpt-4o-mini + gpt-5 редактура)

#openclaw

Что будет, если L2TP‑туннель между роутерами умрёт в три часа ночи, а ты узнаешь об этом через неделю?

Ничего хорошего. У меня в лабе три туннеля: основной L2TP дача↔дом, SSH reverse‑туннель от веб‑шлюза/прокси до роутера и выход на зарубежный VPS. Каждый — своя точка отказа, и все живут за NAT. Без мониторинга — ты просто слеп.

Решение — поставить Uptime Kuma в отдельном контейнере. У меня 16 мониторов и алерты в Telegram. Туннели проверяются по‑простому: пинги на внутренние адреса, SSH‑реверс — проверкой доступности порта 8443. Не отвечает дольше N секунд — прилетает сообщение в телегу.

Живые цифры: основной L2TP сейчас подключен, аптайм 3д19ч54м, IPsec cbc(aes)+hmac(sha1), MTU 1400, keepalive 60с. Дальняя сторона — hAP ac lite с 64MB RAM и MIPS 650MHz за NAT. Железо на пределе, а туннель держит.

Мораль простая: если туннель живёт за NAT на роутере с 64MB памяти, мониторинг — не роскошь, а необходимость. Дороже всего знать, что всё ок.

📊 Метрики поста: см. фактуру (токены/модели/проверки живьём) — ~10k токенов, 2 модели (gpt-4o-mini + gpt-5 редактура)

#monitoring #network

Боль Разбирал конфиги двух MikroTik‑роутеров в двух точках (дом и дача). Прогнал всё вручную: нашёл очевидное — SNMP открыт миру, RDP наружу, слабый пароль на Wi‑Fi, автоскрипт тянется из публичного репозитория. Красота для чек‑листа. И всё же я прошёл мимо главного.

Решение Подал те же конфиги в независимую ИИ‑сессию — мой «субагент». И он ткнул носом туда, куда я не доглядел: на домашнем роутере оказалось 12 статических маршрутов с gateway, который совпадал с локальным адресом самого роутера в L2TP‑туннеле. То есть классический самострел — self‑routing, все 12 в статусе INACTIVE. Причём те же подсети крупных сервисов (YouTube/Google) уже были покрыты рабочим путём через другой L2TP‑шлюз до зарубежного VPS. Дубли чистой воды.

Живые цифры Проверил руками на роутере — субагент прав. Все 12 сетей реально закрыты рабочим маршрутом, добавлять нечего, просто выметаем мёртвые. Команда — одна строка: /ip route remove [find gateway=<внутренний-L2TP-адрес-роутера>]. Минутное дело — и таблица дышит: всего маршрутов было 147, стало 135. YouTube помчал по активному туннелю как и должен — через рабочий L2TP‑шлюз до зарубежного VPS.

Вывод Два мозга видят по‑разному. Я выловил явные дыры в безопасности, субагент — 12 маршрутов‑зомби. С тех пор правило железобетонное: сложный конфиг — минимум два прохода разными моделями. Независимая проверка окупается именно в такие моменты.


Технические детали – Роутер: MikroTik hAP ac lite (RB952Ui-5ac2nD), RouterOS 7.21.3 – Мёртвые маршруты: 12 шт., все INACTIVE, gateway = внутренний L2TP‑адрес самого роутера (self‑routing к даче) – Затронутые сети: 12 публичных префиксов крупных сервисов (YouTube/Google), уже дублировались рабочим маршрутом – Живой шлюз: внутренний адрес L2TP‑туннеля до зарубежного VPS — покрывает все 12 сетей – Команда чистки: /ip route remove [find gateway=<внутренний-L2TP-адрес-роутера>] (бэкап before-routes-clean сделан заранее) – После чистки: всего маршрутов 147 → 135, YouTube ACTIVE через рабочий L2TP‑шлюз – Оценка субагента: ~50 кандидатов в «мёртвые» с дублями через рабочий шлюз; уникально мёртвых через локальный L2TP‑адрес — 12

📊 Метрики поста: ~3k токенов, 2 модели (gpt-4o-mini + gpt-5 редактура)

#openclaw #network

Боль. Сел разбирать конфиги двух наших MikroTik-роутеров. В прошлый раз один субагент уже вытащил на свет классические ужасы: SNMP наружу, RDP в интернет, слабый Wi‑Fi, скрипт с GitHub с завышенными правами. Но чувство «что-то ещё не так» не отпускало. Решил пойти в атаку иначе — ролевым аудитом.

Решение. Беру три субагента, каждому прописываю роль и даю одну и ту же свежую выгрузку конфигов. И — важно — каждому свою модель:

  • 🕸 Сетевой инженер → DeepSeek Flash
  • 🛡 Специалист по безопасности → gpt-4o-mini
  • ⚙️ Системный администратор → DeepSeek Pro

Все трое смотрят на один и тот же зоопарк правил. И вот где всплыли призраки.

Сетевой инженер выстрелил первым — нашёл то, что раньше пролетало мимо: 1. 🔴 DHCP-клиент defconf висит на WAN рядом с PPPoE. Если провайдер внезапно раздаст адрес по DHCP, его дефолт-маршрут (distance 1) перебьёт PPPoE (distance 2) — и привет, сломанный NAT и пробросы портов. Мина под NAT, тикает тихо. 2. 🔴 Мёртвый маршрут до PVE‑lab — шлюз не существует ни в одной подключённой сети, маршрут INACTIVE, через него лаба не ходит. 3. 🟡 Около 110 «немых» маршрутов‑дублей без комментариев — старый дамп перекрывается новыми. Дедупликация схлопнет таблицу на 25–30%. 4. 🟡 Мусор через VPN: multicast (multicast-диапазоны) прогнан через L2TP — бессмысленно; ещё и RFC1918‑сеть через VPN конфликтует, плюс широкие блоки /8 и /12 в туннеле с MTU 1400. 5. 🟡 Неиспользуемый туннель vpn‑office — висит без маршрутов, без NAT, с выключенными правилами.

Администратор (DeepSeek Pro) добавил прицельно в «нагрузку и мусор»: – 🟡 BFD включён на всех интерфейсах, а BGP/OSPF вообще не настроены — пустые hello‑пакеты только грузят CPU. – 🟡 Address‑list для YouTube = 496 записей на роутере с 64 MB RAM, обновляется скриптом каждые 12 часов — и не используется ни одним правилом! – 🟡 DHCP lease‑time = 10m — клиенты переподтверждаются фактически каждые 5 минут, лишний broadcast для слабого MIPS. – 🟡 Включён авто‑шаринг SMB на самом роутере — лишний вектор в LAN.

Безопасник (gpt‑4o‑mini) подтвердил старые дыры и подкинул деталей: проброс RDP целится в хост с динамическим DHCP‑лизом — адрес сменится, а проброс молча уедет к соседу; у GitHub‑скрипта политика с флагами reboot/password/sensitive — жирнее некуда.

Итог: +10 новых находок к прошлому аудиту. Три я проверил живьём на роутере — всё сошлось: DHCP‑клиент на WAN ✅, мёртвый маршрут ✅, BFD на всех интерфейсах ✅.

Вывод. Один ИИ — хорошо, а три ролевых на разных моделях — заметно лучше. Каждый видит своё: сетевой — маршруты и топологию, безопасник — порты и крипту, админ — нагрузку и мусор. Плюс разные провайдеры у моделей = меньше шансов, что все одинаково налажают. Беру в стандарт: роли × модели × живая проверка.


Бонус‑история: локальные gemma без tools (или почему «прогнать на gemma» не равно «оно правда работало локально»)

Захотел прогнать те же три роли на локальных моделях — gemma3:12b и gemma3:4b (у нас Radeon 760M + ROCm). И тут под капотом всплыла важная деталь: ollama 0.32.5 не поддерживает function calling (tools) для gemma3 — capabilities только completion, vision. А субагентский режим без tools слепой: ни прочитать файлы, ни exec.

Практика: – Раньше «субагенты на gemma» тихо работали на DeepSeek Pro — OpenClaw при ошибке молча делал failover на основную модель. Итог: анализ «за 12b» стоил $0.19 на DeepSeek Pro. Классика: думаешь, что локально, а реально жжёшь облако 😄 – gemma3:4b падает с FailoverError: provider rejected the request schema or tool payload.

Лекарство — прямой прогон через ollama API. Берём конфиги, даём системный промпт роли и шлём в /api/chat напрямую. Без tools — зато честно на gemma. 3 роли × 2 модели = 6 генераций последовательно на GPU (параллелить нельзя: модели выдавливают друг друга из VRAM).

Мораль №2: проверяйте, кто реально делает работу. Если в доках у модели чего‑то «нет», не верьте отчёту — проверьте руками. Отсутствие tools у локалок — не приговор, а повод идти через прямой API.


Технические детали

  • Роутеры: роутер на даче (hEX E50UG, 512 MB), домашний роутер (hAP ac lite, 64 MB MIPS)
  • Модели субагентов: deepseek‑v4‑flash (net), openai/gpt‑4o‑mini (sec), deepseek‑v4‑pro (adm)
  • Конфиги: backups/mikrotik/r1‑export‑20260805.rsc (1174 стр.), backups/mikrotik/dom‑export‑20260805.rsc (974 стр.)
  • Полное сравнение: backups/mikrotik/AUDIT‑COMPARE‑20260805.md
  • Подтверждено живьём: /ip dhcp‑client print (клиент searching), /ip route print (проблемный маршрут INACTIVE), /routing bfd configuration print (interfaces=all)
  • Заодно за день: BGP/OSPF off (CPU 99% → 15%), DNS static 231 → 0, удалены 12 мёртвых маршрутов на внутренний хост

📊 Метрики поста: см. фактуру (токены/модели/проверки живьём) — ~Xk токенов, 2 модели (gpt-4o-mini + gpt-5 редактура)

#openclaw #network

Боль: живёшь с одним роутером — а в нём мост из костылей, маршруты-призраки и правила firewall, которые давно смотрят в никуда. Сколько глаз нужно, чтобы увидеть всё сразу?

Решение: дал всем одинаковый экзамен. Один и тот же реальный конфиг MikroTik (14.5 КБ: интерфейсы, адреса, маршруты, firewall, NAT, DHCP, DNS, туннели) и один промпт — на 21 модель (14 локальных через один API + 7 облачных: GPT, DeepSeek). Попросил: 1) описать устройство и топологию, 2) найти до 5 проблем, 3) предложить, что пинговать для проверки. Потом сверил ответы с живыми пингами с самого роутера.

Результат — как в жизни: кто-то гений, кто-то галлюцинирует, а трое молчат, пока им не дашь больше токенов.

🏆 Лучшие находки (совпали с реальностью)

  • DHCP-клиент на WAN-порту рядом с PPPoE — если провайдер вдруг выдаст адрес, дефолт-маршрут (distance 1) перебьёт PPPoE и сломает NAT. Нашёл только GPT-5. Это была главная находка вчерашнего аудита — облачная модель повторила её с нуля.

  • Множественные подсети в одном bridge — три разные /24 на одном мосту. Нашли 6 моделей: gemma4:12b-p40, gemma4:12b, gemma4:e4b, qwen3-vl:8b, DeepSeek V4 Pro, DeepSeek Chat.

  • Мёртвый маршрут до лаборатории — маршрут на тестовую /24 через несуществующий шлюз. Вспомнил qwen3-coder:latest — и предложил именно его пинговать.

  • Маршруты «сам в себя» через адрес в туннельной подсети — 12 мёртвых маршрутов, которые мы чистили вчера. Нашли: qwen3-vl:8b-p40, DeepSeek Chat, GPT-5.

  • check-gateway=none на куче маршрутов — роутер не проверяет шлюзы, мёртвые маршруты висят вечно. Заметил qwen2.5:14b.

  • Несуществующий address-list wan-mgmt — на него ссылается firewall. Нашёл DeepSeek V4 Pro.

💀 Кто облажался

  • Три локальные thinking-модели вернули пустой ответ (qwen3:30b, qwen3-vl:8b, deepseek-r1:14b) — не потому что сломаны: весь лимит токенов ушёл в скрытые размышления, а финальный ответ не влез. С maxtokens=16000 все три заговорили. Тот же фокус с GPT-5 (нужен maxcompletiontokens + reasoningeffort=low) и DeepSeek V4 Flash/Pro/Reasoner.

  • deepseek-coder:6.7b галлюцинировал: написал, что роутер настроен на RIPv2 (которого нет), и выдал учебник вместо анализа.

  • qwen2.5:7b придумал проблему: «ether3 и ether4 не используются» — хотя они в bridge.

  • llama3.1:8b-instruct-q4KM упал с 500 — не пережил конфиг.

✅ Сверка с реальностью

Модели предложили пинговать: публичный DNS, WAN у меня дома, WAN в офисе, шлюзы LAN, адреса туннелей. Я пропинговал всё с роутера: – Интернет, дом, офис, LAN — ✅ отвечают – Два адреса в туннельной сети — ❌ 100% loss

Совпало с подозрениями моделей: именно туннельные адреса они помечали проблемными.

🥇 Итоговый пьедестал

1) GPT-5 — самая глубокая (нашла то, что другие не увидели)
2) DeepSeek V4 Pro — сильный анализ, 16K reasoning
3) gemma3:latest — лучшая локальная, 4.2K разбора бесплатно

💰 Сколько это стоило

Весь эксперимент — ~$0.23: 148K токенов промпта + 70K вывода, 30 запросов.

  • GPT-5 — $0.14
  • DeepSeek V4 Pro — $0.05
  • GPT-4o — $0.02
  • DeepSeek Reasoner/Flash, Chat, GPT-4o mini — ~$0.01
  • Локальные 14 моделей — $0.00 (квота)

Локальные не берут денег, но сожгли 91K токенов дневной квоты одним прогоном. GPT-5 — самый дорогой, и половина его стоимости ушла в первую неудачную попытку (не тот параметр лимита). Урок: дешевле сначала прочитать документацию, чем платить за ошибку 😄

Мораль

Разные модели — разные глаза. GPT-5 увидел то, что мы чинили вчера, локальные gemma подтвердили bridge-хаос, а thinking-модели молчат, пока не дашь им токенов. Ни одна не нашла всё, но вместе покрыли почти все реальные проблемы.

И главное: пустой ответ модели — это не всегда «модель сломана», часто это «не хватило лимита на размышления». Прежде чем списывать — подними max_tokens.


Технические детали (для поста/комментариев)

  • Локальные (14): gemma4:12b-p40, qwen3-vl:8b-p40, gemma4:12b, qwen3-vl:8b, gemma4:e4b, gemma3:latest, qwen3-coder:latest, qwen3:30b, qwen2.5:14b, qwen2.5:14b-instruct, qwen2.5:7b, deepseek-r1:14b, deepseek-coder:6.7b, llama3.1:8b
  • Облачные (7): GPT-5, GPT-4o, GPT-4o mini, DeepSeek V4 Flash, V4 Pro, Reasoner, Chat (V3)
  • Конфиг: 14.5KB, все ключевые секции
  • Пустые при малом лимите: qwen3:30b, qwen3-vl:8b, deepseek-r1:14b, DS V4 Flash/Pro/Reasoner, GPT-5 → все ожили с maxtokens≥16000 (gpt-5: maxcompletiontokens + reasoningeffort=low)
  • Время: ~30 минут на весь прогон
  • Живые пинги: публичный DNS ✅, WAN дома ✅, WAN офиса ✅, LAN ✅, два адреса в туннеле ❌

💰 Стоимость эксперимента

Всего: ~$0.23 (148K токенов промпт + 70K completion, 30 попыток)

Модель/группа Промпт Вывод Попытки Стоимость
GPT-5 9,898 12,875 2 $0.1411
DeepSeek V4 Pro 10,386 10,103 2 $0.0532
GPT-4o 4,950 867 1 $0.0210
DeepSeek Reasoner 10,544 7,905 2 $0.0063
DeepSeek V4 Flash 10,544 10,489 2 $0.0044
DeepSeek Chat (V3) 5,193 1,597 1 $0.0021
GPT-4o mini 4,950 827 1 $0.0012
Локальные (14) 91,489 25,692 16 $0.00 (квота)

Нюансы: локальные жгут дневную квоту токенов (91K промпт за прогон), но не деньги. GPT-5 самый дорогой ($0.14), из них первая неудачная попытка сожгла ~$0.10 впустую. Весь эксперимент дешевле кофе.

📊 Метрики поста: см. фактуру (токены/модели/проверки живьём) — если не знаешь, напиши ~Xk токенов, 2 модели (gpt-4o-mini + gpt-5 редактура)

#openclaw #network

Обложка

Боль

Фото в чужом облаке — это «взято напрокат». Лимит 15 ГБ, подписки, внезапные изменения правил, да и приватность так себе. Хотелось, чтобы снимки жили дома, а не «где‑то у дяди».

Что такое Immich

Immich — self‑hosted менеджер фото и видео: – авто‑бэкап с телефона (iOS/Android); – локальный ML: распознавание лиц и объектов, поиск по ним; – альбомы и совместный доступ (семье/друзьям); – всё работает у вас, без чьих‑то клаудов и подписок.

Врезка: авто‑бэкап

Как подняли (кратко)

Инфраструктура — отдельный LXC‑контейнер (ID не публикуем), внутри docker compose, снаружи — reverse proxy на поддомене photos.example-lab.ru.

Минимальный compose (CPU‑вариант, дальше настраивайте под себя):

version: "3.9"
services:
  immich-server:
    image: ghcr.io/immich-app/immich-server:release
    depends_on: [immich-db, immich-redis, immich-ml]
    environment:
      - DB_HOST=immich-db
      - DB_PASSWORD=change-me
      - REDIS_HOST=immich-redis
    ports:
      - "2283:2283"  # HTTP API/UI
  immich-ml:
    image: ghcr.io/immich-app/immich-machine-learning:release
    # Для GPU добавьте проброс/драйверы; CPU тоже работает
  immich-db:
    image: postgres:14
    environment:
      - POSTGRES_PASSWORD=change-me
    volumes:
      - db:/var/lib/postgresql/data
  immich-redis:
    image: redis:7-alpine
volumes:
  db:

Reverse proxy (Caddy), прячем сервис за своим именем:

photos.example-lab.ru {
  encode zstd gzip
  reverse_proxy 198.51.100.15:2283
}

Примечания: – LXC: включить nesting, keyctl/cgroups v2; для GPU — аккуратно с группами устройств и безопасностью. – Бэкапы кладём на отдельный диск/том. – HTTPS — автоматический (Let’s Encrypt) на прокси.

Фишки в деле

  • Телефон сам заливает новые кадры в фоне.
  • Поиск по лицам/объектам — работает локально; облаку ничего не отправляется.
  • Шаринг альбомов внутри семьи — как в привычных сервисах.
  • Никаких ежемесячных платежей: только ваше железо и диск.

Врезка: поиск и группировка

Грабли и нюансы

  • Docker в LXC — ок, если включены нужные флаги; следите за лимитами памяти/времени сборки.
  • ML‑контейнер на CPU терпим, но лица индексируются дольше; с GPU — заметно бодрее и экономнее по энергозатратам.
  • Не забывайте про резервные копии базы и медиатеки; и про размер tmp при массовом импорте.

Итог

Immich закрывает боль «чужого» облака: фото у вас дома, поиск умный, бэкап автоматический. Поставили один раз — и забыли. А если вырастет — масштабируете железо, а не подписку.

Ссылки

#selfhosting

Обложка

Боль

Чтобы видеть температуру/память/нагрузку GPU в дашборде, обычно городят самописный скрипт, который тащит показания из драйвера и пушит их «куда‑нибудь». Такой код живёт до первого обновления ядра, драйвера или агента — потом ночь дебага и злость на себя прошлого.

Что такое Beszel

Beszel — лёгкий self‑hosted мониторинг: небольшой агент на хосте и аккуратная веб‑панель. Ставитcя быстро, жрёт мало, из коробки показывает CPU/память/диск/сеть и другие базовые вещи. И — сюрприз — умеет GPU.

Открытие дня: метрики GPU уже приходят сами

У агента есть поле g в статистике — там лежат данные по видеокартам. Никакого отдельного скрипта не требуется: если драйвер и устройство видны агенту (в контейнере проброшен GPU), Beszel добавляет блок g и панель рисует графики.

Пример «синтетической» выборки (для идеи структуры, значения условные):

{
  "cpu": { "load": 0.42 },
  "mem": { "used": 8096, "total": 16384 },
  "g": [
    {
      "name": "GPU 0",
      "util": 0.76,
      "mem_used": 2048,
      "mem_total": 8192,
      "temp": 62
    }
  ]
}

Важно: в контейнере дайте агенту доступ к железу. Для встроенных AMD/Intel — обычно достаточно пробросить /dev/dri (чтение), для NVIDIA — соответствующий runtime/плагины. Конкретика зависит от вашей оркестрации.

Как это выглядит

Вот типовой набор, который я вижу у себя: – загрузка GPU (%), – использование видеопамяти (MiB/GB), – температура (°C), – иногда — несколько адаптеров в массиве g.

Врезка: панель с GPU-метриками

«Кастомный скрипт» vs «встроенные g‑метрики»

  • Установка
    • Скрипт: придумать формат, упаковать, прикрутить пуш.
    • g: просто обновить агент и дать доступ к устройству.
  • Поддержка
    • Скрипт: ломается при апдейтах, требует правок.
    • g: обновляется вместе с агентом.
  • Надёжность
    • Скрипт: отдельный процесс, ещё один «пункт отказа».
    • g: часть штатной телеметрии.
  • Совместимость
    • Скрипт: ручной парсинг под конкретный драйвер.
    • g: единый формат в stats → сразу графики в панели.
  • Безопасность
    • Скрипт: лишние права/сети/библиотеки.
    • g: минимум доступа, тот же контур, что и у агента.

Врезка: «подметаем» сломанный скрипт, метрики появляются сами

Итог

Если вы уже используете Beszel — проверьте, не появилось ли у вас поле g. Велика вероятность, что графики по видеокарте заработают без единой строчки кода. Меньше костылей — больше спокойствия.

Ссылки

#monitoring #selfhosting

Обложка

Чрезмерная временная фильтрация шагает по стране семимильными шагами. Где-то на время включают белые списки, где-то выборочно перестают ходить отдельные протоколы, адреса, CDN или целые сети. Добавим к этому обычные аварии, ошибки DNS, неудачную маршрутизацию и бодрый антибот на стороне самого сайта — и получим современное «интернет вроде есть, но ничего не понятно».

Поэтому мы тоже понемногу вооружаемся диагностическими сервисами.

Сразу оговорюсь: это не рейтинг и не реклама. Инструменты решают разные задачи и хорошо дополняют друг друга. Одни смотрят на ресурс снаружи, другие проверяют его именно через проблемное подключение, третьи запоминают, когда и на сколько минут всё падало.

Почему ping уже недостаточно

Ping проверяет ICMP: дошёл ли специальный пакет до узла и вернулся ли ответ. Это полезно, но к открытию сайта относится довольно косвенно.

Возможны оба варианта:

— ping проходит, а HTTPS не работает из-за TLS, SNI, фильтрации порта, ошибки веб-сервера или недоступного CDN; — ping не проходит, потому что ICMP отключён или ограничен, а сайт при этом прекрасно открывается.

Иными словами, ping честно сообщает: «узел ответил на мой ICMP-запрос». Пользователь же в этот момент пытался открыть личный кабинет, посмотреть видео или получить ответ от API. Это уже совсем другой разговор.

Для сайта полезнее смотреть хотя бы всю цепочку:

  1. разрешилось ли доменное имя;
  2. установилось ли TCP-соединение;
  3. прошёл ли TLS для HTTPS;
  4. какой HTTP-код вернул сервер;
  5. пришёл ли ожидаемый контент;
  6. одинаков ли результат из разных сетей и регионов.

Ping-Admin: подробный внешний замер

Ping-Admin пригодится, когда нужно быстро посмотреть на сайт из большого числа внешних точек. Можно выбрать случайные узлы, отдельно российские точки или более широкий набор по разным странам.

Это именно HTTP/HTTPS-проверка, а не просто красивый список задержек. В результате по каждой точке видны:

— IP-адрес, в который разрешилось имя; — полное время загрузки; — время DNS; — установка соединения; — TLS/SSL; — ожидание ответа сервера; — редиректы; — скорость загрузки и размер страницы.

Такой разбор помогает отличить «долго думает сам сервер» от «долго устанавливается соединение» и «в одном регионе домен вообще указывает в другую сторону». Последнее нормально для CDN и Anycast, но иногда именно в различиях между точками и прячется проблема.

Особенно полезен большой набор российских узлов. Если из части городов страница открывается, а из части стабильно нет, это уже намного интереснее, чем один ping с рабочего ноутбука.

Минус очевиден: Ping-Admin проверяет сайт со своих серверов. Он ничего не знает о конкретном домашнем роутере, корпоративном DNS, Wi‑Fi, канале последней мили и маршруте проблемного пользователя. Это внешний свидетель, а не очевидец с места происшествия.

Check-Host: быстрый ответ «а снаружи как?»

Check-Host я обычно воспринимаю как быстрый мультитул. У него отдельно доступны проверки:

— HTTP/HTTPS, в том числе на нестандартном порту; — ping; — TCP-порта; — UDP-порта; — DNS.

Для первичной проверки это удобно: вставили точный URL, выбрали HTTP и через несколько секунд получили ответы из разных стран. Затем тем же ресурсом можно отдельно посмотреть TCP-порт или DNS, если HTTP-проверка показала что-то странное.

По глубине HTTP-разбора Ping-Admin интереснее, зато Check-Host быстрее отвечает на практический вопрос: ресурс не виден вообще, не виден только по HTTP/HTTPS или проблема наблюдается лишь с отдельных точек.

Есть и важная тонкость: проверять надо не только домен, но и тот протокол, которым реально пользуется клиент. Успешный ping не доказывает работу HTTPS, открытый TCP/443 не гарантирует нормальный TLS и HTTP, а ответ 403 или 429 означает, что сервер найден и ответил, но доступ ограничен. Для пользователя сайт всё равно может быть непригоден — просто причина уже не похожа на обрыв маршрута.

connect-check: проверка с места происшествия

После истории «Две недели без интернета» у нас появилась собственная утилита connect-check.

Она отвечает на другой вопрос: не «виден ли сайт из чужого дата-центра», а «что именно работает и не работает с этого компьютера через это подключение».

Утилита запускается локально на Windows, macOS или Linux. Готовые сборки лежат в разделе Releases, исходники открыты. В актуальном пакете диагностика и отдельные пробы встроены в GUI.

Полный прогон проверяет не один адрес, а целый набор классов ресурсов и протоколов: базовую сеть, DNS, captive portal, время, HTTP/HTTPS, TCP, CDN, значимые российские и зарубежные ресурсы, банки, почту, облака, репозитории обновлений, игры, видео, IoT и AI-сервисы. Для некоторых сайтов проверяется не только главная страница, но и API, CDN или статический файл — потому что витрина с антиботом и реальный клиентский трафик могут вести себя совершенно по-разному.

Если проверка ресурса провалилась, в отчёт добавляются ping и traceroute. Результат можно сохранить в HTML и отправить провайдеру или коллеге. Это уже существенно полезнее сообщения «у меня не работает интернет».

Отдельная URL-проба умеет повторять HTTP/HTTPS-запросы с заданным интервалом и числом раундов. Она показывает время, HTTP-код, разрешившийся IP, редирект и итоговый URL. Такой режим хорошо ловит плавающую проблему: пять запросов прошли, шестой завис, ещё два получили редирект куда-то не туда.

Но и connect-check не является абсолютным арбитром. Он показывает взгляд конкретного устройства и конкретного подключения. В этом и его достоинство, и ограничение. Если нужно понять географию проблемы, результат надо сравнить с Ping-Admin или Check-Host.

Uptime Kuma: не проверить сейчас, а следить постоянно

Uptime Kuma — self-hosted-мониторинг, который удобно поднять в Docker на своей ВМ или небольшом VPS.

Он умеет постоянно проверять HTTP/HTTPS, TCP, ping, DNS, WebSocket, push-мониторы и некоторые другие типы целей. Для веб-сервисов особенно полезны проверки по ключевой строке или JSON-запросу: обычный HTTP 200 OK ещё не означает, что приложение действительно отдало нужную страницу, а не вежливую заглушку «всё сломалось».

У Kuma есть история доступности, графики, контроль сертификатов, публичные статус-страницы и уведомления через Telegram, почту и множество других каналов. Минимальный интервал проверки, указанный в проекте, — 20 секунд.

Главное — правильно выбрать место установки. Kuma рядом с наблюдаемым сервером хорошо замечает падение приложения, но может не увидеть региональную или операторскую фильтрацию: внутри одного дата-центра всё будет зелёным. Экземпляр на внешнем VPS лучше показывает доступность снаружи. А если важен взгляд конкретного офиса, монитор надо ставить внутри этого офиса.

Одна точка наблюдения всегда остаётся одной точкой наблюдения. Даже если у неё очень красивый зелёный интерфейс.

Как использовать всё это вместе

Нормальная последовательность при жалобе «сайт не работает» выглядит примерно так.

1. Проверяем точный URL по HTTP/HTTPS

Начинаем с Check-Host. Вставляем именно тот адрес, который не открывается, включая https://, путь и нестандартный порт, если он есть. Смотрим, отвечает ли ресурс из разных стран.

2. Если проблема неоднородная — идём в Ping-Admin

Запускаем подробную проверку из нескольких российских и зарубежных точек. Сравниваем DNS, IP, соединение, TLS, ожидание сервера и редиректы.

3. Запускаем connect-check на проблемном подключении

Теперь получаем взгляд изнутри: как работает DNS, открываются ли соседние классы ресурсов, не сломаны ли только HTTPS, CDN, обновления, видео или отдельные сети. Сохраняем HTML-отчёт.

Если проблема плавающая, оставляем URL-пробу на несколько раундов. Это часто продуктивнее, чем двадцать раз вручную обновлять браузер и пытаться понять, показалось или нет.

4. Для важных сервисов включаем Uptime Kuma

Добавляем постоянную HTTP/HTTPS-проверку. Где возможно — проверяем не только код ответа, но и ключевую строку или JSON. Настраиваем уведомления и сохраняем историю.

Монитор лучше размещать не на том же сервере, который он наблюдает. Иначе при общей аварии они могут исчезнуть вместе, сохранив удивительное единодушие.

Короткая шпаргалка

Вопрос Что взять
Сайт прямо сейчас виден из разных городов и стран? Check-Host или Ping-Admin
Где тратится время: DNS, соединение, TLS или ответ сервера? Ping-Admin
Открыт ли конкретный TCP/UDP-порт? Check-Host
Почему сервис не работает именно у этого пользователя? connect-check на его подключении
Нужно поймать плавающие HTTP/HTTPS-сбои локально? URL-проба connect-check
Когда сервис упал и сколько был недоступен? Uptime Kuma
Нужны уведомления и история? Uptime Kuma
Нужен внятный материал для обращения к провайдеру? connect-check + внешняя проверка Ping-Admin/Check-Host

На что не наступить

Во-первых, не вставляйте во внешние сервисы приватные URL с токенами, одноразовыми подписями, адресами внутренних панелей и другими секретами. Проверка выполняется чужой инфраструктурой, и введённый адрес перестаёт быть только вашим.

Во-вторых, не делайте вывод по одной красной точке. Проверочный узел тоже может быть перегружен, временно потерять маршрут или попасть под ограничение самого сайта.

В-третьих, браузер и HTTP-проба — не одно и то же. JavaScript, авторизация, антибот, API и загрузка статических файлов могут ломаться независимо. Иногда 403 означает «сервер жив, но нас не пустили», а 200 — «заглушка успешно загружена».

И наконец, сохраняйте время проверки, адрес, IP, выбранные узлы и результаты. Фраза «13 августа с 10:15 до 10:27 HTTPS не устанавливался через такого-то провайдера, при этом из шести внешних точек работал» сильно полезнее бессмертного «у вас интернет сломался».

Получается не один идеальный сервис, а небольшой набор инструментов:

— Check-Host быстро подтверждает внешний симптом; — Ping-Admin раскладывает HTTP/HTTPS по этапам и географии; — connect-check показывает картину с проблемного подключения; — Uptime Kuma следит за сервисом постоянно и помнит историю.

В эпоху, когда интернет всё чаще ломается не целиком, а художественно и выборочно, такая коллекция отвёрток уже не выглядит избыточной.

Ссылки

— Ping-Admin: разовая проверка доступности

— Check-Host: HTTP/HTTPS-проверка

— connect-check: репозиторий

— connect-check: готовые сборки

— Uptime Kuma

#monitoring #network

Обложка

Одиннадцать статей позади — пора честно ответить, ради чего всё затевалось: что из этого зоопарка стоит поднимать у себя, а где self-host — красивая идея, которая жрёт время и электричество. Спойлер: «всё своё» не бывает, как и «всё в облако». Есть расклад по задачам, и я его выстрадал на собственных граблях.

Два лагеря, и оба врут

Про self-host пишут либо фанатики («хости сам, будь свободен»), либо скептики («домашний сервер — хобби для мазохистов»). Оба врут: у self-host нет единой цены — есть задачи, где он окупается с первого дня, и задачи, где он — чистая дыра в бюджете.

Где self-host окупается

Три вещи, которые облако не даёт в принципе, сколько ни плати.

Данные под контролем. Фото, видео с камер, заметки, логи — всё на моём диске. Для фотоархива и видеонаблюдения это суть задачи: отдавать семейный архив и камеры с крыльца в чужое хранилище — плохая идея ещё до всяких вопросов о деньгах. Immich и Frigate для того и существуют, чтобы это оставалось твоим.

Нет ежемесячной подписки. Публикации, картинки, аналитика, мониторинг — у каждой такой штуки есть SaaS-аналог «от девяти долларов». У меня вместо десятка подписок — один мини-ПК и несколько контейнеров: блог на WriteFreely, картинки через свою пасту, счётчик посещений — свой Umami. Заплатил за железо один раз — дальше только электричество.

Кастом. Мой вход в лабу — это Caddy с обратным туннелем наружу, NAT между сетями и ACL на админки. Такую схему под свою сеть и свои VPN облачный сервис не соберёт никогда. Как только нужно «не как у всех», self-host из опции становится единственным путём.

Где self-host — чистые грабли

Сложность. Каждый сервис надо поставить, обновить, пробросить, защитить. В облаке ты платишь за то, что это делает кто-то другой. Дома ты сам тот «кто-то». Когда ROCm-костыль падает на длинном промпте, чинить идти тебе, а не в поддержку.

Обновления. SaaS обновляется, пока ты спишь. Домашний сервис стоит в той версии, в которой ты его оставил, и за обновлениями следишь сам. Забыл на полгода — получил дыру и мёртвый бэкап-таймер.

GPU в дефиците. Для инференса нужно видео-железо, а оно либо дорогое, либо его нет. У меня встроенная графика, и весь локальный инференс держится на том, что 8 ГБ общей памяти уходят под модель впритык. Дискретная карта под большую модель — цена, сопоставимая с годом облачной аренды.

Аптайм. Домашнее железо спит, греется, ловит скачки и умирает, когда тебя нет. Облако поднимает за тебя три девятки. Если сервис должен быть доступен всегда и отовсюду — подвал это не гарантирует.

Разбор по нашему стеку

Пройдусь по тому, что у меня реально работает, и скажу честно, где бы я заплатил снова.

Caddy как вход — однозначно self-host. Обратный прокси, NAT, туннель наружу, сертификаты на автомате. Замены облаку нет: это про твою сеть и твои правила доступа.

Публикации (WriteFreely) — оправдан. Свой блог, свой текст, никакой аренды площадки. Единственное требование — дисциплина с бэкапами, их у меня гоняет таймер.

Картинки (rustypaste) — оправдан. Своя паста под обложки и картинки. Чужие CDN из моего региона рвутся, а своя всегда на месте: загрузка по токену, отдача публичная.

Мониторинг и аналитика (Beszel, Kuma, Umami) — оправдан. Лёгкие контейнеры, никаких подписок, данные о твоей инфре не утекают третьим лицам.

Локальный инференс (Ollama) — наполовину. Для приватных вопросов и фона локальная модель — золото: вопросы не уезжают из дома, токены ничего не стоят. Но для агентов с инструментами не годится: модель на 8 ГБ не умеет в инструменты, 8B-варианты возвращают кашу, вижн локально не работает. Поэтому вторая половина задач честно уезжает в облако.

Тяжёлый инференс и большие LLM — аренда. Гнать дома модель, которой нужна дискретная карта за тысячи, бессмысленно, если та же мощность берётся в аренду без вложений в железо. Для тяжёлых агентов, больших контекстов и вижна облако остаётся основным, и я с этим смирился.

Честные цифры, чтобы не спорить на ощущениях

Локальный инференс на встроенной графике:

  • gemma3:12b в квантовке — 14.8 ток/сек, влезает в 8 ГБ VRAM впритык;
  • gemma3:4b — 23.5 ток/сек, но проще и с меньшим окном;
  • точная fp16-версия 12b — 8.1 ток/сек, потому что не влезает в память и ползёт через шину. Выкинута.

Это уровень «читает примерно с моей скоростью»: для приватных вопросов комфортно, для потоковой генерации — на грани. Облачная модель отвечает почти мгновенно, умеет в инструменты и вижн, но стоит денег и гонит текст на чужие серверы.

Потолок — 8 ГБ VRAM. У встроенной графики нет своей памяти, она заимствует её у общей. Поэтому 8 ГБ «видеопамяти» — те же 8 ГБ из оперативки, модель на 12b влезает впритык, а на 16b уже не хватило бы. Главный предел iGPU — не скорость, а память. Отсюда вывод: локально жить можно, но о «больших моделях дома» речи нет.

Бесплатное облако кусается. Бесплатные модели у агрегатора стабильно отдают 429 — «провайдер перегружен». Лимит общий на весь бесплатный пул, в час пик ты в очереди за платными. Для рутины сойдёт, для важного — нет.

Правило выбора: три множителя

Перемножай чувствительность данных × нагрузку × цену железа с электричеством.

Чувствительность. Если данные нельзя отдавать наружу (фото, видео, документы) — self-host без вариантов, вопрос только, потянешь ли железо.

Нагрузка. Лёгкое и постоянное (блог, картинки, мониторинг, аналитика) — домой, окупается. Тяжёлое и пиковое (большая LLM, агенты с инструментами, вижн) — в аренду, если только дискретная карта уже не куплена по другим причинам.

Цена. Мини-ПК круглосуточно ест электричество, и это надо считать. Пока он тянет лёгкие сервисы и фоновый инференс — счёт смешной. Как только начинаешь докупать карты ради «бесплатного ChatGPT» — окупаемость умирает, дешевле арендовать.

Итого: приватное + лёгкое — домой; тяжёлое + пиковое — в аренду; приватное + тяжёлое — дорого в обе стороны, решай по деньгам.

Что в сухом остатке

Self-host окупается там, где речь про контроль данных, отказ от подписок и кастом: вход через Caddy, свой блог, своя паста, мониторинг, аналитика, фото и камеры — всё это я бы поднял снова, не думая. Локальный инференс на встроенной графике — честный бесплатный второй мозг для приватных задач и фона, но не замена облаку.

Облако остаётся там, где нужны инструменты, вижн, большие контексты и мгновенный отклик. Домашние 8 ГБ и 15 токенов в секунду этого не дадут, сколько ни танцуй с бубном вокруг ROCm.

Главный урок серии — не «хости всё» и не «плати за всё», а честный расклад: знай, что влезает в память, что умеет твоя модель, что падает на длинном промпте и где бесплатное на самом деле в очереди. Тогда self-host из религии становится обычным инженерным решением.

#llm #openclaw #selfhosting