Watchdog для WireGuard. Периодически пингует IP внутри туннеля и, если он
перестаёт отвечать заданное число раз подряд, перезапускает туннель через
systemctl restart wg-quick@<iface>. Защищает от «зависшего» туннеля и
кратковременных падений сервера — соединение поднимается заново автоматически.
- Каждые
check.intervalотправляется один ICMP-пинг наcheck.target. - Неудачи считаются подряд; успешный ответ сбрасывает счётчик.
- При
check.failuresнеудачах подряд →systemctl restart wg-quick@<iface>. - После перезапуска — пауза
check.cooldown, пока туннель поднимается. - Корректно завершается по SIGINT/SIGTERM (для systemd).
tunnel-keeper/
├── cmd/
│ └── tunnel-keeper/
│ └── main.go # точка входа: сборка зависимостей и запуск
├── internal/
│ ├── config/ # загрузка и валидация TOML-конфига
│ │ └── config.go
│ ├── pinger/ # ICMP-проверка доступности
│ │ └── pinger.go
│ ├── tunnel/ # перезапуск туннеля через systemctl
│ │ └── tunnel.go
│ └── keeper/ # цикл наблюдения, связывает pinger + tunnel
│ └── keeper.go
├── deploy/
│ ├── tunnel-keeper.service # systemd unit
│ └── install.sh # сборка + установка
├── config.toml # пример конфигурации
├── Makefile
├── go.mod
├── LICENSE
└── README.md
Архитектура — слоистая: keeper оркестрирует, pinger и tunnel — независимые
адаптеры за интерфейсами, config отделён от логики. Это упрощает тестирование
(моки для Pinger/Tunnel) и замену реализаций (например, ping через TCP или
управление туннелем без systemd).
make build # go mod tidy + сборка в ./tunnel-keeper
# или вручную:
go mod tidy
CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o tunnel-keeper ./cmd/tunnel-keeperЗапуск локально:
make run # ./tunnel-keeper -config ./config.toml[tunnel]
iface = "wg0" # systemctl restart wg-quick@wg0
[check]
target = "10.0.0.1" # IP внутри туннеля (обязательно)
interval = "10s" # период проверок
timeout = "3s" # таймаут одной проверки
failures = 3 # неудач подряд до перезапуска
cooldown = "30s" # пауза после перезапуска
privileged = true # raw ICMP (root/CAP_NET_RAW); false — UDP-ICMPПри privileged = false нужно разрешить unprivileged ICMP на хосте:
sudo sysctl -w net.ipv4.ping_group_range="0 2147483647"Автоматически (скрипт соберёт, установит, запустит сервис и добавит в автозагрузку):
sudo ./deploy/install.sh
# затем при необходимости правим конфиг и перезапускаем:
sudo nano /etc/tunnel-keeper/config.toml # укажите target и iface
sudo systemctl restart tunnel-keeperИли через make:
sudo make install
sudo systemctl enable --now tunnel-keepersudo systemctl status tunnel-keeper # статус
sudo systemctl restart tunnel-keeper # перезапуск (в т.ч. после правки config.toml)
sudo systemctl stop tunnel-keeper # остановка
journalctl -u tunnel-keeper -f # логи в реальном времениПосле любого изменения /etc/tunnel-keeper/config.toml примените его перезапуском:
sudo systemctl restart tunnel-keeperRestart=always в unit-файле перезапускает сам сервис при падении, а
WantedBy=multi-user.target — поднимает его автоматически после перезагрузки.
sudo make uninstall # конфиг в /etc/tunnel-keeper оставляется