This is the multi-page printable view of this section. Click here to print.
Администрирование
- 1: MySQL
- 2: Что нового в 3.0
- 3: Обновление SHM
- 4: Разное
- 5: Безопасность
1 - MySQL
Создание архивной копии (Backup)
docker compose exec -T mysql /bin/bash -c 'MYSQL_PWD=${MYSQL_ROOT_PASSWORD} mysqldump -u root shm' > shm_backup.sql
Восстановление БД из архива (Restore)
docker compose exec -T mysql /bin/bash -c 'MYSQL_PWD=${MYSQL_ROOT_PASSWORD} mysql -u root shm' < shm_backup.sql
Периодические бэкапы
mysql_backup.sh
DOCKER_COMPOSE_PATH="/opt/shm"
BACKUP_DIR="/opt/shm/backups"
mkdir -p ${BACKUP_DIR}
cd ${DOCKER_COMPOSE_PATH}
docker compose exec -T mysql /bin/bash -c 'MYSQL_PWD=${MYSQL_ROOT_PASSWORD} mysqldump -u root shm' > ${BACKUP_DIR}/shm_$(date +%d%m%Y-%H%M%S).sql
2 - Что нового в 3.0
SHM 3.0
Версия 3.0 — крупный релиз, в котором переработана система авторизации пользователей, добавлены новые каналы связи и модули аналитики, а также существенно усилена безопасность API. Ниже перечислены основные изменения относительно ветки 2.0.
Перед обновлением
Сделайте резервную копию БД — при первом запуске 3.0 автоматически применяются миграции, часть из которых необратимо меняет структуру таблиц (например, объединение логинов в единую таблицуaccounts). Подробности —
на странице Обновление SHM.
Единая система логинов (Accounts)
Раньше данные для входа пользователя были размазаны по нескольким полям:
login, login2, settings.email, settings.telegram и т.д. В 3.0 они
объединены в единую таблицу accounts — у одного пользователя теперь может
быть произвольное количество способов входа (login, email, telegram,
oauth2 и др.), каждый описывается парой (login, type).
- Новый модуль
Core::User::Loginsуправляет привязкой/поиском аккаунтов - Новые методы API:
/user/accounts,/admin/user/accounts - Миграция
3.0.0.sqlавтоматически переносит существующиеlogin,login2и e-mail/Telegram изsettingsв новую таблицу при обновлении - Отдельный метод
/user/email/verifyубран — подтверждение e-mail теперь часть общего механизма аккаунтов
OAuth2-авторизация
Добавлена авторизация через внешние OAuth2-провайдеры: Google,
Yandex, GitHub (модули Core::Auth::OAuth2::*).
Новые публичные методы:
/oauth2/init/{provider}/oauth2/start/{provider}/oauth2/callback/{provider}
Транспорт MAX
Добавлен новый мессенджер-транспорт MAX (Core::Transport::Max) — по
аналогии с Telegram: приём вебхуков, авторизация WebApp, команда /start.
Новые методы API: /max/bot/*, /max/set_webhook, /max/webapp/auth.
Очереди задач (Spool Queues)
Добавлен модуль Core::SpoolQueue и таблица spool_queues — теперь задачи
в очереди (spool) можно группировать в именованные очереди с собственным
rate_limit (лимит задач в секунду) и управлением через API:
/admin/spool/queues— список/создание очередей/admin/spool/queues/pause,/admin/spool/queues/resume,/admin/spool/queues/delete
Дополнительно:
- Новый статус задачи
SKIPPED - Поддержка приоритетов при постановке задач в очередь
- Глобальный таймаут задач через переменную окружения
TASK_TIMEOUT
Модуль статистики
Добавлен модуль Core::Statistics и таблица statistics — агрегированные
по дням показатели (количество, сумма, min/max/avg) по ключевым метрикам
биллинга.
Логирование API-запросов
Добавлен модуль Core::Logs::Api и таблица logs_api — все запросы к API
пишутся отдельной транзакцией (пользователь, IP, метод, URL, аргументы,
код ответа, длительность). Просмотр — /admin/logs/api. Чувствительные
данные (пароли, токены и т.п.) в логе рекурсивно маскируются.
Безопасность
- Валидация параметров API v1: все методы
v1.cgiпереведены с форматаrequired => [...]на полную схемуparams => { ... }с проверкой типов, длины и обязательности каждого поля - Telegram WebApp/OIDC: подпись (HMAC) и срок действия
auth_dateтеперь проверяются до поиска пользователя; убрана поддержкаlogin_prefix— используется «сырой» Telegramuser_id - Passkey: обязательная проверка при аутентификации
- Смена пароля: требует ввода старого пароля; смена пароля возможна только для собственного логина (запрещено менять пароль по чужому логину)
- Из редиректов OAuth/Telegram авторизации убран
session_id(передаётся иным защищённым способом)
База данных
- Все таблицы переведены с
MyISAMнаInnoDB - Поле
users.passwordрасширено доVARCHAR(128)— для поддержки современных алгоритмов хеширования - Добавлен индекс
idx_forecast_candidatesвuser_services, ускоряющий расчёт прогноза списаний (Core::Pay)
Прочее
- Шаблонизатор: фильтры
isTrue/isFalse, поддержкаgroup_byв System - Возможность задавать приоритет событиям (
events) - Флаг
payment_modeдля платёжных виджетов в WebApp - Режим авто-перезагрузки SHM при разработке (
dev)
3 - Обновление SHM
Обновление версии SHM
Рекомендуем делать резервную копию БД SHM перед обновлением
- Перейдите в директорию с Вашим файлом:
docker-compose.yml - Загрузите новые образы:
docker compose pull - Перезапустите контейнеры:
docker compose down && docker compose up -d
4 - Разное
Просмотр логов
Если что-то пошло не так и есть необходимость посмотреть логи, то:
- Перейдите в директорию с Вашим файлом:
docker-compose.yml - Выполните команду:
docker compose logs -f
Сброс пароля пользователя admin
Если Вы забыли пароль администратора, то можно его сбросить следующим образом:
- Перейдите в директорию с Вашим файлом:
docker-compose.yml - Выполните команду:
docker compose exec core scripts/reset_admin_pass.cgi
Разрешить вход по паролю
Если вы потеряли доступ к Passkey, то можно включить вход по паролю следующим образом:
- Перейдите в директорию с Вашим файлом:
docker-compose.yml - Выполните команду:
docker compose exec core scripts/enable_password_auth.cgi
Редактирование стилей (CSS) клиентского кабинета
- Перейдите в директорию с Вашим файлом:
docker-compose.yml - Скачайте текущий файл стилей:
wget https://raw.githubusercontent.com/danuk/shm-client/master/app/assets/css/styles-alternative.css - Раскоментируйте строки в файле
docker-compose.yml:
# volumes:
# - ./styles-alternative.css:/app/assets/css/styles-alternative.css
- Перезапустите SHM:
docker compose down
docker compose up -d
Теперь Вы можете править файл стилей styles-alternative.css и наблюдать результат в клиентском интерфейсе пользователя (обновляя страницу браузера).
Перенос SHM на другой сервер
Если возникла необходимость в переносе SHM на другой сервер, то выполните следующие шаги:
- Сделайте архивную копию БД на текущем сервере
- Установите и запустите SHM на новом сервере
- Восстановите БД нового SHM из архивной копии (с первого шага)
5 - Безопасность
Безопасность API
SHM имеет встроенные системы безопасности, такие как:
- Общее ограничение количества запросов в API за определенное время (RPS)
- Ограничения на количество запросов в методы аутентификации
- Ограничения на количество запросов в методы регистрации клиентов и их услуг
- Проверка токенов Telegram и многие другие
Лимиты
При превышении одного из следующих лимитов пользователь получит ошибку HTTP: 429 Too Many Requests.
Лимиты накладываются на IP-адрес пользователя.
Общие ограничения HTTP запросов в API
- 1 запрос в секунду. Допускается кратковременное превышение этого лимита до 5 запросов в секунду.
Эти лимиты не распространяются на внутренние IP-адреса (127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16)
Включение/отключение HTTP rate limiting
HTTP rate limiting на уровне nginx отключен по умолчанию. Для его включения необходимо установить переменную окружения ENABLE_RATE_LIMIT=true.
Включение rate limiting:
services:
api:
environment:
ENABLE_RATE_LIMIT: "true"
Настройка через .env файл:
ENABLE_RATE_LIMIT=true
Поведение в зависимости от значения:
Значение ENABLE_RATE_LIMIT |
HTTP rate limiting |
|---|---|
true |
✅ Включен |
false |
❌ Отключен |
| Не указано | ❌ Отключен (по умолчанию) |
| Пустая строка | ❌ Отключен |
Важно: Отключение HTTP rate limiting не влияет на внутренние лимиты SHM (аутентификация, регистрация и т.д.). Эти лимиты всегда активы при наличии Redis.
Настройка проброса реальных IP-адресов
Критически важно: Для корректной работы всех типов лимитов необходимо убедиться, что в логах контейнера API отображаются реальные IP-адреса клиентов, а не IP прокси-сервера или балансировщика нагрузки.
Проверка текущих IP в логах:
Перейдите в директорию, где находится ваш файл: docker-compose.yml и выполните команду:
# Просмотр логов API контейнера
docker compose logs api --tail=10
# 'remote_addr' должен содержать реальные IP клиентов, а не 172.x.x.x или другие внутренние адреса
Если в логах отображаются внутренние IP-адреса (например, 172.18.0.1, 10.0.0.1), необходимо настроить прокси-сервер для передачи заголовков с реальными IP.
Настройка проброса IP для различных прокси-серверов
1. Nginx (рекомендуемый)
Базовая конфигурация:
server {
...
# Передача реальных IP адресов
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
...
}
2. Caddy
Базовая конфигурация (Caddyfile):
your-domain.com {
reverse_proxy localhost:8080 {
header_up X-Real-IP {remote_host}
header_up X-Forwarded-For {remote_host}
}
}
3. HAProxy
Базовая конфигурация:
frontend shm_frontend
...
# Добавление заголовков с реальными IP
option forwardfor
http-request set-header X-Real-IP %[src]
...
Настройка для облачных сервисов
Cloudflare
# Добавить в nginx конфигурацию
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 103.22.200.0/22;
set_real_ip_from 103.31.4.0/22;
set_real_ip_from 141.101.64.0/18;
set_real_ip_from 108.162.192.0/18;
set_real_ip_from 190.93.240.0/20;
set_real_ip_from 188.114.96.0/20;
set_real_ip_from 197.234.240.0/22;
set_real_ip_from 198.41.128.0/17;
set_real_ip_from 162.158.0.0/15;
set_real_ip_from 104.16.0.0/13;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 131.0.72.0/22;
real_ip_header CF-Connecting-IP;
AWS Application Load Balancer
В конфигурации ALB убедитесь, что включены атрибуты:
routing.http.preserve_host_header.enabled = truerouting.http.x_amzn_trace_id.enabled = true
Устранение проблем
Проблема: В логах отображаются внутренние IP
Решение:
- Убедитесь, что прокси передает заголовки
X-Forwarded-ForилиX-Real-IP - Проверьте настройки
set_real_ip_fromв nginx.conf контейнера API - Убедитесь, что IP прокси-сервера включен в
set_real_ip_from
Проблема: Rate limiting не работает для внешних IP
Решение:
- Проверьте, что в логах отображаются реальные IP клиентов
- Убедитесь, что
ENABLE_RATE_LIMIT=true - Проверьте, что IP клиента не входит в
TRUSTED_IPS
Исключение доверенных IP-адресов из лимитов
Вы можете настроить список доверенных IP-адресов, которые будут исключены из всех ограничений rate limiting с помощью переменной окружения TRUSTED_IPS.
Примечание: Переменная
TRUSTED_IPSработает независимо отENABLE_RATE_LIMIT. Доверенные IP исключаются из внутренних лимитов SHM даже при отключенном HTTP rate limiting.
Настройка через docker-compose.yml:
services:
api:
environment:
ENABLE_RATE_LIMIT: "true" # Включить HTTP rate limiting
TRUSTED_IPS: "192.168.1.0/24,10.0.0.1,172.20.0.0/16"
Поддерживаемые форматы:
- Отдельные IP-адреса:
192.168.1.100 - CIDR диапазоны:
192.168.1.0/24,10.0.0.0/8 - IPv6 адреса и диапазоны:
2001:db8::/32 - Список через запятую:
192.168.1.100,10.0.0.0/8,172.16.0.1
Область действия:
- Nginx rate limiting - исключение на уровне веб-сервера
- Application rate limiting - исключение на уровне приложения SHM
- Применяется ко всем типам ограничений (HTTP запросы, аутентификация, регистрация и т.д.)
Пример настройки:
services:
api:
environment:
# Исключить корпоративную сеть и админские IP
TRUSTED_IPS: "192.168.0.0/16,10.1.1.100,10.1.1.101"
Внутренние лимиты SHM
- Неуспешная аутентификация пользователя: 5 за 3 минуты (блокировка на 3 минуты)
- Регистрация пользователя: 5 за час (блокировка на час)
- Регистрация услуги пользователем: 5 за 10 минут (блокировка на 10 минут)
- Неуспешная аутентификация Telegram: 5 за час (блокировка на час)
Для работы этих ограничений необходимо убедиться, что запущен Redis.
Блокировка IP-адресов пользователей на сервере
Вы можете настроить автоматическую блокировку IP-адресов на уровне сервера с помощью fail2ban. Это обеспечит дополнительную защиту от злоупотреблений API.
Настройка логирования
1. Настройка Docker Compose
Раскомментируйте в файле docker-compose.yml строки для логирования API контейнера:
services:
api:
# ... другие настройки ...
logging:
driver: syslog
options:
syslog-address: "udp://127.0.0.1:514"
tag: "shm-api"
2. Настройка rsyslog
Создайте конфигурацию rsyslog для приема логов от Docker:
# Создайте файл /etc/rsyslog.d/49-docker.conf
sudo tee /etc/rsyslog.d/49-docker.conf << 'EOF'
# Включить UDP модуль для приема логов от Docker
module(load="imudp")
input(type="imudp" port="514")
# Шаблон для очистки JSON логов от Docker префиксов
$template SHMAPITemplate,"%msg:2:$%\n"
# Направить логи SHM API в отдельный файл
if $programname == 'shm-api' then /var/log/shm-api.log;SHMAPITemplate
& stop
EOF
# Создайте директорию для логов
sudo mkdir -p /var/log
sudo touch /var/log/shm-api.log
sudo chmod 644 /var/log/shm-api.log
# Перезапустите rsyslog
sudo systemctl restart rsyslog
Настройка fail2ban
1. Установка fail2ban
Ubuntu/Debian:
sudo apt update
sudo apt install fail2ban
2. Создание фильтра
Создайте фильтр для обработки JSON логов SHM API:
sudo tee /etc/fail2ban/filter.d/shm-api-json-429.conf << 'EOF'
# Fail2Ban filter for SHM API JSON format logs
[Definition]
failregex = ^.*"remote_addr"\s*:\s*"<HOST>".*"status"\s*:\s*429.*$
ignoreregex = ^.*"remote_addr"\s*:\s*"<HOST>".*"status"\s*:\s*(?:200|201|202|204|301|302|304).*$
datepattern = "time"\s*:\s*"%%Y-%%m-%%dT%%H:%%M:%%S
EOF
3. Создание jail конфигурации
Создайте jail для автоматической блокировки:
sudo tee /etc/fail2ban/jail.d/shm-api-json-429.conf << 'EOF'
# SHM API protection jail
[shm-api-json-429]
enabled = true
port = http,https
filter = shm-api-json-429
logpath = /var/log/shm-api.log
maxretry = 5
findtime = 300
bantime = 3600
ignoreip = 127.0.0.1/8 ::1 172.16.0.0/12 192.168.0.0/16 10.0.0.0/8
action = iptables-multiport[name=shm-api-429, port="http,https", protocol=tcp]
EOF
4. Параметры блокировки
- maxretry: 5 - количество попыток до блокировки
- findtime: 300 секунд (5 минут) - период анализа попыток
- bantime: 3600 секунд (1 час) - время блокировки IP-адреса
Запуск и проверка
1. Запуск fail2ban
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
2. Проверка статуса
# Общий статус fail2ban
sudo fail2ban-client status
# Статус конкретного jail
sudo fail2ban-client status shm-api-json-429
# Просмотр заблокированных IP-адресов
sudo fail2ban-client get shm-api-json-429 banip
3. Мониторинг
# Мониторинг логов fail2ban
sudo tail -f /var/log/fail2ban.log | grep shm-api
# Мониторинг логов API
sudo tail -f /var/log/shm-api.log
# Проверка iptables правил
sudo iptables -L f2b-shm-api-json-429 -n
Управление блокировками
Разблокировка IP-адресов
# Разблокировать конкретный IP-адрес
sudo fail2ban-client set shm-api-json-429 unbanip 192.168.1.100
# Разблокировать все IP-адреса в jail
sudo fail2ban-client unban --all
Настройка уведомлений
Для получения уведомлений о блокировках добавьте в jail конфигурацию:
[shm-api-json-429]
# ... остальные параметры ...
# Email уведомления
action = %(action_mwl)s
destemail = admin@example.com
sendername = Fail2Ban SHM API
sender = fail2ban@example.com
Логротация
Настройте ротацию логов для предотвращения переполнения диска:
sudo tee /etc/logrotate.d/shm-api << 'EOF'
/var/log/shm-api.log {
daily
rotate 30
compress
delaycompress
missingok
notifempty
create 644 syslog syslog
postrotate
/bin/systemctl reload rsyslog > /dev/null 2>&1 || true
endscript
}
EOF
Рекомендации по безопасности
- Мониторинг: Регулярно проверяйте логи fail2ban и заблокированные IP-адреса
- Настройка: Корректируйте параметры
maxretry,findtimeиbantimeв зависимости от нагрузки - Whitelist: Добавляйте доверенные IP-адреса в
ignoreipдля избежания случайных блокировок - Интеграция с TRUSTED_IPS: Синхронизируйте списки доверенных IP между
TRUSTED_IPSиignoreipв fail2ban - Резервное копирование: Регулярно создавайте резервные копии конфигураций fail2ban
- Обновления: Поддерживайте fail2ban в актуальном состоянии
Важно: IP-адреса, указанные в переменной
TRUSTED_IPS, автоматически исключаются из rate limiting на уровне приложения, но могут по-прежнему блокироваться fail2ban. Рекомендуется также добавлять их в параметрignoreipконфигурации fail2ban.
Устранение неполадок
Проблема: Jail не запускается
# Проверка конфигурации
sudo fail2ban-client --test
# Проверка логов
sudo journalctl -u fail2ban -n 50
Проблема: IP-адрес не блокируется
# Тестирование фильтра
sudo fail2ban-regex /var/log/shm-api.log /etc/fail2ban/filter.d/shm-api-json-429.conf
# Проверка формата логов
sudo tail -5 /var/log/shm-api.log