Если у вашего проекта простой SPOF на единственном сервере, то апгрейды ядра, кривые обновления или даже «битая» планка RAM мгновенно превращают сайт в «503». В этой статье я соберу рабочий минимум для высокой доступности (high availability, HA) веб-уровня на VDS: два узла с Nginx, один плавающий IP и отказоустойчивость через keepalived/VRRP с проверкой здоровья. Без лишних абстракций — с акцентом на то, что реально спасает в проде.
Зачем VRRP и что даёт плавающий IP
VRRP — протокол выбора «мастера» среди нескольких узлов, у которых общий виртуальный (плавающий) IP. В норме один узел держит IP и отвечает на трафик, второй стоит «в засаде». При сбое мастера backup за секунды перехватывает IP и продолжает обслуживать запросы. Это существенно уменьшает время простоя и позволяет делать обслуживание без полной недоступности.
Важно: VRRP работает на L2-сегменте. Оба узла должны «видеть» один и тот же broadcast-домен, иначе плавающий IP не сможет быстро переезжать с корректной раздачей ARP.
Базовая архитектура
Мы берём два VDS в одной подсети. На обоих установлен Nginx и keepalived. Виртуальный IP (VIP) «плавает» между ними, а внешние DNS-записи на домен указывают именно на VIP (A/AAAA). Если вы настраиваете новый домен — удобно совместить это с регистрация доменов.
Сценарий активный/пассивный: один обслуживает, второй готов перехватить.
Варианты роли Nginx:
- Reverse proxy перед backend’ами (PHP-FPM, Node.js, Python и т.п.) — наиболее распространённый вариант. State хранится не на прокси, а в БД/Redis.
- Статический контент (файлы) — синхронизация через rsync/obj-storage; при failover статика остаётся доступной.
- Терминирование TLS — сертификаты одинаковые на обоих узлах, автоматизация обновления обязательна: используйте надёжные SSL-сертификаты.
Требования и сетевые нюансы
Чтобы VRRP и плавающий IP работали предсказуемо, проверьте:
- Оба VDS в одной L2-сети. При облачном провайдере это обычно один и тот же сегмент/виртуальный свитч.
- Multicast для VRRP может быть ограничен. Если мультикаст запрещён, используйте unicast-режим keepalived.
- ARP-обновление после failover: нужна корректная рассылка gratuitous ARP, чтобы гейтвей и соседи перестроили таблицы.
- Понимание, что существующие TCP-сессии при переключении сорвутся. HA на L4/L7 без state replication не «мигрирует» активные соединения.

Подготовка системы
ОС — любая популярная серверная Linux. Примеры далее для Debian/Ubuntu и RHEL-подобных.
# Debian/Ubuntu
sudo apt update
sudo apt install -y nginx keepalived curl jq
# RHEL/Alma/Rocky
sudo dnf install -y nginx keepalived curl jq
Рекомендуемый sysctl-тюнинг для VIP и корректной ARP-семантики (на обоих узлах):
sudo tee /etc/sysctl.d/99-ha-vip.conf > /dev/null << 'EOF'
net.ipv4.ip_nonlocal_bind = 1
net.ipv4.conf.all.arp_ignore = 1
net.ipv4.conf.default.arp_ignore = 1
net.ipv4.conf.all.arp_announce = 2
net.ipv4.conf.default.arp_announce = 2
EOF
sudo sysctl --system
net.ipv4.ip_nonlocal_bind позволяет Nginx слушать адрес даже до прихода VIP (или если VIP временно у соседа), а параметры arp_ignore/arp_announce снижают риск ARP-флукса при перемещении адреса.
Минимальная конфигурация Nginx
Если Nginx — реверс-прокси к вашему backend на 127.0.0.1:9000 или upstream-пулу, хватит базовой конфигурации. Главное — она должна быть одинаковой на обоих узлах и обновляться атомарно.
# /etc/nginx/conf.d/site.conf
server {
listen 80;
server_name example.com;
location /health {
access_log off;
return 200 'ok';
}
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_pass http://127.0.0.1:9000;
}
}
Блок /health — это наш локальный health check для keepalived. Он должен отвечать 200 быстро и без внешних зависимостей.
Конфигурация keepalived: VRRP + health check
Это сердце HA. Настроим одну vrrp_instance, VIP в формате /32 и проверку Nginx через vrrp_script. Пример для «левого» узла (Node A):
# /etc/keepalived/keepalived.conf (Node A)
vrrp_script chk_nginx {
script "/usr/bin/curl -fsS http://127.0.0.1/health >/dev/null || exit 1"
interval 2
rise 2
fall 2
timeout 2
weight -20
}
vrrp_instance VI_1 {
state BACKUP
interface eth0
virtual_router_id 51
priority 200
advert_int 1
# Используем unicast, если multicast недоступен
unicast_src_ip 10.0.0.11
unicast_peer {
10.0.0.12
}
authentication {
auth_type PASS
auth_pass s3cr3tPass
}
virtual_ipaddress {
203.0.113.10/32 dev eth0 label eth0:vip
}
garp_master_delay 1
garp_master_repeat 5
preempt_delay 5
nopreempt
track_script {
chk_nginx
}
}
Для второго узла (Node B) конфигурация идентична, но с другой исходной unicast_src_ip и меньшим priority, например 150. Поле nopreempt полезно, если не хотите, чтобы первоначальный мастер «отбирал» VIP назад сразу после краткого сбоя второго узла. Если нужна обратная логика, уберите nopreempt и используйте preempt_delay, чтобы избежать «дерганья» VIP.
Опции garp_master_delay и garp_master_repeat помогают агрессивнее разослать gratuitous ARP при переключении — это ускоряет обновление ARP-таблиц соседей и гейтвея.
Заметки по безопасности VRRP
В IPv4 VRRPv2 можно включить простую аутентификацию (auth_type PASS), но это не криптостойкая защита. Основной щит — сетевой периметр и unicast. В IPv6 (VRRPv3) встроенной аутентификации нет: полагайтесь на сегментацию и фильтрацию.
Запуск и проверка
sudo systemctl enable --now nginx
sudo systemctl enable --now keepalived
# Проверяем VIP
ip addr show dev eth0 | grep 203.0.113.10 || echo "VIP не на этом узле"
# Смотрим VRRP-анонсы
sudo tcpdump -ni eth0 ip proto 112 -vv
На одном из узлов вы должны увидеть VIP на интерфейсе. Если нет — читайте логи keepalived и убедитесь, что интерфейс/адреса указаны корректно, а мультикаст/юникаст-достижимость работает.
Failover-тесты: как убедиться, что HA реальное
Проведите серию тестов в непиковое время, но с реальными клиентскими запросами (или генератором нагрузки):
- Остановите Nginx на активном узле. Health check на мастере провалится — при достаточном «весе» проверок его приоритет станет ниже, и VIP переедет на backup.
- Остановите keepalived на активном узле. VIP должен уехать на backup почти мгновенно.
- Перегрузите сеть интерфейса (down/up) — убедитесь, что ARP обновляется корректно, нет «залипания» на маршрутизаторе.
# Примеры
sudo systemctl stop nginx
sleep 5
curl -I http://203.0.113.10/ || echo "Проверка с клиента"
sudo systemctl stop keepalived
sleep 3
ip addr show dev eth0 | grep 203.0.113.10 || echo "VIP ушел на соседа"
Фиксируйте RTO для клиентов: при корректном тюнинге failover занимает секунды. Помните: существующие TCP-сессии разорвутся — это нормально для L7-прокси без state sync.

Продвинутые health checks
Минимальный health check проверяет локальный /health. Но полезно контролировать и жизнеспособность бэкенда или TLS:
- HTTP к upstream через Nginx: если backend упал, отдавайте 502 на
/healthи валите проверку. - Проверка порта:
nc -z 127.0.0.1 80илиss -lntкак быстрый индикатор. - Валидность сертификата: периодическая проверка сроков и перезапуск Nginx при обновлении.
# Пример скрипта более строгой проверки
sudo tee /usr/local/bin/check_nginx.sh > /dev/null << 'EOF'
#!/usr/bin/env bash
set -euo pipefail
# 1) сам Nginx
curl -fsS http://127.0.0.1/health >/dev/null
# 2) один из бэкендов
curl -fsS --max-time 1 http://127.0.0.1/backend-health >/dev/null
exit 0
EOF
sudo chmod +x /usr/local/bin/check_nginx.sh
vrrp_script chk_nginx {
script "/usr/local/bin/check_nginx.sh"
interval 2
rise 2
fall 2
timeout 2
weight -30
}
weight задаёт, насколько «штрафовать» приоритет при провале проверки. Если на мастере проверки провалились, он уступит VIP.
Согласованность конфигураций и деплой
Одинаковые версии и конфиги Nginx на обоих VDS упрощают жизнь. Применяйте атомарный деплой: выкатывайте на пассивный узел, переключайтесь, затем обновляйте второй. Если используете CI/CD, добавляйте шаги синтакс-проверки (nginx -t) и canary-раздачу, чтобы не уронить оба узла единовременно. Для сценариев переноса полезно заглянуть в гайд по миграции без даунтайма.
Sticky-сессии и пользовательский опыт
При простом VRRP-переключении TCP-сессии рвутся, а IP клиента на новом мастере может прийти к другому узлу бэкенда. Для веб-приложений используйте хранение сессий вне «фронтов» (например, в Redis), а не в памяти Nginx/PHP-FPM. Если есть персистентность на уровне балансировщика (cookie, ip_hash), при failover неизбежны кратковременные промахи — их стоит учитывать.
Логи и мониторинг
Мониторьте:
- Состояние VRRP: логи keepalived, событие смены мастера.
- Время ответа
/health, коды ответа, RPS. - Сетевые показатели: дропы пакетов, ошибки на интерфейсе, переполнения conntrack.
- Использование CPU/IO — чтобы избежать «ложных» флапов от перегруза.
Для расследований полезен tcpdump ip proto 112 и разметка логов момента «переброса» VIP. Сохраняйте таймлайны и связывайте их с алертами.
Типичные проблемы и как их лечить
- VIP «залип» у соседа: увеличьте
garp_master_repeat, проверьте ARP/ND кеши на гейтвее, убедитесь, что VIP действительно добавлен на интерфейс. - Failover слишком «шумный»: уберите
preemptили добавьтеpreempt_delay, увеличьтеfall/riseу проверок. - Мультикаст режется: переходите на unicast-конфиг (
unicast_src_ipиunicast_peer). - Nginx не стартует до прихода VIP: включён
net.ipv4.ip_nonlocal_bind=1? Либо слушайте 0.0.0.0, либо управляйте рестартом через notify-хуки keepalived. - Сертификаты не обновляются: автоматизируйте выпуск и раскатку на оба узла, тестируйте
nginx -tперед рестартом.
Хуки keepalived для тонкой логики
Keepalived поддерживает скрипты notify_master, notify_backup, notify_fault. Например, можно включать/отключать дополнительный сервис или метрики.
vrrp_instance VI_1 {
# ... остальной конфиг ...
notify_master "/usr/local/bin/on_master.sh"
notify_backup "/usr/local/bin/on_backup.sh"
}
Скрипты должны быть простыми, быстрыми и с явным логированием. Никогда не вешайте на них тяжёлые миграции или долгие блокирующие операции — это ухудшит RTO.
Резервирование уровня хранения
Если Nginx отдаёт статический контент, позаботьтесь о репликации: либо регулярный rsync, либо хранение в объектном хранилище с локальным кэшем. Для пользовательских загрузок — синхронизация по событию, чтобы при переключении контент не «исчезал». Для устойчивости к ЧС держите резервные копии в S3.
План внедрения (чек-лист)
- Два VDS в одном L2-сегменте, выделенный VIP.
- Установка Nginx и keepalived, настройка sysctl.
- Единые конфиги Nginx, маршрут health check.
- Конфиг keepalived: VRID, приоритеты, unicast/multicast, VIP, GARP.
- Health checks и веса, опционально хуки notify.
- Тесты failover: Nginx stop, keepalived stop, link flap.
- Мониторинг, алерты, документация runbook’а.
Итоги
Связка Nginx + keepalived/VRRP с плавающим IP — простой и понятный способ получить высокую доступность фронтенда на VDS. Ключ к успеху — дисциплина: единые конфиги, корректные health checks, аккуратный тюнинг ARP и предсказуемая процедура переключения. Так вы сократите простои до секунд и сможете обслуживать систему без страха «уронить прод» при каждом обновлении ядра или прокси.


