Files
DmitryandClaude Sonnet 5 a3fe8031fe feat: migrate all managed LXC provisioning to OpenTofu (blue-green)
Blue-green: a new container is created beside the old one, data is copied, the
IP is moved onto it, and the old container is kept stopped as rollback for at
least a week. Keeping the IP means only the VMID changes, and its consumers
(backup jobs, backup audit) already derive it from the registry.

Batch 1 (2026-09-02): emergency-bot 148->151, docker-test 145->152,
gitea 141->153, vaultwarden 140->154, monitoring 146->155, gyro 150->156,
grimmory 149->157.
Batch 2 (2026-09-03): adguard 144->158, mihomo 143->159, ovpn-mini 132->160.
All migratable LXC are now provisioner: tofu. hermes-ai (frozen) and pbs stay.

- tofu/services.tf + tofu/svc-*.tf: one resource per service, reproducing the
  pct-config etalon. /dev/fuse -> features.fuse; /dev/net/tun ->
  device_passthrough (first live use on mihomo and ovpn-mini); gitea bind mount
  -> datastore volume (data finally reaches PBS); console { type = "shell" }
  declared explicitly (provider tracks cmode there).
- services.yml: vmid + provisioner: tofu for every migrated service; features
  strings and device notes updated to the tofu representation; also drops the
  memoir-bot entry and adds homelab_reverse_proxy_image/_unit.
- pve-*.yml: configuration play target is `{{ pve_config_target | default(...) }}`
  so it can run against <name>-new on a temp address (a bare --limit zeroes the
  play instead of retargeting it). Container-creation plays are gated behind
  `provisioner != 'tofu'` / `pve_provisioning_enabled` (meta: end_play), so a
  stray run cannot pct start a stopped OLD VMID on a live IP. Override for
  intentional legacy rollback: -e pve_<svc>_legacy_provisioning_enabled=true.
- ssh_config: drop memoir-bot; ovpn-mini gets ProxyJump none (a jump via ru-vps
  would route through the very tunnel ovpn-mini terminates).
- gyro.yml / uptime-kuma.yml: same pve_config_target override.
- roles/uptime_kuma: only freeze homelab-monitoring when the unit actually
  exists (a fresh blue-green container never had it).
- offsite-restic-yadisk.yml: the gitea restic profile now runs inside the LXC
  (hosts: gitea), since the bind-mount host path is gone after the volume move;
  lost+found excluded (unreadable in an unprivileged LXC, restic exit 3).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012uoq5AVK8mkBgg83Mq6o5V
2026-09-03 07:05:46 +03:00

115 lines
6.6 KiB
Plaintext
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 SSH config — единый источник правды по SSH-доступу
#
# Файл управляется репозиторием infras. Правь его здесь, а не в ~/.ssh/.
#
# Как подключить (один раз), первой строкой ~/.ssh/config:
#
# Include /home/ada/Documents/Projects/HomeLab/infras/ansible/ssh_config
#
# После этого из обычного терминала работает: ssh gitea, ssh pbs, ssh cloud-pc
#
# SSH берёт ПЕРВОЕ найденное значение опции, поэтому:
# - Include в начале ~/.ssh/config -> побеждают настройки репозитория;
# - Include в конце ~/.ssh/config -> побеждают личные записи из config.d/*
# (личные vps/cloud-pc/mini-pc/pbs остаются под пользователем ada,
# а LXC-хосты всё равно резолвятся отсюда).
#
# Ansible использует этот же файл: ansible.cfg -> [ssh_connection] ssh_args
# содержит -F <абсолютный путь к этому файлу>. Поэтому каждая запись
# указана и по имени (ssh gitea), и по IP (Ansible ходит по ansible_host).
# ════════════════════════════════════════════════════════════════════════
# ── Jump host: публичная VPS ────────────────────────────────────────────
Host ru-vps vps 157.22.231.198
HostName 157.22.231.198
Port 3422
User ansible
IdentityFile ~/.ssh/id_ed25519_homelab_ansible
# ── Proxmox VE ноды (через ru-vps) ──────────────────────────────────────
Host cloud-pc 192.168.1.5
HostName 192.168.1.5
Host mini-pc 192.168.1.10
HostName 192.168.1.10
Host cloud-pc mini-pc 192.168.1.5 192.168.1.10
User ansible
IdentityFile ~/.ssh/id_ed25519_homelab_ansible
ProxyJump ru-vps
# ── LXC pbs и ovpn-mini ─────────────────────────────────────────────────
# pbs идёт через ProxyJump ru-vps (агрегированная строка ниже): вне LAN это
# его единственный путь, а `make check`/`status`/`backup-audit` иначе падали.
Host pbs 192.168.1.20
HostName 192.168.1.20
# ovpn-mini — ProxyJump none НАМЕРЕННО: путь через ru-vps шёл бы по туннелю,
# который сам ovpn-mini и терминирует. Пока туннель жив это работало, но при
# его реконфигурации (или переезде контейнера) транспорт закольцовывается на
# мёртвый туннель. Из LAN хост доступен напрямую; вне LAN управление —
# через консоль ноды (pct exec) или при заранее поднятом туннеле.
# Первая строка блока побеждает по правилу "первое значение опции".
Host ovpn-mini 192.168.1.23
HostName 192.168.1.23
ProxyJump none
# ── LXC за jump-хостом ──────────────────────────────────────────────────
Host vaultwarden 192.168.1.24
HostName 192.168.1.24
Host gitea 192.168.1.25
HostName 192.168.1.25
Host mihomo 192.168.1.27
HostName 192.168.1.27
Host adguard 192.168.1.28
HostName 192.168.1.28
Host docker-test 192.168.1.29
HostName 192.168.1.29
Host monitoring 192.168.1.30
HostName 192.168.1.30
Host hermes-ai 192.168.1.31
HostName 192.168.1.31
Host emergency-bot 192.168.1.32
HostName 192.168.1.32
Host grimmory 192.168.1.34
HostName 192.168.1.34
Host gyro 192.168.1.35
HostName 192.168.1.35
# ── Групповые опции. ssh_config не поддерживает перенос строк, поэтому
# списки паттернов длинные: имя хоста (для `ssh gitea`) + IP (Ansible
# подключается по ansible_host). ─────────────────────────────────────
# ProxyJump для всех LXC. ОСТОРОЖНО: путь до ovpn-mini идёт через туннель,
# который сам ovpn-mini и терминирует. Для чтения это безопасно, но
# playbooks/openvpn-vps-mini.yml вне LAN может оборвать себе транспорт на
# середине прогона — переконфигурацию OpenVPN выполняй из локальной сети.
Host pbs ovpn-mini vaultwarden gitea mihomo adguard docker-test monitoring hermes-ai emergency-bot grimmory gyro 192.168.1.20 192.168.1.23 192.168.1.24 192.168.1.25 192.168.1.27 192.168.1.28 192.168.1.29 192.168.1.30 192.168.1.31 192.168.1.32 192.168.1.34 192.168.1.35
ProxyJump ru-vps
# Все LXC — под root с ключом id_ed25519_homelab
Host pbs ovpn-mini vaultwarden gitea mihomo adguard docker-test monitoring hermes-ai emergency-bot grimmory gyro 192.168.1.20 192.168.1.23 192.168.1.24 192.168.1.25 192.168.1.27 192.168.1.28 192.168.1.29 192.168.1.30 192.168.1.31 192.168.1.32 192.168.1.34 192.168.1.35
User root
IdentityFile ~/.ssh/id_ed25519_homelab
# Общие опции для хостов HomeLab (намеренно не `Host *`, чтобы не влиять
# на остальные записи ~/.ssh/config пользователя)
Host ru-vps vps cloud-pc mini-pc pbs ovpn-mini vaultwarden gitea mihomo adguard docker-test monitoring hermes-ai emergency-bot grimmory gyro 157.22.231.198 192.168.1.5 192.168.1.10 192.168.1.20 192.168.1.23 192.168.1.24 192.168.1.25 192.168.1.27 192.168.1.28 192.168.1.29 192.168.1.30 192.168.1.31 192.168.1.32 192.168.1.34 192.168.1.35
IdentitiesOnly yes
StrictHostKeyChecking accept-new
ControlMaster auto
ControlPath ~/.ssh/sockets/%C
ControlPersist 60s
ServerAliveInterval 30
ServerAliveCountMax 3