
Пинг точки доступа не проверяет работу её радио. А отсутствие ответа не доказывает зависание: причиной может быть PoE, VLAN управления, uplink или отказ станции мониторинга. Правильный watchdog собирает несколько независимых сигналов, ограничивает число действий и сохраняет причину перезапуска. Ниже — пример для одной пилотной AP и выделенного Linux Wi-Fi-клиента.

1. Определите, что именно перестало работать
Что будем строить и какие адреса заменить
Нужны одна уже принятая в UniFi Network точка, станция мониторинга и Linux-пробник с двумя интерфейсами. Это три роли: монитор принимает решение; AP обслуживает радио; пробник воспроизводит путь реального клиента. Контроллер Network не запускает приведённый скрипт и не обязан находиться на мониторе. Проводное управление пробником необходимо, чтобы потеря Wi-Fi не оборвала канал получения результатов.
В лаборатории management VLAN 10 содержит AP 10.77.10.21, монитор 10.77.10.30 и eth0 пробника 10.77.10.31. Клиентский VLAN 20 содержит Wi-Fi пробника 10.77.20.31/24, шлюз 10.77.20.1 и SSID AVG-LAB. Между монитором и клиентским шлюзом разрешён контрольный ICMP, между монитором и двумя управляемыми устройствами — TCP 22. Это вымышленные частные адреса: сверяйте маршруты, чтобы не попасть в существующую сеть с такими же адресами.
Условия применимости: исправное проводное соединение, известный BSSID выбранного диапазона, контрольный шлюз отвечает на ICMP, SSH доступен, NetworkManager управляет wlan0. Станция с одним беспроводным интерфейсом не даёт независимого канала контроля. На рабочей площадке сначала выделите тестовый SSID/VLAN, чтобы упражнения с пакетными фильтрами не отключали сотрудников.
Снимите исходное состояние
ip -br address
ip route
nmcli device status
iw dev
ping -c 3 10.77.20.1
ip -br address показывает интерфейсы и адреса без длинного служебного вывода; ip route — куда система отправит пакеты; nmcli — какие интерфейсы обслуживает NetworkManager; iw dev — действительное имя беспроводного устройства. Если вместо wlan0 обнаружен wlp2s0, замените его во всех командах и в скрипте. Пинг здесь выполняют с проводного монитора. Не переходите к автоматизации при неработающем контрольном маршруте.
Для первичной ручной диагностики запишите время в UTC, номер порта коммутатора, PoE-мощность, uptime AP, клиентов по диапазонам и момент последнего обновления. Один клиент может потерять связь из-за своего драйвера, тогда как AP продолжает обслуживать остальных. Если отключились сразу все AP на одном коммутаторе, вероятнее общий uplink или питание.
Разделите доступность управления AP, ассоциацию клиента, получение DHCP, достижимость локального шлюза и доступ в Интернет. Если шлюз доступен, а внешний сайт нет, перезапуск AP обычно не поможет. Если вся площадка одновременно исчезла из мониторинга, сначала проверяют общий путь и коммутатор.
Сохраните время, модель AP, версию прошивки, uptime, PoE-события порта и симптомы нескольких клиентов. В UniFi Network откройте устройство, его события и сведения о соединении. Перед изменениями сделайте штатную резервную копию Network и экспортируйте доступные диагностические данные. Старый PHP-рецепт с устаревшими SSH-шифрами и паролем внутри файла не подходит для современной эксплуатации.
Автоматизация ниже обнаруживает конкретное сочетание: проводной контрольный шлюз доступен, AP отвечает по SSH, выделенный клиент связан с её BSSID, но локальный шлюз из Wi-Fi не отвечает несколько проверок подряд. Это сигнал деградации пути через AP, а не доказательство дефекта процессора или радиомодуля.
2. Подготовьте доступ к AP
Создайте ключи от имени реальной сервисной учётной записи
На мониторе сначала проверьте getent passwd avg-monitor. Если аккаунта нет, создайте его; существующий аккаунт с другим назначением нельзя переиспользовать без проверки:
sudo useradd --system --user-group --create-home --home-dir /var/lib/avg-monitor --shell /usr/sbin/nologin avg-monitor
sudo install -d -o avg-monitor -g avg-monitor -m 700 /var/lib/avg-monitor/.ssh
sudo install -d -o avg-monitor -g avg-monitor -m 700 /var/lib/avg-unifi-watchdog
Ключи создают после подготовки пользователя и каталогов. В инструкции ключ AP и ключ пробника разные: первый предоставляет право перезапуска оборудования, второй — только запуск фиксированной проверки.
sudo -u avg-monitor ssh-keygen -t ed25519 -N '' -f /var/lib/avg-monitor/.ssh/id_ap
sudo -u avg-monitor ssh-keygen -t ed25519 -N '' -f /var/lib/avg-monitor/.ssh/id_probe
sudo -u avg-monitor ssh-keygen -lf /var/lib/avg-monitor/.ssh/id_ap.pub
sudo -u avg-monitor ssh-keygen -lf /var/lib/avg-monitor/.ssh/id_probe.pub
Пустая passphrase в этом примере позволяет таймеру работать без человека; защита приватных ключей переносится на закрытый home, права 600 и доступ к самому монитору. Для другой модели угроз используйте агент с контролируемой разблокировкой и жизненным циклом. Ed25519 поддерживается не каждой старой прошивкой: при несовместимости сначала проверьте обновление и поддерживаемые алгоритмы. Не отключайте проверку ключа хоста.
В интерфейс Network добавляют только содержимое id_ap.pub по инструкции производителя. Имя пользователя AP возьмите из Device SSH Settings, не подставляйте root или ubnt по памяти. Приватный id_ap никогда не загружают в контроллер. Создайте файл /var/lib/avg-monitor/.ssh/config, заменив AP_SSH_USER на это имя:
Host avg-ap
HostName 10.77.10.21
User AP_SSH_USER
IdentityFile /var/lib/avg-monitor/.ssh/id_ap
IdentitiesOnly yes
BatchMode yes
StrictHostKeyChecking yes
ConnectTimeout 5
Host avg-probe
HostName 10.77.10.31
User avg-probe
IdentityFile /var/lib/avg-monitor/.ssh/id_probe
IdentitiesOnly yes
BatchMode yes
StrictHostKeyChecking yes
ConnectTimeout 5
Подтвердите ключи хостов до фонового запуска
Получите кандидаты на мониторе: ssh-keyscan -t ed25519 10.77.10.21 10.77.10.31 > /tmp/avg-hostkeys.candidate. Покажите отпечатки ssh-keygen -lf /tmp/avg-hostkeys.candidate. Для пробника доверенное значение можно получить через его консоль: sudo ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub. AP сверяют через доверенный доступ к устройству и доступный на его прошивке способ просмотра SSH host key. Если такого канала нет, сначала организуют его; совпадение с результатом второго keyscan не подтверждает подлинность.
После сверки установите файл кандидатов как /var/lib/avg-monitor/.ssh/known_hosts с владельцем avg-monitor и режимом 600. Для всех файлов config/id_ap/id_probe используйте 600, для .ssh — 700. Ошибка REMOTE HOST IDENTIFICATION HAS CHANGED требует расследования замены устройства/прошивки/адреса; нельзя автоматически удалять старый ключ.
Ubiquiti разделяет SSH консоли и сетевых устройств. Для AP используют Device SSH Settings в UniFi Network, а не настройки SSH Cloud Key. Текущий интерфейс показывает Device Updates and Settings; названия разделов меняются между версиями Network.
Создайте отдельный ключ мониторинга и настройте его поддерживаемым для устройства способом. Инструкция добавления SSH-ключей описывает управление ключами. Приватный ключ остаётся на станции мониторинга, права файла — 600. Не рассчитывайте, что пользователь AP имеет только права чтения: способность выполнить reboot фактически является административной.
В конфигурации SSH станции задайте два псевдонима, avg-ap и avg-probe, с реальными HostName, User, IdentityFile и параметрами:
BatchMode yes
StrictHostKeyChecking yes
ConnectTimeout 5
IdentitiesOnly yes
Ключи хостов предварительно сверяют по доверенному каналу и записывают в known_hosts. ssh-keyscan только получает ключ; сам по себе он не подтверждает личность устройства. Не включайте group1/SHA1 или 3DES ради автоматического перезапуска: сначала обновите поддерживаемое устройство либо пересмотрите способ управления.
3. Создайте выделенный беспроводной пробник
Подключите пробник и закрепите его за AP
На выделенном пробнике установите инструменты. SSH-сервер нужен только для управления по eth0; перед включением проверьте ACL на management VLAN.
sudo apt-get update
sudo apt-get install network-manager iw iputils-ping openssh-server sudo
systemctl is-active NetworkManager
nmcli -f NAME,DEVICE,TYPE connection show
nmcli -f IN-USE,SSID,BSSID,CHAN,SIGNAL device wifi list ifname wlan0
Последняя команда сканирует эфир; из строки нужного SSID возьмите BSSID конкретного радио. MAC AP в списке оборудования может отличаться от BSSID каждого SSID. Выберите один диапазон и не смешивайте адреса 2,4/5/6 ГГц. Слабый сигнал на удалённом пробнике приведёт к ложным выводам: поставьте его в устойчивую зону покрытия, но не вплотную к антенне.
Следующий профиль создаёт новое подключение на wlan0, не редактируя eth0. Команды выполняются на тестовом клиенте с NetworkManager; существующий профиль с тем же именем сначала изучите. Пароль вводится через интерактивный запрос, а не в историю shell.
sudo nmcli connection add type wifi ifname wlan0 con-name avg-ap-probe ssid AVG-LAB
sudo nmcli connection modify avg-ap-probe 802-11-wireless.bssid 02:11:22:33:44:55
sudo nmcli connection modify avg-ap-probe wifi-sec.key-mgmt wpa-psk
sudo nmcli connection modify avg-ap-probe ipv4.method manual ipv4.addresses 10.77.20.31/24 ipv4.never-default yes ipv6.method disabled
sudo nmcli --ask connection up avg-ap-probe
Фиксация BSSID запрещает незаметный переход на соседнюю точку. never-default сохраняет проводной default route: тест Wi-Fi выполняется явным выбором интерфейса. Статический адрес исключает DHCP из условия автоматического решения; отдельно проверьте, что он зарезервирован и не выдается сервером. Это watchdog передачи данных уже связанного клиента, а не тест всей процедуры выдачи адреса. При необходимости контролировать DHCP используют отдельный пробник с другим критерием восстановления.
Для корпоративного WPA-Enterprise не создавайте исключение с общим PSK. Вариант EAP-TLS требует действующих сертификатов, доверенного CA и проверки имени RADIUS; пример меняет только лабораторный профиль:
sudo nmcli connection modify avg-ap-probe wifi-sec.key-mgmt wpa-eap 802-1x.eap tls 802-1x.identity avg-probe
sudo nmcli connection modify avg-ap-probe 802-1x.ca-cert /etc/avg-probe/ca.pem 802-1x.client-cert /etc/avg-probe/client.pem 802-1x.private-key /etc/avg-probe/client.key 802-1x.domain-suffix-match radius.example.com
sudo nmcli --ask connection up avg-ap-probe
radius.example.com здесь заменяют ожидаемым именем из сертификата своего сервера. Закрытый ключ принадлежит устройству пробника и хранится с ограниченными правами. Назначение bssid и параметров IP описано в справочнике NetworkManager.
Проверьте, что трафик действительно проходит через радио
iw dev wlan0 link
ip route get 10.77.20.1 oif wlan0
ping -I wlan0 -c 3 -W 2 10.77.20.1
Ожидается Connected to с выбранным BSSID, маршрут dev wlan0 src 10.77.20.31 и ответы шлюза. Пример нормального результата — 3 переданных, 3 полученных, 0% потерь. Сам факт Connected подтверждает ассоциацию, но не прохождение IP-пакетов. Если gateway фильтрует ICMP, выберите другой разрешённый локальный контрольный ресурс и соответствующим образом измените оба теста.
Ограничьте SSH пробника одним проверочным действием
На пробнике проверьте getent passwd avg-probe; если аккаунта нет, создайте его и каталог ключей:
sudo useradd --system --user-group --create-home --home-dir /var/lib/avg-probe --shell /bin/sh avg-probe
sudo passwd -l avg-probe
sudo install -d -o avg-probe -g avg-probe -m 700 /var/lib/avg-probe/.ssh
OpenSSH нужен shell для forced command. На некоторых PAM/SSH-профилях locked service account запрещает также public-key вход: проверяйте действующую policy и журнал, не снимайте блокировку вслепую. Для такого профиля используйте утверждённую организацией key-only service identity. Пароль заблокирован, интерактивный доступ по ключу ограничен. Создайте root-owned скрипт из примера ниже, затем файл /etc/sudoers.d/avg-wifi-probe:
avg-probe ALL=(root) NOPASSWD: /usr/local/libexec/avg-wifi-probe
Проверьте sudo visudo -cf /etc/sudoers.d/avg-wifi-probe, права файла 440. В .ssh/authorized_keys пользователя пробника добавьте одну строку, где SSH_PUBLIC_KEY заменён полным содержимым id_probe.pub с монитора:
restrict,command="sudo -n /usr/local/libexec/avg-wifi-probe" SSH_PUBLIC_KEY
restrict отключает forwarding и PTY; forced command игнорирует присланную команду и запускает только пробник. Скрипт, его каталог и конфигурацию sudoers не может изменять avg-probe. Сам пользователь не получает произвольный sudo. Это стандартные ограничения OpenSSH authorized_keys. Проверяйте доступ сначала по eth0, сохранив независимую административную сессию.
Пробник имеет проводной интерфейс для управления и отдельный Wi-Fi-интерфейс wlan0. Он закреплён за пилотным BSSID настройками собственного network manager. Шлюз тестовой Wi-Fi-сети в примере — 10.77.20.1. Эти параметры заменяют перед испытаниями; обычный роумящий ноутбук не годится.
Сохраните на пробнике root-owned /usr/local/libexec/avg-wifi-probe со следующим содержимым. Нужны iw, iputils-ping, Python 3 и право чтения состояния wlan0. Если iw требует привилегии, делегируют только этот неизменяемый root-owned скрипт, а не произвольный shell.
#!/bin/bash
set -eu
BSSID=02:11:22:33:44:55
GATEWAY=10.77.20.1
LINK=$(iw dev wlan0 link)
if ! printf '%s\n' "$LINK" | grep -qi "Connected to $BSSID "; then
printf '{"state":"unknown","reason":"wrong_or_missing_bssid"}\n'
exit 0
fi
if ping -I wlan0 -c 3 -W 2 "$GATEWAY" >/dev/null 2>&1; then
printf '{"state":"ok"}\n'
else
printf '{"state":"fail","reason":"associated_gateway_unreachable"}\n'
fi
Фиксированный MAC выше — учебный локально администрируемый адрес, не адрес вашего оборудования. Реальное значение берут из данных AP и сверяют на клиенте. Проверьте маршрутизацию: ping -I wlan0 должен уходить через тестируемый интерфейс. Корпоративный firewall должен разрешать этот контрольный ICMP. Иначе watchdog начнёт лечить штатный запрет трафика.
Установите подготовленный пробник после проверки содержимого:
sudo install -d -m 755 /usr/local/libexec
sudo install -o root -g root -m 755 ./avg-wifi-probe /usr/local/libexec/avg-wifi-probe
4. Реализуйте ограниченный watchdog
На проводной станции сохраните следующий Python-код в /usr/local/sbin/avg-unifi-watchdog.py. В примере Python 3, OpenSSH, Linux flock через fcntl и интервал запуска 60 секунд.
sudo apt-get install python3 openssh-client iputils-ping
getent passwd avg-monitor
Если пользователь отсутствует, создайте его: sudo useradd --system --user-group --create-home --home-dir /var/lib/avg-monitor --shell /usr/sbin/nologin avg-monitor. Затем подготовьте состояние:
sudo install -d -o avg-monitor -g avg-monitor -m 700 /var/lib/avg-unifi-watchdog
sudo install -d -o avg-monitor -g avg-monitor -m 700 /var/lib/avg-monitor/.ssh
После сохранения кода установите его root-owned: sudo install -o root -g root -m 755 ./avg-unifi-watchdog.py /usr/local/sbin/avg-unifi-watchdog.py. SSH config и known_hosts находятся в home сервисного пользователя; ключи подготавливают отдельно, не берут из скачиваемого архива. Каталог /var/lib/avg-unifi-watchdog предварительно создаётся для пользователя мониторинга с режимом 700. Его нельзя размещать в доступном для записи общем каталоге.
#!/usr/bin/env python3
import argparse
import fcntl
import json
import subprocess
import time
from pathlib import Path
ROOT = Path('/var/lib/avg-unifi-watchdog')
AP = 'avg-ap'
PROBE = 'avg-probe'
WIRED_GATEWAY = '10.77.20.1'
THRESHOLD = 3
COOLDOWN = 3600
GAP = 90
def run(argv):
return subprocess.run(argv, capture_output=True, text=True, timeout=15)
def ssh(host, command):
return run(['ssh', '-o', 'BatchMode=yes', '-o',
'StrictHostKeyChecking=yes', '-o', 'ConnectTimeout=5',
host, command])
def permitted(count, now, last_action):
return count >= THRESHOLD and now - last_action >= COOLDOWN
def main():
parser = argparse.ArgumentParser()
parser.add_argument('--apply', action='store_true')
args = parser.parse_args()
with (ROOT / 'lock').open('a') as lock:
try:
fcntl.flock(lock, fcntl.LOCK_EX | fcntl.LOCK_NB)
except BlockingIOError:
return
statefile = ROOT / 'state.json'
s = json.loads(statefile.read_text()) if statefile.exists() else {}
now = time.time()
count = int(s.get('count', 0))
previous = float(s.get('checked', 0))
last = float(s.get('action', 0))
if not 0 <= now - previous <= GAP:
count = 0
observed = 'unknown'
reason = 'control_path_failed'
try:
wired = run(['ping', '-c', '2', '-W', '2', WIRED_GATEWAY])
ap = ssh(AP, 'uptime')
if wired.returncode == 0 and ap.returncode == 0:
probe = ssh(PROBE, '/usr/local/libexec/avg-wifi-probe')
if probe.returncode == 0:
answer = json.loads(probe.stdout)
observed = answer.get('state', 'unknown')
reason = answer.get('reason', '')
except (subprocess.TimeoutExpired, json.JSONDecodeError, OSError):
reason = 'probe_error'
count = count + 1 if observed == 'fail' else 0
action = 'observe'
if permitted(count, now, last):
action = 'would_reboot'
if args.apply:
# Record attempt BEFORE SSH: disconnect is expected on reboot.
last = now
count = 0
action = 'reboot_attempt'
new = {'count': count, 'checked': now, 'action': last}
temp = ROOT / 'state.tmp'
temp.write_text(json.dumps(new))
temp.replace(statefile)
print(json.dumps({'state': observed, 'reason': reason,
'failures': count, 'action': action}), flush=True)
if action == 'reboot_attempt':
try:
result = ssh(AP, 'reboot')
print(json.dumps({'ssh_exit': result.returncode}), flush=True)
except (subprocess.TimeoutExpired, OSError):
print('{"ssh_exit":"unknown"}', flush=True)
if __name__ == '__main__':
main()
Скрипт не сохраняет пароли и не использует shell=True. Ошибка контроля, неподходящий BSSID и разрыв между запусками сбрасывают последовательность неудач. Режим по умолчанию только выводит would_reboot. Повреждение state.json останавливает выполнение вместо снятия cooldown; исправление состояния выполняется оператором после анализа.
Как читать алгоритм и где он сознательно останавливается
run запускает программу массивом аргументов: значения не подставляются в shell. ssh задаёт ограниченное ожидание соединения и запрещает вопросы о пароле. flock не допускает двух одновременно работающих экземпляров. Порог THRESHOLD=3 означает три соседних результата fail; неизвестный результат не считается отказом радиоканала. GAP=90 обнуляет серию после долгого перерыва, например при остановленном мониторе.
Состояние атомарно заменяется отдельным файлом. action хранит время попытки, поэтому разрыв SSH при reboot не приводит к немедленной повторной перезагрузке. COOLDOWN=3600 означает минимум час между попытками для одной AP. Перевод часов назад блокирует действие, пока разница не станет допустимой; синхронизация времени и контроль её скачков обязательны. Поврежденный JSON не заменяется автоматически пустым состоянием: оператор расследует ошибку и тем самым сохраняет ограничение частоты.
Измерения не доказывают физическое зависание AP. Коммутатор может пропускать management VLAN и терять client VLAN, а шлюз может отвечать с проводной сети и блокировать только Wi-Fi-клиента. Поэтому решение используют после пилота, анализа инцидентов и выбора политики. При массовом применении нужен общий выключатель площадки: одиночный скрипт ниже не содержит такого распределённого механизма.
5. Проверьте поведение без реальных перезапусков
Скачать исходники watchdog, пробник и unit-файлы. Архив содержит только учебные файлы без ключей и действующих адресов. Сначала вручную выполните обе SSH-проверки от того же пользователя, которым будет работать планировщик. Ручной успешный запуск от root не доказывает доступность ключа у сервисной учётной записи.
sudo -u avg-monitor ssh avg-ap uptime
sudo -u avg-monitor ssh avg-probe /usr/local/libexec/avg-wifi-probe
sudo -u avg-monitor python3 /usr/local/sbin/avg-unifi-watchdog.py
Ожидаемый нормальный результат пробника — state=ok. На тестовом стенде заблокируйте только контрольный путь пробника и убедитесь: после трёх соседних проверок появляется would_reboot. При разрыве проводного контроля, отключении SSH пробника или переходе клиента на другой BSSID должно получиться unknown без действия. Если этого нет, исправьте пробник и схему до включения apply.
Отдельно проверьте cooldown, конкурирующие запуски и пропуск одного интервала. Автоматический watchdog не должен перезагружать несколько AP из-за общего отказа DHCP или firewall. Этот пример обслуживает только одну AP; масштабирование требует площадочного interlock и последовательной очереди действий.
Дайте каждой проверке однозначный ожидаемый результат
Для нормального режима пробник выводит {"state":"ok"}, watchdog — состояние ok, failures=0 и action=observe. Если wlan0 отключён либо ушёл на иной BSSID, пробник выдаёт unknown. Если association сохранена, но ICMP до шлюза не проходит, получается fail. После первого и второго fail действия нет; после третьего в режиме наблюдения появляется would_reboot.
На отдельном пробнике можно воспроизвести fail временным nftables-фильтром. Делайте это только после подтверждения нормального ICMP и сохраните возможность управления по eth0:
sudo nft add table inet avg_probe_test
sudo nft 'add chain inet avg_probe_test output { type filter hook output priority 0; policy accept; }'
sudo nft add rule inet avg_probe_test output oifname wlan0 ip daddr 10.77.20.1 icmp type echo-request drop
sudo /usr/local/libexec/avg-wifi-probe
sudo nft delete table inet avg_probe_test
sudo /usr/local/libexec/avg-wifi-probe
Пакет nftables устанавливают отдельно, если nft отсутствует. Уникальная таблица не меняет штатные chains. Первый результат должен стать fail, второй — ok. Если получился unknown, причина в association, а не в тестовом фильтре. Для серии из трёх запусков оставьте фильтр только на время наблюдения и обязательно удалите в конце; режим apply при этом выключен.
Негативный тест: отключите только доступ монитора к пробнику либо временно остановите NetworkManager-подключение avg-ap-probe. Watchdog должен сбросить failures и не давать would_reboot. Восстановите подключение sudo nmcli --ask connection up avg-ap-probe. Изменение произвольного состояния вручную не заменяет испытание реального пути.
6. Запускайте наблюдение через systemd
Для уже созданного пользователя avg-monitor, его SSH-ключей и каталога состояния пример unit выглядит так:
[Unit]
Description=Observe one UniFi AP wireless path
[Service]
Type=oneshot
User=avg-monitor
ExecStart=/usr/bin/python3 /usr/local/sbin/avg-unifi-watchdog.py
NoNewPrivileges=yes
PrivateTmp=yes
[Unit]
Description=UniFi AP watchdog observation interval
[Timer]
OnBootSec=2min
OnUnitActiveSec=60s
AccuracySec=1s
[Install]
WantedBy=timers.target
Сохраните файлы как avg-unifi-watchdog.service и .timer в /etc/systemd/system. Выполните daemon-reload, затем enable --now именно timer. Проверяйте systemctl list-timers и journalctl -u avg-unifi-watchdog.service --since '-10 minutes'. Таймер отсчитывает интервал от предыдущей активации; слишком долгий запуск может сбросить последовательность по GAP, что безопаснее пропуска проверки.
Установите unit-файлы и проверьте расписание
После сохранения приведённых service и timer в текущий каталог выполните:
sudo install -o root -g root -m 644 avg-unifi-watchdog.service avg-unifi-watchdog.timer /etc/systemd/system/
sudo systemd-analyze verify /etc/systemd/system/avg-unifi-watchdog.service /etc/systemd/system/avg-unifi-watchdog.timer
sudo systemctl daemon-reload
sudo systemctl enable --now avg-unifi-watchdog.timer
systemctl list-timers avg-unifi-watchdog.timer
sudo journalctl -u avg-unifi-watchdog.service --since '-10 minutes' --no-pager
verify проверяет синтаксис unit, а не сетевые права; daemon-reload перечитывает определения; enable обеспечивает запуск таймера после загрузки. В list-timers должны появиться NEXT и LAST. Отсутствие записей в журнале при активном timer требует проверки service: systemctl status avg-unifi-watchdog.service. Ошибка HOME/known_hosts чаще означает, что файлы созданы для другого пользователя.
OnUnitActiveSec отсчитывает от предыдущей активации, а не от завершения проверки. Важно, чтобы проверка укладывалась в интервал; повторно уже активный oneshot не запускается. При длительной работе получается пропуск измерения и безопасный сброс серии. Для большого количества AP создают отдельные экземпляры и общий лимит действий, а не запускают одну минутную проверку на сотни устройств последовательно.
7. Включайте действие только после пилота
Перед включением --apply проверьте команду reboot на вашей модели AP в согласованном окне и подтвердите, что устройство возвращается под управление без factory reset. Перезагрузка и сброс к заводским настройкам — разные операции; set-default в watchdog не нужен.
Измените ExecStart в unit, добавив --apply, выполните daemon-reload и проверьте эффективную команду через systemctl cat. Включение должно сопровождаться доставкой событий would_reboot/reboot_attempt в действующую систему оповещений. Код возврата SSH при reboot может быть ненулевым из-за разрыва соединения; это не доказывает, что AP не перезагрузилась.
Cooldown ограничивает частоту попыток одной AP, но не гарантирует число действий на площадку. Для критичной сети добавляют общий бюджет и ручную разблокировку после неуспешного восстановления. До этого описанный пилот нельзя распространять автоматически на все устройства.
Включите перезапуск через отдельное переопределение
После успешного пилота создайте drop-in с помощью sudo systemctl edit avg-unifi-watchdog.service. Пустая строка ExecStart сбрасывает исходное значение, следующая задаёт единственную команду:
[Service]
ExecStart=
ExecStart=/usr/bin/python3 /usr/local/sbin/avg-unifi-watchdog.py --apply
Затем sudo systemctl daemon-reload и systemctl cat avg-unifi-watchdog.service. В эффективной конфигурации должен быть --apply. Без этого скрипт продолжит только наблюдение, даже если в другом файле записана желаемая команда. Оповещение о reboot_attempt должно включать AP, время и причину; журнал state=fail без оповещения нельзя считать работающим мониторингом.
8. Проверьте восстановление услуги
После reboot дождитесь загрузки AP, подключения к Network и state=ok на том же BSSID. Проверьте DHCP, локальный шлюз, корпоративный ресурс и реальные приложения клиента. Запишите длительность простоя. Если пробник восстановился, но сотрудники всё ещё не работают, изучите клиентский VLAN, DHCP, DNS и NAC отдельно.
В отчёте должны быть время причины, номер действия, uptime до/после, состояние контрольного пути и результат беспроводного теста. Без проверки после действия watchdog превращается в генератор перезапусков. Три успешных последующих наблюдения — полезный критерий устойчивого возвращения, но для пользовательской приёмки нужен тест приложения.
Отличите выполненную команду от восстановленной услуги
Сравните ssh avg-ap uptime до/после действия. Малый uptime после перезапуска подтверждает новую загрузку, но не успешную работу SSID. Нужны state=ok на закреплённом пробнике, видимость AP в Network и проверка приложения из клиентского VLAN. Три последовательных ok помогают исключить краткое возвращение связи. Добавьте лимит времени восстановления в существующее оповещение: если его превышено, следующий шаг — расследование и отключение автоматических действий.
Проверьте отдельно DNS и DHCP обычным клиентом: статический пробник не обнаружит исчерпанный DHCP pool. Если сеть использует RADIUS, подтвердите новое подключение с повторной аутентификацией, а не только ранее созданную сессию. Успешный ping не подтверждает работу captive portal, голосовой связи и конкретного корпоративного сервиса.
9. Найдите первопричину повторных зависаний
Проверьте ошибки uplink, бюджет PoE, перегрев, совместимость питания, DFS-события, каналы, загрузку эфира, проблемную версию прошивки и масштаб сбоя. Перезапуск, устраняющий симптом, не подтверждает причину. Для обновления сначала выберите поддерживаемую прошивку и пилотную AP, затем сравните частоту инцидентов при одинаковой нагрузке.
Если management SSH недоступен, приведённая автоматизация не пытается угадать команду PoE-коммутатора. Отключение питания требует подтверждённого соответствия порт → AP и исключения портов с несколькими устройствами. Vendor-specific API нельзя заменять неподтверждённой универсальной командой.
Практический порядок поиска причины
Если SSH недоступен, смотрите линк, PoE и management VLAN. Если SSH доступен, но association нет, смотрите радио, канал, SSID и аутентификацию. Если association есть, но gateway недоступен, изучите client VLAN, ACL, порт uplink и MAC-таблицу. Если gateway доступен, но приложение нет, проверяйте DNS, маршрут, NAT и удалённый сервис. Такой порядок сокращает число случайных перезапусков.
В Network сопоставьте частоту инцидентов с обновлениями, DFS и нагрузкой; на коммутаторе — с событиями link down, ошибками CRC и отключением PoE. Обновление меняет сразу несколько компонентов, поэтому сначала сохраняют предыдущую поддерживаемую версию и план отката. Не редактируйте произвольные init-файлы AP: после provision/upgrade они могут быть перезаписаны, а локальная модификация затруднит поддержку.
10. Остановите watchdog и верните настройки
Для прекращения наблюдения: sudo systemctl disable --now avg-unifi-watchdog.timer. Убедитесь, что уже запущенный service завершился; при необходимости остановите его отдельно. Верните ExecStart без --apply, затем daemon-reload. Сохраните журнал инцидентов и state.json до удаления.
Отзовите выделенный ключ на AP и пробнике, если автоматизация выведена из эксплуатации. Factory reset для отката watchdog не требуется. Работу считают завершённой после доказанного отсутствия лишних перезапусков, подтверждения восстановления услуги и документирования ограничений пробника.
Возврат по шагам
sudo systemctl disable --now avg-unifi-watchdog.timer
sudo systemctl stop avg-unifi-watchdog.service
systemctl is-active avg-unifi-watchdog.timer
sudo -u avg-monitor cat /var/lib/avg-unifi-watchdog/state.json
Ожидается inactive у timer. Сохраните журнал и state до удаления файлов: это история того, почему принималось решение. Отзовите id_ap.pub в Network, затем ключ пробника в его authorized_keys. Отключите и удалите только профиль avg-ap-probe, если он был создан для пилота. Удалите только собственный drop-in с --apply, перечитайте systemd и проверьте отсутствие старого задания cron. Отзыв ключа, остановка таймера и удаление кода — разные действия; для немедленной остановки достаточно первых двух.
Команды и алгоритм в материале проверены на уровне синтаксиса и модельных сценариев. Совместимость SSH, association, PoE и выполнение reboot проверяются отдельно на конкретной модели AP. Критерий готовности — воспроизводимые ok/fail/unknown, отсутствие действий при неизвестном состоянии, выдержанный cooldown и подтверждённое возвращение пользовательской услуги.
