| README.md | ||
Журнал настройки отказоустойчивого Traefik
Дата работ: 2026-08-01.
Обозначения: pve — 192.168.1.10, pve01 — 192.168.1.13.
Секреты, SSH-ключи и пароль VRRP намеренно заменены на <redacted>.
Итоговая схема
| Роль | Узел | LXC | Реальный IP | Состояние на момент журнала |
|---|---|---|---|---|
| Active | pve |
301 traefik |
192.168.1.98 |
Traefik + keepalived active, владеет VIP |
| Standby | pve01 |
301 traefik |
192.168.1.71 |
keepalived active, Traefik stopped |
| VIP | — | — | 192.168.1.9 |
TCP 80/443 с роутера направлены на него |
1. Обнаружение основного узла
Первое подключение по имени не сработало:
$ ssh -o BatchMode=yes pve '...'
ssh: Could not resolve hostname pve: nodename nor servname provided, or not known
$ ssh -o BatchMode=yes pve.home '...'
ssh: Could not resolve hostname pve.home: nodename nor servname provided, or not known
Из SSH-конфигурации и known_hosts определён адрес pve.home: 192.168.1.10:22933.
ssh -p 22933 -o BatchMode=yes root@192.168.1.10 \
'hostname; pveversion --verbose | head -3; ip -brief address; pct list; qm list'
Ключевой вывод:
pve
proxmox-ve: 9.2.0
pve-manager: 9.2.6
vmbr0 UP 192.168.1.10/24
VMID 301 running traefik
2. Инвентаризация действующего Traefik
ssh -p 22933 root@192.168.1.10 \
'pct config 301; pct exec 301 -- sh -lc "ip -brief address; systemctl status traefik; traefik version"'
Результат:
LXC 301:
hostname: traefik
net0: ... bridge=vmbr0, ip=dhcp
memory: 2048 MB
rootfs: 4G
onboot: 1
IP LXC: 192.168.1.98/24
Traefik: active (running)
Version: 3.7.9
Проверены конфигурация и маршруты:
pct exec 301 -- sed -E '/(token|secret|password|apikey|email)/I s/:.*/: <redacted>/' \
/etc/traefik/traefik.yaml
pct exec 301 -- grep -RHE '^[[:space:]-]*url:' /etc/traefik/conf.d
Установлено:
- файловый provider:
/etc/traefik/conf.d/; - ACME TLS challenge, хранилище:
/etc/traefik/ssl/acme.json; - CrowdSec bouncer подключается к
127.0.0.1:8080; - Traefik зависит от
crowdsec.serviceчерез systemd drop-in; - около 20 маршрутов на сервисы в локальной сети.
Проверена существующая схема keepalived у AdGuard:
AdGuard primary: 192.168.1.11
AdGuard VIP: 192.168.1.8
keepalived: active
virtual_router_id: 42
Для Traefik выбран независимый VRID 43.
3. Обнаружение и доступ к pve01
На pve выполнено:
getent hosts pve01 pve01.home
Вывод:
192.168.1.13 pve01
SSH на 22/tcp был закрыт, на 22933/tcp доступен. После добавления пользователем публичного ключа:
ssh -p 22933 -o BatchMode=yes root@192.168.1.13 \
'hostname; pveversion --verbose | head -3; ip -brief address; pct list; pvesm status'
Ключевой вывод:
pve01
vmbr0 UP 192.168.1.13/24
ОЗУ доступно: ~29 GiB
local: доступно ~34 GiB
PBS и synology_nfs: active
4. Резервная копия и перенос LXC
Попытка использовать NFS как backup storage:
vzdump 301 --storage synology_nfs --mode snapshot --compress zstd
Ошибка:
can't use storage 'synology_nfs' for backups - wrong content type
Успешная резервная копия в PBS:
vzdump 301 --storage backup --mode snapshot --compress zstd \
--notes-template 'HA standby seed for pve01'
Ключевой вывод:
Starting Backup of VM 301 (lxc)
root.pxar: reused 4.179 GiB (94.3%)
uploaded: 78.792 MiB
Finished Backup of VM 301
PBS snapshot: ct/301/2026-08-01T06:48:06Z
Первое восстановление с исходным диском 4 GiB:
pct restore 301 pbs:backup/ct/301/2026-08-01T06:48:06Z \
--storage local --unique 1 --start 0
Ошибка из task log:
failed to extract file ... journal:
No space left on device (os error 28)
Остаток был проверен (/var/lib/lxc/301, 8 KiB, конфигурация LXC отсутствовала) и удалён. Повторное восстановление:
rm -rf /var/lib/lxc/301
pct restore 301 pbs:backup/ct/301/2026-08-01T06:48:06Z \
--storage local --rootfs local:8 --unique 1 --start 0
pct set 301 --onboot 0
Успешный результат:
LXC 301 restored on pve01
rootfs: local:301/vm-301-disk-0.raw,size=8G
MAC: BC:24:11:D8:A3:16
Перед первым запуском резервного LXC Traefik был выключен офлайн:
unlink /var/lib/lxc/301/rootfs/etc/systemd/system/multi-user.target.wants/traefik.service
pct start 301
Полученный DHCP адрес резервного LXC:
192.168.1.71/24
5. Установка зависимостей
Команда обновления списка пакетов выявила уже существующую проблему:
https://packagecloud.io/crowdsec/crowdsec/debian trixie Release
404 Not Found
Репозиторий не изменялся. Установка из доступного Debian-кэша успешно выполнена на обоих LXC:
apt-get install -y keepalived rsync
Установлены:
keepalived 2.3.3-1
rsync 3.4.1+ds1-5+deb13u4
ipvsadm и зависимости
6. Конфигурация VIP и health-check
На обоих LXC созданы:
/etc/keepalived/keepalived.conf
/usr/local/sbin/check-traefik.sh
/usr/local/sbin/traefik-ha-state.sh
Основные параметры конфигурации:
VIP: 192.168.1.9/24
VRID: 43
advert_int: 1
pve priority: 150
pve01 priority: 100
unicast peers: 192.168.1.98 <-> 192.168.1.71
nopreempt: включён
health weight: -60
Health-check в финальном виде:
#!/bin/sh
set -eu
/usr/bin/systemctl is-active --quiet traefik
/usr/bin/curl -fsS --max-time 2 -o /dev/null http://127.0.0.1/
Скрипт состояния:
master -> systemctl start traefik
backup/fault -> systemctl stop traefik
Допущена и исправлена ошибка первой доставки: файлы были кратко записаны на хосты Proxmox вместо LXC. keepalived на хостах был inactive и VIP не назначался. Созданные файлы были удалены, затем конфигурация записана корректно через pct exec 301.
Проверка синтаксиса:
keepalived -t -f /etc/keepalived/keepalived.conf
Результат: код возврата 0 на обоих LXC.
7. Активация keepalived
На primary:
systemctl enable --now keepalived
Ключевой вывод:
eth0: 192.168.1.98/24 192.168.1.9/24
keepalived: active
Traefik: active
На standby:
systemctl enable --now keepalived
Ключевой вывод:
eth0: 192.168.1.71/24
keepalived: active
Traefik: inactive
Локальная проверка VIP:
curl -ksS --resolve pve.qubo.su:443:192.168.1.9 https://pve.qubo.su/
Вывод:
VIP HTTPS pve.qubo.su: 200
8. Синхронизация конфигурации и сертификатов
На каждом LXC создан выделенный SSH-ключ синхронизации; публичный ключ второго LXC добавлен в /root/.ssh/authorized_keys первого. Приватные ключи не выводились.
На обоих LXC созданы:
/usr/local/sbin/sync-traefik-standby.sh
/etc/systemd/system/traefik-standby-sync.service
/etc/systemd/system/traefik-standby-sync.timer
Таймер запускается раз в две минуты. Скрипт сначала проверяет, владеет ли локальный LXC VIP 192.168.1.9; только активный узел синхронизирует:
/etc/traefik/conf.d/
/etc/traefik/traefik.yaml
/etc/traefik/ssl/acme.json
Текущая схема двунаправленная по роли: кто владеет VIP, тот отправляет состояние на второй LXC. Это предотвращает параллельное обновление ACME.
9. Сетевые изменения, выполненные пользователем
Пользователь подтвердил и выполнил:
VIP: 192.168.1.9
TCP 80 -> 192.168.1.9:80
TCP 443 -> 192.168.1.9:443
DHCP reservation:
192.168.1.98 -> BC:24:11:AC:25:91
192.168.1.71 -> BC:24:11:D8:A3:16
Проверка через публичное имя:
curl -ksS -o /dev/null -w 'Public DNS HTTPS status: %{http_code}\n' https://pve.qubo.su/
Вывод:
Public DNS HTTPS status: 200
10. Контролируемый failover
Тест перехода pve -> pve01:
# на pve, внутри LXC 301
systemctl stop keepalived
Через ~7 секунд на pve01:
inet 192.168.1.9/24 ... proto keepalived
keepalived: active
Traefik: active
Keepalived: Entering MASTER STATE
Traefik health-check: succeeded
Внешняя проверка после перехода:
Public DNS HTTPS after failover: 200
После этого pve возвращён в standby, обратная синхронизация принудительно проверена с активного pve01.
11. Контролируемый failback на pve
По запросу пользователя выполнено:
# на pve01, внутри LXC 301
systemctl stop keepalived
# после захвата VIP pve
# на pve01, внутри LXC 301
systemctl start keepalived
Финальные проверки:
pve:
192.168.1.9 назначен
keepalived active
traefik active
pve01:
VIP отсутствует
keepalived active
traefik inactive
Public DNS HTTPS final: 200
Автозапуск обеих LXC включён:
pve LXC 301: onboot: 1
pve01 LXC 301: onboot: 1
12. Проверка CrowdSec после клонирования
Команда на обоих LXC:
systemctl is-active crowdsec traefik
ss -ltn | grep ':8080'
cscli console status
cscli metrics
Итог:
pve:
crowdsec active
traefik active
LAPI 127.0.0.1:8080 listening
bouncer обновляет decision stream раз в минуту
pve01:
crowdsec active
traefik inactive, потому что standby
LAPI 127.0.0.1:8080 listening
во время failover Traefik+bouncer работали корректно
Выявлен нюанс клонирования:
/etc/machine-id на pve: 1b6954d643b04911be2a413da2139804
/etc/machine-id на pve01: 1b6954d643b04911be2a413da2139804
Поэтому CrowdSec Console сейчас видит оба LXC как один агент. Для раздельной статистики и независимой идентичности pve01 нужно отдельно переинициализировать и зарегистрировать в CrowdSec Console.