Files
DmitryandClaude Sonnet 5 05d8c748ab
lint / yamllint + ansible-lint + syntax-check (push) Canceled after 0s
feat: infrastructure dashboard (Homepage) generated from the service registry
playbooks/dashboard.yml deploys Homepage as a second compose stack on the
monitoring LXC (CT 155) next to Uptime Kuma and renders its config from
homelab_services: one tile per service, link to its UI, grouped by Proxmox
node. Adding a service to the registry is enough — no second service list.

- new registry consumer: playbooks/dashboard.yml + playbooks/templates/homepage-*.j2
- homelab_dashboard_* vars in group_vars/all/services.yml (top-level, like
  homelab_reverse_proxy_*); image pinned by digest, floating tag needs an
  explicit -e dashboard_allow_floating_tag=true
- bootstrap-dashboard-pve-token.yml: read-only homepage@pve!dashboard token
  (PVEAuditor) for the Proxmox widget, secret in the root .env as DASHBOARD_PVE_*
- Makefile: dashboard, dry-dashboard, bootstrap-dashboard-token
- container binds the LAN address only (192.168.1.30:8082), not published via Caddy
- docs: architecture.md Monitoring section, plan.md active task, consumer lists

Deployed to CT 155 on 2026-09-03: container healthy, http://192.168.1.30:8082/
returns 200, `make dashboard` idempotent, `make validate` and `make lint` green.
Pending operator steps: `make bootstrap-dashboard-token` (blocked in the agent
session as credential creation) and an Uptime Kuma status page with slug homelab.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KbuZrUoevfBgCpf5DCF4DG
2026-09-03 09:17:16 +03:00

642 lines
29 KiB
YAML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
# ============================================================================
# homelab_services — декларативный реестр сервисов HomeLab
# ============================================================================
#
# ЧТО ЭТО
# Единственное место, где собраны факты о каждом сервисе домашней лаборатории:
# VMID, узел Proxmox, адрес, порты, публичный домен, закреплённые образы
# с digest, ресурсы LXC, схема резервного копирования, мониторинг и порядок
# автозапуска.
#
# ВСЕ значения взяты из существующего кода (ansible/playbooks/*.yml,
# ansible/roles/*, ansible/inventory/hosts.yml). Ничего не выдумано.
# Там, где факта в коде нет, стоит комментарий "# нет в коде", а не догадка.
#
# КТО ЭТО ПОТРЕБЛЯЕТ
# * playbooks/reverse-proxy.yml — Caddyfile по блокам `proxy`.
# * playbooks/ru-vps-base.yml — стек Caddy и закреплённый образ.
# * playbooks/pve-backup-jobs.yml — списки VMID заданий по полю `backup.job`.
# * roles/backup_audit — VMID по флагу `monitoring.backup_audit_vmid`.
# * playbooks/validate.yml — сверка с фактическим состоянием Proxmox.
# * playbooks/dashboard.yml — services.yaml для Homepage-обзора инфры.
# * Человек — как справочник вместо чтения семи playbook'ов по 200-400 строк.
#
# Существующие pve-*.yml пока НЕ читают этот реестр: их перевод на
# homelab_services + роли lxc_docker_host/compose_service — отдельный этап.
# До тех пор реестр и pve-*.yml нужно править согласованно.
#
# ЧТО ПРАВИТЬ ПРИ ДОБАВЛЕНИИ НОВОГО СЕРВИСА
# 1. Добавить запись в homelab_services ниже (все обязательные поля).
# 2. Если сервис публикуется наружу — заполнить блок `proxy`
# (domain, upstream, caddy_marker, caddy_container_check, health).
# Больше ничего для reverse-proxy делать не нужно.
# 3. Хост в ansible/inventory/hosts.yml (+ группы monitoring_exporters и др.).
# 4. Задание бэкапа в ansible/playbooks/pve-backup-jobs.yml
# и VMID в roles/backup_audit/defaults/main.yml.
# 5. Плейбук развёртывания (pve-<name>.yml).
#
# СОГЛАШЕНИЯ ПО ПОЛЯМ
# vmid int, уникальный в кластере
# node cloud-pc | mini-pc — узел Proxmox, где живёт контейнер
# ip адрес в LAN без маски
# hostname имя LXC и имя хоста в inventory
# role короткое человеческое описание
# provisioner чем создаётся контейнер:
# pct_ssh — прямой `pct create` по SSH на узле PVE
# pve_lxc — роль roles/pve_lxc через Proxmox API
# unmanaged — создан вручную, в репозитории нет плейбука
# lxc ресурсы и параметры контейнера (as-created)
# ports опубликованные порты сервиса
# images закреплённые образы с digest (пустой список — образ не
# используется или собирается локально)
# backup pbs / restic / none — фактическая схема из pve-backup-jobs.yml
# и offsite-restic-yadisk.yml
# monitoring node_exporter — состоит ли хост в группе monitoring_exporters;
# blackbox — пробится ли снаружи из roles/monitoring_blackbox
# proxy присутствует только у сервисов с публичным доменом
# ============================================================================
# Хост, на котором стоит Caddy и терминируется публичный HTTPS.
homelab_reverse_proxy_host: ru-vps
homelab_reverse_proxy_dir: /opt/services/ru-vps/caddy
homelab_reverse_proxy_caddyfile: /opt/services/ru-vps/caddy/Caddyfile
homelab_reverse_proxy_container: caddy
# Стек Caddy разворачивает playbooks/ru-vps-base.yml (роль compose_service).
# Содержимое Caddyfile принадлежит playbooks/reverse-proxy.yml — ru-vps-base
# его не трогает, только проверяет наличие.
# Образ закреплён по digest: до принятия в Ansible на ru-vps крутился
# floating-тег caddy:2-alpine (на момент фиксации — v2.11.4).
homelab_reverse_proxy_image: >-
caddy:2-alpine@sha256:5f5c8640aae01df9654968d946d8f1a56c497f1dd5c5cda4cf95ab7c14d58648
# Systemd-юнит намеренно называется homelab-caddy, а не caddy: на ru-vps уже
# есть отключённый caddy.service от APT-пакета, и одноимённый unit в
# /etc/systemd/system его бы затенил.
homelab_reverse_proxy_unit: homelab-caddy
# Адрес центрального хоста мониторинга (источник scrape для node-exporter).
homelab_monitoring_host_ip: 192.168.1.30
# --- Дашборд-обзор инфраструктуры (Homepage, gethomepage.dev) ----------------
# Потребитель реестра: playbooks/dashboard.yml рендерит services.yaml из
# homelab_services (плитка на сервис, ссылка на его UI, группировка по узлу).
# Живёт compose-стеком на LXC monitoring рядом с Uptime Kuma; наружу НЕ
# публикуется — доступ только из LAN и по OpenVPN.
homelab_dashboard_host: monitoring
homelab_dashboard_dir: /opt/homepage
homelab_dashboard_bind_ip: 192.168.1.30
# Порт на хосте: 3000 в модели реестра занят замороженной Grafana, 3001 —
# Uptime Kuma, поэтому Homepage слушает 8082 -> контейнерный 3000.
homelab_dashboard_port: 8082
# Образ закреплён по digest (закреплён 2026-09-03 после первого pull на CT 155).
# Обновление: docker pull <новый тег> на monitoring, взять digest
# docker inspect --format '{{ index .RepoDigests 0 }}' <image>
# и вписать сюда. playbooks/dashboard.yml падает на assert'е без @sha256
# (разовый обход — `-e dashboard_allow_floating_tag=true`).
homelab_dashboard_image: >-
ghcr.io/gethomepage/homepage:v2.2.0@sha256:753eeb0cc22ab7baad39ed47cbd1aae14e193dd1b264e965f193a9ea1d1e1bdd
# HOMEPAGE_ALLOWED_HOSTS: Homepage >=1.0 отклоняет запросы с прочих Host-ов.
homelab_dashboard_allowed_hosts: "192.168.1.30:8082"
# Виджет proxmox: URL любого узла кластера (без node: -> среднее по кластеру).
# Секрет — read-only токен homepage@pve!dashboard (роль PVEAuditor), выпускается
# playbooks/bootstrap-dashboard-pve-token.yml в корневой .env как DASHBOARD_PVE_*.
# Пустой URL -> плитка Proxmox не рендерится.
homelab_dashboard_proxmox_url: "https://192.168.1.10:8006"
# slug опубликованной Status Page в Uptime Kuma для виджета сводки up/down
# (мониторы и статус-страницы Kuma живут только в её UI — их тут не завести).
homelab_dashboard_kuma_slug: homelab
homelab_services:
# --------------------------------------------------------------------------
pbs:
vmid: 120
node: cloud-pc
ip: 192.168.1.20
hostname: pbs
role: Proxmox Backup Server
provisioner: unmanaged # плейбука создания в репозитории нет
lxc:
cores: null # нет в коде
memory: null # нет в коде
swap: null # нет в коде
disk: null # нет в коде
startup: null # нет в коде
features: null # нет в коде
unprivileged: null # нет в коде
ports:
- {name: pbs-api, port: 8007, proto: tcp} # стандартный порт PBS
images: []
backup:
kind: pbs-local
# pve-backup-jobs.yml: job homelab-local-weekly-pbs, хранилище "backup"
job: homelab-local-weekly-pbs
schedule: "Sun 03:30"
storage: backup
prune: keep-last=2
monitoring:
node_exporter: true
blackbox: false
backup_audit_vmid: false # 120 отсутствует в backup_audit_pbs_vmids
# --------------------------------------------------------------------------
ovpn-mini:
vmid: 160
node: mini-pc
ip: 192.168.1.23
hostname: ovpn-mini
role: OpenVPN-шлюз в LAN (клиент ru-vps)
provisioner: tofu # tofu/svc-ovpn-mini.tf, переезд 2026-09-03 (migration-tofu.md)
lxc:
cores: 1
memory: 256
swap: 128
disk: local-lvm:8
startup: order=30
features: "nesting=1" # keyctl/fuse намеренно не заданы
unprivileged: true
# /dev/net/tun — блок device_passthrough в Tofu (dev0: path=/dev/net/tun)
# вместо прежних сырых lxc.* строк из pve-ovpn-mini.yml. Эффект тот же.
devices: ["/dev/net/tun"]
ports:
- {name: openvpn, port: 8443, proto: tcp, note: "туннель к ru-vps 10.78.0.1"}
images: []
backup:
kind: pbs
job: homelab-pbs-daily-mini
schedule: "02:40"
storage: pbs
monitoring:
node_exporter: true
blackbox: false
backup_audit_vmid: true
# --------------------------------------------------------------------------
vaultwarden:
vmid: 154
node: mini-pc
ip: 192.168.1.24
hostname: vaultwarden
role: Менеджер паролей Vaultwarden
provisioner: tofu # tofu/svc-vaultwarden.tf, переезд 2026-09-02 (migration-tofu.md)
lxc:
cores: 2
memory: 1024
swap: 512
disk: local-lvm:16
startup: order=40
# fuse=1 — штатный флаг PVE вместо прежнего обхода сырыми lxc.* строками.
features: "fuse=1,keyctl=1,nesting=1"
unprivileged: true
ostemplate: local:vztmpl/debian-13-standard_13.1-2_amd64.tar.zst
devices: ["/dev/fuse"]
data_dir: /opt/vaultwarden/data
ports:
- {name: http, port: 80, proto: tcp}
images:
- vaultwarden/server:1.37.1@sha256:e9efdf001bf0d68c21f2cbfb8e1d9b5961a7ca9c85e0a7e58bf51a13b997d744
runtime: docker-run-systemd # /etc/systemd/system/vaultwarden.service
backup:
kind: pbs+restic
job: homelab-pbs-daily-mini
schedule: "02:40"
storage: pbs
restic:
profile: vaultwarden
repository: rclone:yadisk:System/Backups/HomeLab/restic/vaultwarden
source_path: /opt/vaultwarden/data
schedule: "*-*-* 04:45:00"
sqlite_db: /opt/vaultwarden/data/db.sqlite3
monitoring:
node_exporter: true
blackbox: true
backup_audit_vmid: true
proxy:
domain: pass.ada-dev.ru
upstream: 192.168.1.24:80
caddy_marker: "# {mark} ANSIBLE MANAGED VAULTWARDEN SITE"
# caddy_body не задан -> используется простой `reverse_proxy <upstream>`
caddy_container_check: "reverse_proxy 192.168.1.24:80"
# Устаревшая секция от миграции с 10.122.62.95. Удалить это поле
# можно после подтверждённого прогона reverse-proxy.yml на ru-vps.
caddy_legacy_regexp: '(?ms)^pass\.ada-dev\.ru \{\n\s*reverse_proxy 10\.122\.62\.95:10380\n\}\n+'
health:
path: /
status_code: [200]
follow_redirects: none # соответствует `curl -fsS` без -L в старом плейбуке
# --------------------------------------------------------------------------
gitea:
vmid: 153
node: cloud-pc
ip: 192.168.1.25
hostname: gitea
role: Git-хостинг Gitea
provisioner: tofu # tofu/svc-gitea.tf, переезд 2026-09-02 (migration-tofu.md)
lxc:
cores: 2
memory: 2048
swap: 1024
disk: data:32
startup: order=50
# fuse=1 — штатный флаг PVE вместо прежнего обхода сырыми lxc.* строками.
features: "fuse=1,keyctl=1,nesting=1"
unprivileged: true
ostemplate: local:vztmpl/debian-13-standard_13.1-2_amd64.tar.zst
devices: ["/dev/fuse"]
mounts:
# Был bind mount каталога ноды /opt/data/gitea. С переезда 2026-09-02 —
# независимый volume на datastore: mp0 data:153/vm-153-disk-1.raw.
# Побочный выигрыш: bind mount vzdump ИСКЛЮЧАЛ из бэкапа ("not a
# volume"), то есть данные gitea в PBS никогда не попадали. Volume
# попадает.
- {volume: data, size: 32G, container_path: /opt/gitea/data}
data_dir: /opt/gitea/data
ports:
- {name: http, port: 3000, proto: tcp}
- {name: ssh, port: 2222, proto: tcp, container_port: 22}
images:
- gitea/gitea:1.27.1@sha256:b64126cf5c3f4e5f0f231b510bb13715f6cb8e508188b44de90bdb9a04f3055d
runtime: docker-run-systemd # /etc/systemd/system/gitea.service
backup:
kind: pbs+restic
job: homelab-pbs-daily-cloud
schedule: "02:10"
storage: pbs
restic:
profile: gitea
# С переезда 2026-09-02 профиль выполняется ВНУТРИ LXC, как у
# vaultwarden: пути ноды больше не существуют, данные в volume.
run_on: gitea
repository: rclone:yadisk:System/Backups/HomeLab/restic/gitea
source_path: /opt/gitea/data
schedule: "*-*-* 04:15:00"
sqlite_db: /opt/gitea/data/gitea/gitea.db
monitoring:
node_exporter: true
blackbox: true
backup_audit_vmid: true
proxy:
domain: git.ada-dev.ru
upstream: 192.168.1.25:3000
caddy_marker: "# {mark} ANSIBLE MANAGED GITEA SITE"
caddy_container_check: "reverse_proxy 192.168.1.25:3000"
# Устаревшая секция от миграции с 10.122.62.51. Удалить это поле
# можно после подтверждённого прогона reverse-proxy.yml на ru-vps.
caddy_legacy_regexp: '(?ms)^git\.ada-dev\.ru \{\n\s*reverse_proxy 10\.122\.62\.51:3002\n\}\n+'
health:
path: /
status_code: [200]
follow_redirects: none # соответствует `curl -fsS` без -L в старом плейбуке
# --------------------------------------------------------------------------
mihomo:
vmid: 159
node: mini-pc
ip: 192.168.1.27
hostname: mihomo
role: Локальный прокси Mihomo + веб-интерфейс MetaCubeXD
provisioner: tofu # tofu/svc-mihomo.tf, переезд 2026-09-03 (migration-tofu.md)
lxc:
cores: 1
memory: 512
swap: 512
disk: local-lvm:8
startup: order=70
# fuse=1 — штатный флаг PVE вместо прежнего обхода сырыми lxc.* строками.
# /dev/net/tun — блок device_passthrough в Tofu (dev0: path=/dev/net/tun),
# тоже вместо сырых lxc.* строк. Эффект тот же, запись в pct config иная.
features: "fuse=1,keyctl=1,nesting=1"
unprivileged: true
ostemplate: local:vztmpl/debian-13-standard_13.1-2_amd64.tar.zst
devices: ["/dev/fuse", "/dev/net/tun"]
data_dir: /opt/mihomo
ports:
- {name: mixed, port: 7890, proto: tcp}
- {name: socks, port: 7891, proto: tcp}
- {name: controller, port: 9090, proto: tcp}
- {name: ui, port: 8080, proto: tcp, container_port: 80}
images:
- metacubex/mihomo:v1.19.29@sha256:5e7bcc5e7a866afcc8b007ef827c9ba773f2f34b6d7311b6d39ed1751f37cfd5
- ghcr.io/metacubex/metacubexd:v1.270.6@sha256:156d55be885d4ba6254d840bd781b715c20c00afee6e6c24c76be4cfe5eb89d4
runtime: docker-run-systemd # mihomo.service + mihomo-ui.service
backup:
kind: pbs
job: homelab-pbs-daily-mini
schedule: "02:40"
storage: pbs
monitoring:
node_exporter: true
blackbox: false
backup_audit_vmid: true
# --------------------------------------------------------------------------
adguard:
vmid: 158
node: mini-pc
ip: 192.168.1.28
hostname: adguard
role: AdGuard Home — DNS с фильтрацией
provisioner: tofu # tofu/svc-adguard.tf, переезд 2026-09-03 (migration-tofu.md)
lxc:
cores: 1
memory: 512
swap: 512
disk: local-lvm:8
startup: order=40
# fuse=1 — штатный флаг PVE вместо прежнего обхода сырыми lxc.* строками
# (lineinfile по /etc/pve/lxc/144.conf в pve-adguard.yml). Эффект тот же.
features: "fuse=1,keyctl=1,nesting=1"
unprivileged: true
ostemplate: local:vztmpl/debian-13-standard_13.1-2_amd64.tar.zst
devices: ["/dev/fuse"]
data_dir: /opt/adguard
ports:
- {name: dns-tcp, port: 53, proto: tcp}
- {name: dns-udp, port: 53, proto: udp}
- {name: http, port: 80, proto: tcp}
- {name: setup, port: 3000, proto: tcp}
images:
- adguard/adguardhome:v0.107.78@sha256:2c127294fa5f96151d9d3a433fb9d66c17e4d18cf698c2b04372a80e26fdd26f
runtime: docker-run-systemd # /etc/systemd/system/adguard.service
backup:
kind: pbs
job: homelab-pbs-daily-mini
schedule: "02:40"
storage: pbs
monitoring:
node_exporter: true
blackbox: false
backup_audit_vmid: true
# --------------------------------------------------------------------------
docker-test:
vmid: 152
node: cloud-pc
ip: 192.168.1.29
hostname: docker-test
role: Песочница для проверки Docker в непривилегированном LXC
provisioner: tofu # tofu/svc-docker-test.tf, переезд 2026-09-02 (migration-tofu.md)
lxc:
cores: 1
memory: 512
swap: 512
disk: data:8
startup: order=50
# fuse=1 появился после переезда на Tofu: раньше /dev/fuse пробрасывался
# сырыми lxc.* строками через lineinfile, теперь это штатный флаг PVE.
# Эффект тот же, запись в pct config другая.
features: "fuse=1,keyctl=1,nesting=1"
unprivileged: true
ostemplate: local:vztmpl/debian-13-standard_13.1-2_amd64.tar.zst
devices: ["/dev/fuse"]
ports: []
images: [] # используется только hello-world для smoke-теста
backup:
kind: pbs
job: homelab-pbs-daily-cloud
schedule: "02:10"
storage: pbs
monitoring:
node_exporter: false # хоста нет в группе monitoring_exporters
blackbox: false
backup_audit_vmid: true
# --------------------------------------------------------------------------
monitoring:
vmid: 155
node: cloud-pc
ip: 192.168.1.30
hostname: monitoring
# До переезда 2026-09-02 контейнер нёс ещё и замороженный стек
# Prometheus/Alertmanager/Grafana/blackbox/pve-exporter. В новый контейнер
# он сознательно не разворачивался (migration-tofu.md, п.5.5), поэтому
# фактически здесь работает только Uptime Kuma. Возврат стека — отдельное
# architecture decision, см. legacy-warning.md.
role: Uptime Kuma (замороженный стек Prometheus больше не развёрнут)
provisioner: tofu # tofu/svc-monitoring.tf, переезд 2026-09-02 (migration-tofu.md)
lxc:
cores: 2
memory: 4096
swap: 512
disk: data:24
# Ресурсы оставлены как были, под замороженный стек. Фактическое
# потребление после переезда — 184 МБ RAM и 1.8 ГБ диска. Уменьшение —
# отдельное решение, не часть переезда.
startup: order=80
features: "keyctl=1,nesting=1"
unprivileged: true
ostemplate: local:vztmpl/debian-13-standard_13.1-2_amd64.tar.zst
# Данные Uptime Kuma лежат в /opt/uptime-kuma, а НЕ в /opt/monitoring:
# последний принадлежал замороженному стеку и на новом контейнере
# отсутствует.
data_dir: /opt/uptime-kuma
ports:
- {name: grafana, port: 3000, proto: tcp, bind: 192.168.1.30}
- {name: pushgateway, port: 9091, proto: tcp, bind: 192.168.1.30}
- {name: uptime-kuma, port: 3001, proto: tcp, bind: 192.168.1.30}
images:
# без digest — так закреплено в roles/monitoring_server/templates/compose.yml.j2
- prom/prometheus:v3.2.1
- prom/alertmanager:v0.28.0
- grafana/grafana:11.5.1
- prom/blackbox-exporter:v0.25.0
- prompve/prometheus-pve-exporter:3.5.5
- prom/pushgateway:v1.11.0
- louislam/uptime-kuma:1.23.16@sha256:431fee3be822b04861cf0e35daf4beef6b7cb37391c5f26c3ad6e12ce280fe18
runtime: docker-compose-systemd
backup:
kind: pbs
job: homelab-pbs-daily-cloud
schedule: "02:10"
storage: pbs
monitoring:
node_exporter: true
blackbox: false
backup_audit_vmid: true
# --------------------------------------------------------------------------
hermes-ai:
vmid: 147
node: cloud-pc
ip: 192.168.1.31
hostname: hermes-ai
role: Хост под приложение Hermes + прозрачный TUN-прокси через mihomo
provisioner: pct_ssh # playbooks/pve-hermes-ai.yml
lxc:
cores: 2
memory: 4096
swap: 512
disk: data:24
startup: order=90
features: "nesting=1,keyctl=1"
unprivileged: true
ostemplate: local:vztmpl/debian-13-standard_13.1-2_amd64.tar.zst
devices: ["/dev/fuse", "/dev/net/tun"]
data_dir: /srv/hermes-ai
ports: [] # публикация портов запрещена: Docker обходит UFW
images:
- metacubex/mihomo@sha256:e6acd921addecfd59a8e2d38203f88356d635b54de6c0673db0e015139989312
runtime: docker-run-systemd # hermes-ai-tun-proxy.service
backup:
kind: pbs
job: homelab-pbs-daily-cloud
schedule: "02:10"
storage: pbs
monitoring:
node_exporter: false # хоста нет в группе monitoring_exporters
blackbox: false
backup_audit_vmid: true
# --------------------------------------------------------------------------
emergency-bot:
vmid: 151
node: mini-pc
ip: 192.168.1.32
hostname: emergency-bot
role: Telegram-бот аварийного доступа
provisioner: tofu # tofu/services.tf, переезд 2026-09-02 (migration-tofu.md)
lxc:
cores: 1
memory: 512
swap: 256
disk: local-lvm:4
startup: order=70
features: "nesting=1" # из roles/pve_lxc/defaults
unprivileged: true
ostemplate: local:vztmpl/debian-13-standard_13.1-2_amd64.tar.zst
ports: []
images: [] # роль emergency_bot образы не закрепляет
backup:
kind: none # VMID 148 отсутствует в pve-backup-jobs.yml — бэкапа нет
monitoring:
node_exporter: false # хоста нет в группе monitoring_exporters
blackbox: false
backup_audit_vmid: false
# --------------------------------------------------------------------------
grimmory:
vmid: 157
node: cloud-pc
ip: 192.168.1.34
hostname: grimmory
role: Библиотека книг Grimmory (+ MariaDB), OPDS/KOReader
provisioner: tofu # tofu/svc-grimmory.tf, переезд 2026-09-02 (migration-tofu.md)
lxc:
cores: 2
memory: 4096
swap: 1024
disk: data:64
startup: order=100
# fuse=1 — штатный флаг PVE вместо прежнего обхода сырыми lxc.* строками.
features: "fuse=1,keyctl=1,nesting=1"
unprivileged: true
ostemplate: local:vztmpl/debian-13-standard_13.1-2_amd64.tar.zst
devices: ["/dev/fuse"]
data_dir: /opt/grimmory
ports:
- {name: http, port: 6060, proto: tcp, bind: 192.168.1.34}
images:
- grimmory/grimmory:v3.2.4@sha256:dfa7afdfcf25d649fd664497a62385dd00cd9678c37546e182c172e41c8e80cb
- lscr.io/linuxserver/mariadb:11.4.8@sha256:91de7f701bc7fc3a424b81beafca7a7c6c4c5b7c8be6afd2ae148698695c0b0c
runtime: docker-compose-systemd # grimmory.service + grimmory-docker-firewall.service
backup:
kind: pbs+restic
job: homelab-pbs-daily-cloud
schedule: "02:10"
storage: pbs
restic:
profile: grimmory
repository: rclone:yadisk:System/Backups/HomeLab/restic/grimmory
source_path: /opt/grimmory
schedule: "*-*-* 05:15:00"
mariadb_container: grimmory-mariadb
mariadb_database: grimmory
monitoring:
node_exporter: true
blackbox: true
backup_audit_vmid: true
proxy:
domain: books.ada-dev.ru
upstream: 192.168.1.34:6060
caddy_marker: "# {mark} ANSIBLE MANAGED GRIMMORY SITE"
# Тело секции Caddy целиком: OPDS/KOReader требуют отключить сжатие
# и принудительно выставить Accept, иначе читалки не понимают ответ.
# Апстрим в теле обязан совпадать с полем `upstream` выше —
# reverse-proxy.yml это проверяет assert'ом.
caddy_body: |
@grimmory_opds_atom path /api/v1/opds /api/v1/opds/libraries /api/v1/opds/shelves /api/v1/opds/magic-shelves /api/v1/opds/authors /api/v1/opds/series /api/v1/opds/catalog /api/v1/opds/recent /api/v1/opds/surprise
handle @grimmory_opds_atom {
reverse_proxy 192.168.1.34:6060 {
header_up Accept "application/atom+xml"
header_up Accept-Encoding identity
transport http {
compression off
}
}
}
@grimmory_opds_search path /api/v1/opds/search.opds
handle @grimmory_opds_search {
reverse_proxy 192.168.1.34:6060 {
header_up Accept "application/opensearchdescription+xml"
header_up Accept-Encoding identity
transport http {
compression off
}
}
}
@grimmory_device_api path /api/koreader /api/koreader/* /api/v1/opds /api/v1/opds/*
handle @grimmory_device_api {
reverse_proxy 192.168.1.34:6060 {
header_up Accept-Encoding identity
transport http {
compression off
}
}
}
handle {
reverse_proxy 192.168.1.34:6060
}
# Проверка бинд-маунта внутри контейнера caddy: у grimmory ищем маркер
# маршрутизации, а не строку reverse_proxy — она встречается многократно.
caddy_container_check: "@grimmory_device_api path /api/koreader"
# caddy_legacy_regexp отсутствует: в старом reverse-proxy-grimmory.yml
# секции удаления legacy-конфига не было.
health:
path: /api/v1/healthcheck
status_code: [200]
follow_redirects: safe # поведение ansible.builtin.uri по умолчанию
# --------------------------------------------------------------------------
gyro:
vmid: 156
node: mini-pc
ip: 192.168.1.35
hostname: gyro
role: Изолированный контейнер под задачу gyro (доступ в сеть только через mihomo)
provisioner: tofu # tofu/svc-gyro.tf
lxc:
cores: 1
memory: 512
swap: 256
disk: local-lvm:2
startup: order=80
features: "" # pve_lxc_features: [] — nesting отключён намеренно
unprivileged: true
ostemplate: local:vztmpl/debian-13-standard_13.1-2_amd64.tar.zst
firewall: proxmox # /etc/pve/firewall/156.fw, policy_in DROP
ports: []
images: [] # роль gyro образы не закрепляет
backup:
kind: pbs
job: homelab-pbs-daily-mini
schedule: "02:40"
storage: pbs
monitoring:
node_exporter: false # хоста нет в группе monitoring_exporters
blackbox: false
backup_audit_vmid: true