Как защитить серверы SA-MP и open.mp от DDoS-атак
SA-MP и open.mp пропускают игру, query и RCON через один-единственный UDP-порт. Руководство показывает, что вы можете закрыть сами и с какого размера атаки помогает только фильтрация в сети перед сервером.
Проект на SA-MP или open.mp растёт почти всегда по одному сценарию: число игроков увеличивается, сервер поднимается в списке, а через несколько дней соединения начинают обрываться одно за другим. Самая длинная часть этого руководства посвящена тому, что вы можете изменить на своём сервере сами и без дополнительных расходов. Дальше разбирается, где такие меры технически заканчиваются, и только потом, что противопоставляет им KernelHost.
Почему под удар так часто попадают именно SA-MP и open.mp
Сцена узкая и конкурентная. Множество ролевых и freeroam-серверов борется за одну и ту же аудиторию, а порог, чтобы на пару часов выбить конкурента из списка, здесь низкий. К этому добавляются забаненные игроки и попытки шантажа проектов с собственным магазином.
Технически игра сильно облегчает задачу атакующему. Весь игровой трафик идёт по UDP, а UDP не устанавливает соединение, которое чего-то стоило бы атакующему; вдобавок адрес отправителя легко подделать. Запись в списке серверов публикует адрес и порт, поэтому предварительная разведка не нужна. И поскольку большинство проектов живёт на одном сервере, игровой сервер, база данных, пользовательская панель и часто голосовой сервер находятся на одном адресе: одно попадание выводит из строя сразу всё.
О каких портах и протоколах идёт речь
- Сервер SA-MP: UDP 7777 по умолчанию, меняется параметром
portвserver.cfg. - Сервер open.mp: тоже UDP 7777 по умолчанию, меняется параметром
network.portвconfig.json. - Query: тот же самый UDP-порт. Отдельного порта для запросов не существует. Браузеры серверов, страницы статуса и Discord-боты обращаются ровно к тому порту, через который идёт игра.
- RCON: тоже тот же UDP-порт, отдельным опкодом внутри протокола query и в открытом виде.
- Регистрация в списке серверов уходит исходящим трафиком на соответствующий список, входящее соединение для этого открывать не нужно.
- Всё остальное на той же машине: SSH на TCP 22, MariaDB или MySQL на TCP 3306, пользовательская панель на TCP 80 и 443.
Отсюда следствие: отделить доступ к query от игрового трафика с помощью файрвола невозможно, потому что и то и другое живёт на одном порту. Кто закрывает UDP 7777, закрывает вход своим же игрокам.
Запрос query начинается с одиннадцати байт: четыре байта сигнатуры, четыре байта адреса сервера, два байта порта и один байт опкода. Опкод определяет ответ: i отдаёт информацию о сервере, r правила, c короткий список игроков, d подробный список с именем, счётом и пингом каждого игрока, p возвращает обратно четыре байта для замера пинга, x это RCON. На хорошо заполненном сервере одиннадцать байт запроса порождают несколько килобайт ответа. Именно поэтому открытый доступ к query интересен вдвойне: и как цель, и как усилитель для атаки на третьих лиц. Что стоит за такой схемой атаки, разбирает статья Что такое DDoS-атака?.
Что вы можете сделать сами, прежде чем тратить деньги
Следующие шаги ничего не стоят и работают против атак, которые составляют повседневность: флуд подключениями, флуд query-запросами и отдельные источники с высокой частотой пакетов. Все команды предполагают root, иначе добавляйте перед ними sudo.
1. Инвентаризация: что вообще слушает порты?
ss -lnup
ss -lntp
Тому, что слушает на 127.0.0.1 или ::1, правило файрвола не нужно. А всё, что стоит на 0.0.0.0 или [::], доступно снаружи, и для этого должна быть причина.
2. Закройте всё, что игровому серверу не нужно
Пакетный фильтр не устраняет объёмную атаку, но уменьшает поверхность атаки. Рабочая стартовая конфигурация на UFW:
ufw allow 22/tcp comment 'SSH'
ufw allow 7777/udp comment 'SA-MP / open.mp'
ufw default deny incoming
ufw default allow outgoing
ufw --force enable
ufw status verbose
Порядок здесь не случаен: разрешающие правила идут до включения, иначе вы закроете доступ самому себе. Подробности вместе с путём назад описаны в статье Настройка файрвола UFW без потери доступа к серверу. На KVM root-серверах и выделенных серверах KernelHost в аварийной ситуации вы попадёте в систему через VNC-консоль в личном кабинете.
Базе данных в открытой сети не место. Если ss -lntp | grep 3306 показывает 0.0.0.0:3306, пропишите bind-address = 127.0.0.1 и перезапустите службу. Игровой сервер тоже привяжите к конкретному адресу: в SA-MP через bind, в open.mp через network.bind.
3. Обезвредьте доступ к query, не закрывая вход игрокам
В server.cfg у SA-MP есть переключатель query 0, после которого сервер перестаёт отвечать на любые запросы. Это работает, но цена высока: сервер пропадает из браузера серверов, число игроков и правила больше не считываются, страницы статуса и Discord-боты показывают его офлайн. Для закрытого круга это вариант, для растущего проекта нет. В open.mp этот переключатель находится в разделе network файла config.json; точное имя ключа лучше проверить в своей версии, а не угадывать.
Поэтому реалистичный путь: ограничивать, а не отключать. Этот фильтр показывает в реальном времени только пакеты с сигнатурой query:
tcpdump -ni any -c 100 'udp port 7777 and udp[8:4] = 0x53414d50'
Какие адреса отправителей шлют больше всего трафика на игровой порт:
tcpdump -nn -q -c 2000 'udp dst port 7777' 2>/dev/null \
| awk '{print $3}' | cut -d. -f1-4 | sort | uniq -c | sort -rn | head -20
4. Задайте ограничения частоты в сетевом стеке
С помощью nftables вы ограничиваете частоту пакетов на каждый адрес отправителя. Набор ниже создаёт отдельную таблицу, чтобы не мешать UFW:
nft add table inet gameguard
nft add chain inet gameguard input '{ type filter hook input priority -150 ; policy accept ; }'
nft add rule inet gameguard input udp dport 7777 meter perip '{ ip saddr limit rate over 60/second burst 120 packets }' drop
nft list table inet gameguard
Дополнительно имеет смысл общий потолок на весь порт, чтобы широко распределённый флуд не просочился в зазор между множеством отдельных источников:
nft add rule inet gameguard input udp dport 7777 limit rate over 20000/second burst 5000 packets drop
В iptables того же добивается модуль hashlimit:
iptables -N SAMPGUARD
iptables -A INPUT -p udp --dport 7777 -j SAMPGUARD
iptables -A SAMPGUARD -m hashlimit --hashlimit-name samp --hashlimit-mode srcip \
--hashlimit-above 60/sec --hashlimit-burst 120 --hashlimit-htable-expire 30000 -j DROP
Эти числа — стартовые значения, а не рекомендация для вашего сервера. Один игрок только на синхронизации позиции создаёт несколько десятков пакетов в секунду; частоту вы задаёте в SA-MP через onfoot_rate, incar_rate и weapon_rate. Критично становится тогда, когда за одним адресом сидит сразу несколько игроков, например в одной квартире или за carrier-NAT мобильного оператора. Слишком жёсткий предел выбрасывает именно этих игроков, и выглядит это как атака. Сначала измеряйте, потом задавайте значения, потом следите за обрывами.
5. Предельные значения в server.cfg и config.json
Обе реализации приносят собственные защитные лимиты, которые чаще всего так и остаются на значениях по умолчанию. Для SA-MP в server.cfg:
lanmode 0
query 1
announce 1
rcon 0
conncookies 1
connseedtime 300000
minconnectiontime 1000
messageslimit 500
messageholelimit 3000
ackslimit 3000
playertimeout 10000
В open.mp те же самые величины лежат в config.json:
{
"network": {
"port": 7777,
"bind": "",
"use_lan_mode": false,
"cookie_reseed_time": 300000,
"minimum_connection_time": 1000,
"messages_limit": 500,
"message_hole_limit": 3000,
"acks_limit": 3000,
"player_timeout": 10000,
"limits_ban_time": 60000
},
"rcon": {
"enable": false
}
}
Что делают эти значения:
- Cookie подключения (
conncookiesиcookie_reseed_timeсоответственно) требуют от клиента ответа на встречный запрос, прежде чем будет занят слот. Поддельный адрес отправителя этот встречный запрос никогда не увидит и, значит, ответить на него не сможет. Это самый действенный встроенный тормоз против флуда подключениями, оставьте его включённым. - Минимальный интервал между попытками подключения (
minconnectiontimeиminimum_connection_timeсоответственно, в миллисекундах) не даёт одному и тому же адресу открывать новые соединения раз в секунду. Против заходов ботов это вторая по важности настройка. - Лимиты сообщений, пропусков и подтверждений (
messageslimit,messageholelimit,ackslimit) ограничивают, сколько разрешено слать уже установленному соединению. Они защищают от изменённых клиентов, но не от объёма. - Тайм-аут (
playertimeout,player_timeout) определяет, как долго молчащее соединение держит слот. Низкое значение быстрее освобождает места при флуде подключениями, но и раньше выбрасывает игроков с плохим каналом. Длительность блокировки (limits_ban_timeв open.mp) задаёт, сколько подозрительный адрес остаётся заблокированным.
Два замечания. config.json должен оставаться корректным JSON: одна лишняя запятая, и сервер не запустится. И open.mp сам дописывает недостающие параметры при старте, поэтому правьте файл на остановленном сервере.
Отдельно про RCON: пароль идёт по UDP в открытом виде и читается на всём пути. Если RCON вам не нужен, отключите его через rcon 0 или "enable": false, а если нужен, то действует правило: длинный случайный пароль и доступ только через VPN.
6. Защита в гейммоде и в плагинах
SA-MP вызывает OnIncomingConnection до того, как будет занят слот игрока. Прямо там вы можете вести счёт и временно блокировать подозрительные адреса:
public OnIncomingConnection(playerid, ip_address[], port)
{
if (ConnectAttemptsTooHigh(ip_address))
{
BlockIpAddress(ip_address, 60000);
}
return 1;
}
ConnectAttemptsTooHigh намеренно оставлена вашей собственной функцией подсчёта: разумные пороги зависят от вашего числа игроков. BlockIpAddress ожидает длительность блокировки в миллисекундах, UnBlockIpAddress снимает её досрочно. Список блокировок лежит в оперативной памяти и после перезапуска пуст.
Дополнительно в каждом проекте должны быть два инструмента. Плагин crashdetect при падении показывает функцию и строку в гейммоде; без него ошибка времени выполнения в собственном коде выглядит снаружи ровно как атака. Поддерживаемый анти-чит вроде Nex-AC закрывает манипуляции на стороне клиента, но работает исключительно с подключёнными игроками внутри игровой логики. Флуд поддельных пакетов никогда не станет игроком и проходит мимо него. Это две разные задачи.
Отдельно стоит держать инклуды и плагины в актуальном состоянии: несколько известных способов уронить сервер SA-MP основаны на значениях вне допустимого диапазона, которые передаются в нативные функции. И никогда не передавайте непроверенный ввод игрока в SendRconCommand или в запрос к базе данных.
7. Запись в списке серверов и ваш настоящий адрес
Запись в списке делает вас находимым, причём как для игроков, так и для атакующих. С announce 0 вы исчезаете из обоих списков, а вместе с этим и из органического притока игроков. Это компромисс, а не секретный приём.
Домен перед сервером не поможет: клиент разрешает имя один раз, а дальше общается напрямую с адресом, и разрешить это имя может кто угодно. Лучше проверьте, что ещё выдаёт ваш адрес: старые записи A и AAAA в DNS, пользовательская панель на той же машине, статус в Discord-боте, открытый веб-интерфейс базы данных, TLS-сертификаты со старыми именами хостов и сообщения на форумах из самого начала проекта.
Отсюда правило, которое многие проекты усваивают слишком поздно: переезжая на защищённый адрес, меняйте одновременно и исходный адрес. Иначе старый останется в каждой базе сканеров, и атака пойдёт мимо защиты.
8. Белый список и закрытый режим
Для игрового порта белый список редко применим на практике, потому что игроки приходят с меняющихся адресов. Пароль сервера (password в обеих реализациях) без всяких усилий превращает сервер в закрытый круг, а запись в списке при этом сохраняется. Зато для административных доступов белый список обязателен: для SSH, базы данных, панели и, если вы его оставили, RCON:
ufw allow from 203.0.113.10 to any port 22 proto tcp comment 'Admin'
ufw delete allow 22/tcp
ufw status numbered
Если ваш собственный адрес меняется, VPN аккуратнее, чем разрастающийся список исключений.
9. Логи: сначала измерить, потом действовать
SA-MP пишет свой лог в server_log.txt в каталоге сервера, open.mp в файл, заданный в разделе logging. Какие адреса стучатся чаще всего:
grep "Incoming connection" server_log.txt \
| grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' \
| sort | uniq -c | sort -rn | head -20
Большое число запрошенных cookie подключения указывает на флуд подключениями:
grep -c "requests connection cookie" server_log.txt
Но самое показательное значение лежит не в игровом логе, а в ядре. Если процесс сервера не успевает забирать пакеты из приёмного буфера, ядро считает потери:
nstat -az | grep -E 'Udp(InDatagrams|InErrors|NoPorts|RcvbufErrors)'
ip -s -s link show
Отсюда следует самое важное различие вообще: если ошибки буфера растут при низкой загрузке CPU, до вас доходит больше трафика, чем процесс успевает обработать. Если же одно ядро упирается в потолок, а трафик выглядит обычным, проблема в гейммоде, а не в сети. Как разделить эти два случая, описывает статья Как определить DDoS-атаку на сервере.
Где эти меры заканчиваются
Все описанные выше шаги срабатывают только тогда, когда пакеты уже прошли по вашему каналу: ядро отбрасывает их после прибытия. Тем самым задан жёсткий потолок, который никак не связан с качеством ваших правил.
Канал на 1 Гбит/с при минимально возможном размере пакета принимает около 1,49 миллиона пакетов в секунду, больше физически не проходит. Для сравнения две атаки, измеренные и отфильтрованные на серверах KernelHost: свыше 473,4 Гбит/с при более чем 41,5 миллиона пакетов в секунду на голосовой сервер на UDP 9987 и свыше 112,2 Гбит/с при более чем 8,7 миллиона пакетов в секунду на игровой сервер на UDP 7777. Первый случай — это примерно 473-кратная полоса и около 28-кратной частоты пакетов от того, что вообще способен принять канал на 1 Гбит/с. Даже идеальный фильтр на сервере ничего здесь не изменит, потому что пакеты до него просто не доходят: канал перед ним забит, а вместе с ним теряются и пакеты ваших игроков.
Ещё два ограничения срабатывают даже раньше. Во-первых, игровой сервер читает порт в одном-единственном потоке выполнения. Флуд query-запросами способен занять этот поток настолько, что пакеты синхронизации настоящих игроков пропадут в приёмном буфере задолго до того, как насытится канал. Процесс при этом не падает, он просто становится медленным, а игроки видят рывки и откаты позиции (rubberbanding). Во-вторых, адреса отправителей в UDP подделываются; блокировки по адресу тогда бьют по непричастным, а по атакующему не попадают вовсе.
Если коротко и без иллюзий: ваша работа на сервере решает, пройдёт ли небольшая атака. Пройдёт ли крупная, решает сеть перед сервером.
Что противопоставляет этому KernelHost
Входит в каждый сервер: двухуровневая постоянная защита
Каждый сервер в KernelHost стоит за постоянно активной двухуровневой фильтрацией:
- Уровень 1: глобальная scrubbing-сеть с ёмкостью mitigation 17 Тбит/с. Волюметрические атаки перехватываются и очищаются рядом с источником, ещё до того, как они вообще дойдут до дата-центра во Франкфурте-на-Майне.
- Уровень 2: фильтрация Arbor в реальном времени на 3,2 Тбит/с прямо на площадке во Франкфурте-на-Майне. Непосредственно перед сервером распознаются специфичные для протокола схемы, и трафик отбрасывается пакет за пакетом.
Решающими здесь оказываются три свойства. Защита активна постоянно, поэтому нет фазы обнаружения, во время которой ваш сервер уходит в офлайн. Null-routing не применяется: атакуемый адрес остаётся в сети, отсеиваются только вредоносные пакеты, а соединения настоящих игроков продолжают работать. И стоит она не отдельных денег, а входит в каждый серверный тариф, от KVM root-сервера через игровой сервер до выделенного сервера. Фильтрация идёт на уровнях 3, 4 и 7 на любом TCP- или UDP-порту, то есть и на UDP 7777. Работает всё это в дата-центре maincubes во Франкфурте-на-Майне (Германия), оператор KernelHost GmbH со штаб-квартирой в Вене (Австрия). Какие игры и протоколы имеют собственные профили, показывает статья Защита игровых серверов от DDoS в реальном времени.
Для проектов под постоянным обстрелом: Advanced DDoS Protection
Некоторые проекты попадают под удар не время от времени, а целенаправленно и неделями. Для такого случая есть Advanced DDoS Protection от 50,00 € в месяц, PrePaid и без минимального срока. Она дополняет постоянную защиту тремя вещами:
- Выделенный защищённый IP-адрес из франкфуртского ядра сети. Ваш сервер переключается на него внутри сети KernelHost, на своей стороне вы ничего не перестраиваете.
- Самостоятельно управляемые правила защиты по портам и протоколам в личном кабинете. Изменения применяются в реальном времени, без тикета и без ожидания, поэтому подстраивать правила можно прямо посреди атаки.
- Профиль защиты под конкретную игру. Готовые профили более чем для 40 игр, сервисов и протоколов, среди них SA-MP и open.mp, а также собственные TCP- и UDP-приложения. Пользовательская панель, голосовой сервер и VPN тоже помещаются за один и тот же защищённый адрес.
Сравнение двух уровней
| Характеристика | Включённая постоянная защита | Advanced DDoS Protection |
|---|---|---|
| Цена | без доплаты в каждом серверном тарифе | от 50,00 € в месяц, PrePaid |
| Подключение | активна с момента выдачи сервера, настраивать нечего | заказать, получить защищённый IP, сервер переключается |
| Ёмкость фильтрации | 17 Тбит/с глобального scrubbing плюс 3,2 Тбит/с фильтрации Arbor в реальном времени во Франкфурте-на-Майне | та же инфраструктура, дополненная собственными правилами |
| Адрес | IP-адрес сервера из тарифа | дополнительный выделенный защищённый IP |
| Управление правилами | преднастроено и автоматически | самостоятельно в личном кабинете по портам и протоколам, изменения применяются в реальном времени |
| Профили защиты | автоматическое распознавание схем атак | профиль выбирается под игру, более 40 игр и протоколов |
| Null-routing | нет | нет |
| Кому подходит | обычному случаю, в том числе при эпизодических атаках | проектам под постоянным целенаправленным обстрелом |
| Срок | привязан к серверному тарифу | PrePaid, без минимального срока и без срока расторжения |
Частые ошибки и что с ними делать
«Сервер пропал, значит это атака». Сначала проверьте, работает ли ещё процесс. Ошибка времени выполнения в гейммоде выглядит снаружи точно так же. С crashdetect причина попадает в лог, без него вы гадаете.
«Мы закрыли query-порт». Отдельного query-порта не существует. Кто закрывает UDP 7777, закрывает саму игру. Речь может идти либо о query 0 (сервер пропадает из списка), либо об ограничении частоты на том же порту.
«Мы сменили IP и снова онлайн». Если утечку не закрыть, новый адрес станет публичным уже через несколько часов. Старые записи DNS, панель на той же машине и статус в Discord-боте выдают его надёжно.
«Мы поставили лимит 20 пакетов в секунду на адрес». Это слишком жёстко. Уже один игрок выходит за такой предел, а несколько игроков за одним NAT-адресом делят между собой одну и ту же квоту. Так вы выбрасываете собственных игроков.
«Мы закрыли доступ сами себе через файрвол». Перезагрузка не поможет, потому что UFW восстанавливает свои правила при старте системы. В KernelHost вы открываете VNC-консоль в личном кабинете и выполняете там ufw disable. IPMI или iDRAC на KVM root-серверах и выделенных серверах нет, путь идёт через VNC-консоль.
«Пароль от RCON лежит в командном чате». RCON идёт по UDP в открытом виде и читается на всём пути. Если он вам не нужен, отключите его, а если нужен, то действует правило: длинный случайный пароль и доступ только через VPN.
«Мы просто переждём атаку». Атаки, которые дают результат, повторяют. Фиксируйте время начала, длительность, пиковые значения и затронутые порты. Ровно эти данные нужны и в тикете поддержки, чтобы фильтрацию можно было донастроить прицельно.
Если атака идёт прямо сейчас
Если ваш проект уже размещён в KernelHost, фильтрация активна постоянно, включать ничего не нужно. Если вы всё же замечаете аномалии, откройте тикет в поддержку с указанием периода, порта и наблюдаемого поведения, чтобы правила для вашего адреса подстроили. Во время идущей атаки с нами можно связаться дополнительно через экстренный чат в WhatsApp по номеру +43 650 8209883.
Частые вопросы
На каком порту работает сервер SA-MP или open.mp?
Можно ли закрыть доступ к query, не закрывая сам сервер?
Сервер пропал: это атака или падение?
Какие настройки сразу тормозят флуд подключениями?
Достаточно ли файрвола на сервере против DDoS-атак?
Помогает ли смена IP-адреса?
Защита от DDoS в KernelHost входит в цену?
Когда есть смысл в Advanced DDoS Protection?
2026 KernelHost GmbH. Все права защищены. Эта инструкция охраняется авторским правом. Публикация на других сайтах, в том числе частично или в изменённом виде, без нашего письменного согласия не разрешается. Цитирование с указанием источника и активной ссылкой мы приветствуем.

