---
date: 2026-06-27
type: decision
tags: [dttb, dashboard, homepage, proxmox, authentik, npm]
---

# Homepage — единый дашборд home lab (LXC 145)

## Контекст
Зоопарк сервисов dttb разросся (42 VM/LXC). Нужна одна точка входа — карта инфраструктуры с живыми метриками. Выбран [Homepage](https://gethomepage.dev) (`gethomepage/homepage`) — нативные виджеты под бо́льшую часть стека.

## Что развёрнуто
- **LXC 145 `homepage`** — Debian 12, unprivileged + nesting/keyctl, 2 vCPU / 1 GB / 8 GB на `work`, статика **10.0.0.148**, nameserver 1.1.1.1.
- Docker `ghcr.io/gethomepage/homepage:latest`, `-p 3000:3000`, `--env-file /opt/homepage/.env`, volume `/opt/homepage/config`.
- Веб: **https://dash.dttb.ru** (NPM proxy host **id 42**, LE cert **id 134** до 2026-09-24) за **NPM Basic Auth** (access-list id 5, `oleg`/`OL260380eg`). LAN/NetBird — `http://10.0.0.148:3000` без авторизации.
- ⚠️ **authentik forward-auth НЕ боевой** (отложен) — см. грабли #4. Enforcement работал (unauth→302 в authentik), но embedded-outpost строит authorize-URL как `http://localhost` (игнорит `authentik_host_browser`, а `authentik_host=https://auth.dttb.ru` упирается в зависший hairpin LXC144→NPM). Плюс Олег ещё не прошёл 2FA-enrollment в authentik. Объекты (provider/app/outpost) оставлены готовыми, гейт пока Basic Auth.
- 5 групп / 22 сервиса: Инфраструктура, Облако и данные, AI-боты и инструменты, Доступ и безопасность, Дом-сеть-медиа.

## Live-виджеты (read-only доступы — не мастер-креды)
| Сервис | Виджет | Доступ |
|--------|--------|--------|
| Proxmox VE | proxmox | API-токен `homepage@pve!homepage` (роль **PVEAuditor**, privsep 0) |
| Nginx Proxy Manager | nginxproxymanager | логин it5870@yandex.ru (виджет сам берёт JWT) |
| Gitea | gitea | read-only PAT `homepage-dashboard` (scopes read:repository/issue/user/org/notification/misc) |
| Nextcloud | nextcloud | admin + **app-password** (serverinfo API) |

Остальное — ping-плитки (siteMonitor на внутренний IP): UniFi, Vaultwarden, LinkWarden, ZimaOS, Антошка, SwarmClaw, German, Open WebUI, OmniRoute, code-server, authentik, RustDesk, Mailcow, Amnezia, Home Assistant, WatchYourLAN, PBS, pve-147.

## Секреты
`/opt/homepage/.env` (chmod 600, **НЕ в vault, не в git**): `HOMEPAGE_VAR_*` (proxmox token, npm/nc creds, gitea token) + `HOMEPAGE_ALLOWED_HOSTS=dash.dttb.ru,10.0.0.148:3000,localhost:3000`. В `services.yaml` — только плейсхолдеры `{{HOMEPAGE_VAR_*}}`.

## Грабли (за них наступали)
1. **`download.docker.com` SNI-блок РКН** (`tlsv1 unrecognized name`) — DNS отдаёт реальный CloudFront, но РКН режет по SNI. Фикс: `docker.io` из репо Debian, а сам apt переключён на **`mirror.yandex.ru`** (deb.debian.org=Fastly тоже троттлится из РФ).
2. **Nextcloud-виджет и split-DNS** — `dttb.ru` из контейнера (DNS 1.1.1.1) резолвится в публичный 176.62.183.186 → хайрпин через WAN. Фикс: `/etc/hosts` → `10.0.0.195 dttb.ru` (идёт прямо на NPM).
3. **NPM + authentik forward-auth, duplicate `location /`** — NPM кладёт `advanced_config` ПОСЛЕ своего `location /` (стр. 72 vs 96 в `42.conf`). Свой `location /` в сниппет = nginx duplicate location → конфиг не сохранится. Решение: `auth_request` на уровне **server** (наследуется в NPM-овский `location /`), а в `location /outpost.goauthentik.io` и `@goauthentik_proxy_signin` — **`auth_request off;`** (иначе рекурсия auth-сабреквеста сам в себя).
4. **`http://localhost` в authorize-redirect** — embedded outpost не знал внешний URL. Фикс: outpost config **`authentik_host_browser=https://auth.dttb.ru`** + рестарт `server`/`worker` (config подхватывается рестартом, не сразу).
5. authentik objects: proxy provider pk **3** (`forward_single`, external_host https://dash.dttb.ru), application slug **`dash`**, привязан к embedded outpost `88286dc5-…`.

## NPM advanced_config (server-level auth_request)
```nginx
location /outpost.goauthentik.io {
    auth_request off;
    proxy_pass http://10.0.0.144:9000/outpost.goauthentik.io;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Original-URL $scheme://$http_host$request_uri;
    auth_request_set $auth_cookie $upstream_http_set_cookie;
    add_header Set-Cookie $auth_cookie;
    proxy_pass_request_body off;
    proxy_set_header Content-Length "";
}
location @goauthentik_proxy_signin {
    internal; auth_request off;
    add_header Set-Cookie $auth_cookie;
    return 302 /outpost.goauthentik.io/start?rd=$request_uri;
}
auth_request /outpost.goauthentik.io/auth/nginx;
error_page 401 = @goauthentik_proxy_signin;
auth_request_set $auth_cookie $upstream_http_set_cookie;
add_header Set-Cookie $auth_cookie;
```

## Дополнения 2026-06-27 (2-я итерация)
- **Здоровье хоста (glances)** — на Proxmox-хосте `apt install glances lm-sensors`, systemd `glances.service` = `/usr/bin/glances -w --disable-webui -p 61208` (⚠️ НЕ `-B/-q/-t` — с ними uvicorn не биндился). Группа «Хост Proxmox»: 6 виджетов `type: glances, version: 4` (cpu, memory, sensor:Core 0, fs:/, fs:/mnt/pve/work, network:vmbr0). API `http://10.0.0.250:61208/api/4/...`.
- **Доска клиентов** — LXC 145 подключён в **NetBird** (`100.70.113.28`, группа Claude-Diag, ключ SwarmClaw `1558712D…`, netbird 0.73.2 из apt-репо pkgs.netbird.io). Группа «Клиенты (NetBird)»: ping-плитки always-on площадок (НИИКН 100.70.145.223, ММФБ 100.70.128.49, Бужарово 100.70.75.103, Знаменское 100.70.93.36, Главторг 100.70.195.47, Sergey 100.70.110.164, Lipki 100.70.35.234). ⚠️ **NetBird-грабля:** при поднятии туннеля LAN на миг отвалился (glances→000), но прямые маршруты 10.0.0.0/24 защищены правилом `105: lookup main suppress_prefixlength 0` (туннельная таблица netbird не перехватывает directly-connected). resolv.conf НЕ тронут (1.1.1.1). watchdog `*/5` `/usr/local/bin/netbird-watchdog.sh`.
- **Закладки** (`bookmarks.yaml`): Proxmox, NetBird console, Spaceweb DNS, HOSTKEY, claude.ai usage, OmniRoute, SwarmClaw, боты.
- **Группа «OpenWrt роутеры»** — все 10 OpenWrt-роутеров (собраны workflow-сканом vault), ping по NetBird: дом (по LAN 10.0.0.1), Sergey 100.70.110.164, Olivier 100.70.194.241, Lipki 100.70.35.234, Benelux 100.70.207.97, НИИКН-VM101 100.70.120.229, Переделки 100.70.197.125, Бужарово-Сев.лес 100.70.113.251, Красногорск 100.70.152.137, Знаменское-3 100.70.54.204. На момент сборки UP: дом/Sergey/Lipki/Benelux/НИИКН/Бужарово/Знаменское-3 (7); down: Olivier, Переделки (vault: возможно offline с 05-08), Красногорск. **Sergey/Lipki намеренно дублируются** в «Клиенты» (это клиенты с подкопом) и в «OpenWrt роутеры» (по-железу) — по правке Олега.
- **Хардеринг:** onboot=1 (есть). ⚠️ **НАХОДКА: на Proxmox нет ни одного запланированного бэкапа** (`jobs.cfg` пуст) — вынесено в отдельную задачу.

## Self-serve: апгрейд плиток до live-виджетов (нужны токены, генерит Олег за 2 мин)
Достижимы из контейнера, не хватает только токена (вписать в `/opt/homepage/.env` как `HOMEPAGE_VAR_*` + добавить `widget:` в `services.yaml`):
- **Home Assistant** (home.dttb.ru): Профиль → Long-Lived Access Token. `type: homeassistant`.
- **Mailcow** (mail.dttb.ru): Admin → API → read-only ключ. `type: mailcow`.
- **Vaultwarden** (bit.dttb.ru): задать `ADMIN_TOKEN` в compose. `type: vaultwarden`.
- **PBS** (VM 106 сейчас недоступен по SSH — сперва проверить, жив ли): `proxmox-backup-manager user generate-token`. `type: proxmoxbackupserver`.

## TODO / можно докрутить
- **authentik forward-auth → боевой**: починить `localhost` в authorize (embedded outpost). Варианты: standalone-outpost контейнер на dash-LXC; либо разобраться, почему `authentik_host_browser` не применяется в 2026.5.3; нужен живой браузерный тест + 2FA-enrollment Олега. Тогда снять Basic Auth (access-list 5).
- UniFi/Vaultwarden можно перевести из плиток в live-виджеты (нужны read-only креды/токены).

См. [[../projects/dttb/proxmox-inventory#LXC 145 — homepage Dashboard]], [[2026-06-26-authentik-sso-deploy]].
