Перейти к содержанию

Рабочие процедуры (Runbooks)

Уровни доступа

  • L2 — может выполнять диагностику (проверки, логи, health check) и перезапуск отдельных контейнеров.
  • L3 — может менять конфигурацию, деплоить серверы, работать с MySQL напрямую, менять DNS.
  • Процедуры с пометкой ⚠️ L3 требуют согласования с DevOps Lead.

Аварийные процедуры

API недоступен (P0)

Симптомы: клиенты не могут подключиться, api.shivavpn.io таймаутит.

# 1. Проверить прокси
ssh -p 2255 root@212.70.189.60 "docker ps; nginx -t"

# 2. Проверить бэкенд
./scripts/ssh-internal.sh 10.99.87.249 \
  "docker ps --filter name=vpn-back; curl -s http://localhost:8080/actuator/health"

# 3. Если бэкенд упал — рестарт
./scripts/ssh-internal.sh 10.99.87.249 "docker restart vpn-back-blue"
# или vpn-back-green — смотри какой активный

# 4. Если не помогает — проверить ресурсы
./scripts/ssh-internal.sh 10.99.87.249 "free -h; df -h; docker stats --no-stream"

Redis упал — массовый разлогин (P0)

Симптомы: все пользователи одновременно разлогинились.

Redis хранит все auth сессии

Рестарт Redis = разлогин ВСЕХ пользователей. Перезапускать только при необходимости.

# 1. Проверить статус
./scripts/ssh-internal.sh 10.99.87.249 "docker ps | grep redis"

# 2. Проверить память
./scripts/ssh-internal.sh 10.99.87.249 "docker exec redis redis-cli INFO memory"

# 3. Рестарт (крайняя мера)
./scripts/ssh-internal.sh 10.99.87.249 "docker restart redis"

Redis: stop-writes-on-bgsave-error (P1)

Симптомы: Redis отклоняет команды записи (MISCONF Redis is configured to save RDB snapshots, but it is currently not able to persist on disk), обычно из-за заполненного диска.

# 1. Проверить диск
./scripts/ssh-internal.sh 10.99.87.249 "df -h"

# 2. Если диск полон — освободить место
./scripts/ssh-internal.sh 10.99.87.249 "docker image prune -a -f"
./scripts/ssh-internal.sh 10.99.87.249 "journalctl --vacuum-size=100M"

# 3. Отключить блокировку записи (временно)
./scripts/ssh-internal.sh 10.99.87.249 \
  "docker exec redis redis-cli -a '\$(см. Vaultwarden → Redis)' \
   CONFIG SET stop-writes-on-bgsave-error no"

# 4. Принудительный BGSAVE
./scripts/ssh-internal.sh 10.99.87.249 \
  "docker exec redis redis-cli -a '\$(см. Vaultwarden → Redis)' BGSAVE"

# 5. Когда диск освобождён — вернуть защиту
./scripts/ssh-internal.sh 10.99.87.249 \
  "docker exec redis redis-cli -a '\$(см. Vaultwarden → Redis)' \
   CONFIG SET stop-writes-on-bgsave-error yes"

MySQL: Too many connections (P1)

⚠️ L3 — убивание процессов MySQL только по согласованию

# 1. Текущие подключения
./scripts/ssh-internal.sh 10.99.87.62 \
  "docker exec vpn-db mysql -uvpn -p'$(см. Vaultwarden  Databases)' -e 'SHOW STATUS LIKE \"Threads_connected\"'"

# 2. Убить спящие подключения (>5 мин)
./scripts/ssh-internal.sh 10.99.87.62 \
  "docker exec vpn-db mysql -uvpn -p'$(см. Vaultwarden  Databases)' -e \"
    SELECT CONCAT('KILL ', id, ';')
    FROM information_schema.processlist
    WHERE command = 'Sleep' AND time > 300;\" | tail -n +2 | \
  docker exec -i vpn-db mysql -uvpn -p'$(см. Vaultwarden  Databases)'"

# 3. Временно увеличить лимит
./scripts/ssh-internal.sh 10.99.87.62 \
  "docker exec vpn-db mysql -uvpn -p'$(см. Vaultwarden  Databases)' -e 'SET GLOBAL max_connections = 500'"

Диск заполнен (P1)

# 1. Проверить
./scripts/ssh-internal.sh 10.99.87.249 "df -h"

# 2. Почистить Docker
./scripts/ssh-internal.sh 10.99.87.249 "docker system prune -a -f"

# 3. Почистить логи
./scripts/ssh-internal.sh 10.99.87.249 "journalctl --vacuum-time=3d"

# 4. MySQL binlogs
./scripts/ssh-internal.sh 10.99.87.62 \
  "docker exec vpn-db mysql -uvpn -p'$(см. Vaultwarden  Databases)' \
    -e 'PURGE BINARY LOGS BEFORE DATE_SUB(NOW(), INTERVAL 3 DAY)'"

Ограничения journald и Docker

journald ограничен 500M (SystemMaxUse=500M в /etc/systemd/journald.conf). Docker образы очищаются еженедельно через cron: /etc/cron.d/docker-cleanup (docker image prune -a -f).

Деплой

Backend (auto CI/CD)

Push в main → автоматический blue-green деплой.

# Проверить текущее состояние
./scripts/ssh-internal.sh 10.99.87.249 "cat /opt/deploy/.deploy-state"

# Откат
./scripts/ssh-internal.sh 10.99.87.249 "/opt/deploy/deploy-backend.sh --rollback"

# Контейнеры: vpn-back-blue (:8080) / vpn-back-green (:8081)
# nginx upstream: equal-weight 8080/8081, fail_timeout=10s

VPN Config Service (manual deploy)

# CI/CD (push → test → build → manual trigger deploy_prod)
cd vpn-config-service && git push

Mass Server Drop alert

После рестарта worker'а — last_sync устареет на ~10 мин (пока идёт full_sync). Это ожидаемое поведение, не баг.

Admin Frontend (manual deploy)

Push в main → auto build → manual trigger update_service_prod.

GitLab project ID: 39, target: 10.99.87.64:80.

Обслуживание

Ручная проверка состояния системы

# API layers
curl -I https://api.shivavpn.io                          # External
curl -I https://212.70.189.60                            # Proxy direct
curl http://10.99.87.249:8080/actuator/health            # Backend direct

# Docker containers
./scripts/ssh-internal.sh 10.99.87.249 \
  "docker ps --format 'table {{.Names}}\t{{.Status}}\t{{.RunningFor}}'"

# Resources
./scripts/ssh-internal.sh 10.99.87.249 "free -h; df -h; docker stats --no-stream"

Продлить подписку пользователю

./scripts/ssh-internal.sh 10.99.87.249 'TOKEN=$(curl -s -X POST \
  http://localhost:8080/api/auth/login/admin \
  -H "Content-Type: application/json" \
  -d "{\"login\":\"admin@shivavpn.io\",\"password\":\"<см. Vaultwarden → Databases → MySQL PROD>\"}" \
  | python3 -c "import sys,json; print(json.load(sys.stdin)[\"accessToken\"])") && \
  curl -s -X POST \
  "http://localhost:8080/api/admin/maintenance/accounts/ACCOUNT_NUMBER/add-days?days=30" \
  -H "Authorization: Bearer $TOKEN"' 2>/dev/null

Заменить ACCOUNT_NUMBER (16 цифр) и days=30.

Принудительная синхронизация аккаунта

# Через Backend Admin API
TOKEN=<получить через login>
curl -X POST \
  "http://10.99.87.249:8080/api/admin/maintenance/sync/account/by-login/<ACCOUNT>" \
  -H "Authorization: Bearer $TOKEN"

# Через VPN Config Service
curl -X POST "http://10.99.87.249:8000/api/v1/sync/fast?force=true" \
  -H "X-API-Key: [API key: см. Vaultwarden]"

Рестарт VPN сервера (XUI)

Никогда не делай docker restart xray

Это отключит ВСЕХ пользователей на сервере. Для изменения конфигов используй X-UI API (addClient/delClient), xray подхватывает через gRPC hot-reload.

# Только если сервер реально не работает:
ssh -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519_shivavpn root@<IP>
systemctl restart xray
journalctl -u xray --tail 50

Бэкап MySQL

TIMESTAMP=$(date +%Y%m%d_%H%M%S)
./scripts/ssh-internal.sh 10.99.87.62 \
  "docker exec vpn-db mysqldump -uvpn -p'$(см. Vaultwarden  Databases)' \
    --single-transaction --quick vpn" | gzip > shiva_backup_$TIMESTAMP.sql.gz

Диагностика VPN сервера (XUI)

# Проверить состояние xray
ssh -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519_shivavpn root@SERVER_IP
systemctl status xray
journalctl -u xray --tail 50
ss -tlnp | grep 443
xray -test -config /usr/local/etc/xray/config.json

docker restart xray

Отключает ВСЕХ пользователей на сервере. Для изменения конфигов используй X-UI API (hot-reload через gRPC). Рестартовать systemctl только если сервер реально не работает.

Обновление сертификатов

# Проверить срок
ssh shivavpn-proxy "docker exec nginx_app_1 certbot certificates"

# Обновить
docker exec nginx_app_1 certbot renew
docker exec nginx_app_1 nginx -s reload

# Проверить
openssl s_client -connect api.shivavpn.io:443 -servername api.shivavpn.io \
  2>/dev/null | openssl x509 -noout -dates

DDoS атака

⚠️ L3 — блокировка IP на прокси

# 1. Проверить подключения
ssh shivavpn-proxy
netstat -anp | grep :443 | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -n

# 2. Заблокировать IP
iptables -A INPUT -s BAD_IP -j DROP

Безопасность

Реагирование на инцидент безопасности

⚠️ L3 only — немедленно связаться с DevOps Lead

# 1. Изолировать скомпрометированную систему
iptables -A INPUT -j DROP  # блокировать весь входящий трафик

# 2. Сохранить доказательства
tar -czf /tmp/incident_$(date +%Y%m%d).tar.gz /var/log

# 3. Проверить признаки компрометации
last -10              # последние логины
ps auxf               # запущенные процессы
netstat -tulpn        # открытые порты
find / -mtime -1 -type f  # файлы изменённые за последние 24ч

# 4. Сброс учётных данных
# Сменить все пароли (см. Vaultwarden)
# Ротировать SSH ключи
# Отозвать API токены

# 5. Восстановление сервиса
# Пересобрать из чистого образа
# Восстановить из бэкапа
# Применить патчи безопасности

После инцидента: задокументировать инцидент (monorepo: incidents/INCIDENT-NAME-YYYY-MM-DD.md).

Ротация паролей

⚠️ L3 only — ротация паролей затрагивает все сервисы

# 1. MySQL root
./scripts/ssh-internal.sh 10.99.87.62 \
  "docker exec vpn-db mysql -uroot -p'\$MYSQL_ROOT_PASS' -e \
    \"ALTER USER 'root'@'%' IDENTIFIED BY 'NEW_PASSWORD'; FLUSH PRIVILEGES;\""

# 2. Обновить в Vaultwarden → Databases → MySQL PROD

# 3. Обновить конфигурацию backend
./scripts/ssh-internal.sh 10.99.87.249 \
  "grep DB_PASSWORD /opt/deploy/.env"
# Заменить значение, затем:
./scripts/ssh-internal.sh 10.99.87.249 "docker restart vpn-back-blue vpn-back-green"

# 4. Обновить VPN Config Service
./scripts/ssh-internal.sh 10.99.87.249 \
  "nano /opt/vpn-config-service/.env && docker restart vpn-config-service vpn-config-worker"

# 5. Проверить доступность
curl http://10.99.87.249:8080/actuator/health
curl http://10.99.87.249:8000/health

Окно обслуживания

# 1. За 24 часа до начала
# - Обновить статус-страницу
# - Отправить анонс в Telegram

# 2. Подготовка (перед началом)
./scripts/ssh-internal.sh 10.99.87.249 \
  "docker tag vpn-back-blue:latest vpn-back-blue:rollback"
./scripts/ssh-internal.sh 10.99.87.62 \
  "docker exec vpn-db mysqldump -uvpn -p'\$MYSQL_PASS' \
    --single-transaction vpn | gzip > /tmp/backup_pre_maintenance.sql.gz"

# 3. Выполнить обслуживание
# (следовать конкретному runbook)

# 4. Проверка после завершения
curl -I https://api.shivavpn.io
curl http://10.99.87.249:8080/actuator/health
curl http://10.99.87.249:8000/health

# 5. Мониторинг 2 часа
watch -n 30 'docker logs vpn-back-blue --tail 5'
# Проверять Grafana на аномалии (online_sessions, error rate)

Уровни критичности

Уровень Описание Время реакции
P0 Полный аутейдж, потеря данных < 15 мин
P1 Частичный аутейдж, деградация > 50% < 1 час
P2 Отдельные фичи не работают < 4 часа
P3 Косметические проблемы Следующий спринт

Контакты

  • Max — Product Owner (бизнес-решения)
  • Nikita — Ops (доступ к инфраструктуре)
  • zardes — DevOps + Backend (техническая часть)