Короткий ответ

Rate limiting — потолок новых сессий и HTTP-запросов, не замена allow-листа. На периметре: nft limit/meter, RouterOS limit/connection-limit, synproxy/cookie где умеете штатно. На reverse proxy в DMZ 10.0.30.10: limit_req/limit_conn nginx. Не ставьте 1 SYN/min на весь офис. Не nft flush, не stop nginx «чтобы пропустило». Brute паролей — ещё и отдельная статья.

WAN 203.0.113.10, LAN 10.0.10.0/24.

Симптомы и как отличить

Conntrack table full в dmesg. Сайт лежит, ping шлюза жив. netstat/ss тысячи SYN_RECV с WAN. nginx access.log: один /24, сотни rps на /wp-login.php или API. IDS орёт на flood.

СлойИнструментКого режет
L3/L4 newnft/RouterOSSYN/UDP flood
HTTPnginx limit_reqтяжёлые URL
IPSSID floodможет ложно резать

Отличие от «канал 100 Мбит забит видео»: saturation vs мелкий пакетный flood. Смотрите pps, не только bps.

Возможные причины

  1. Политика forward/input без limit.
  2. Публикация 443 без proxy limits.
  3. UDP DNS recursion открыт в мир — отдельный инцидент.
  4. Микротик FastTrack, CPU в interrupt.
  5. Боты легитимного вида, нужен limit на URI.
  6. Свой мониторинг без whitelist.

Диагностика

sudo conntrack -S
sudo nft list ruleset | grep -iE 'limit|meter'
ss -ltn | grep ':443'
/ip firewall filter print where limit!=""
/ip firewall connection print count-only
/interface print stats

На web:

sudo grep limit_req /etc/nginx/nginx.conf /etc/nginx/sites-enabled/* 2>/dev/null
sudo tail -n 20 /var/log/nginx/access.log

Не генерируйте свой flood на прод «для проверки» сверх лёгкого теста. Не флудите чужие адреса.

dmesg: nf_conntrack: table full — да, нужен limit + размер таблицы осмысленный, не «просто увеличить в 100 раз без потолка new».

Концепция pf: max-src-conn-rate, synproxy. Смотрите states. Не выдумывайте опции GUI.

Решение

Сценарий A. nftables new с WAN

sudo cp /etc/nftables.conf /root/nftables.conf.bak.rate

Пример идеи (сверьте синтаксис meter в man nft 22.04/24.04):

# iifname "ens18" tcp flags syn / syn,ack ct state new \
#   meter wan_syn { ip saddr limit rate 20/second } counter accept
# превышение — drop с log prefix WAN-SYN-LIMIT limit rate 5/second

Для UDP VPN: лимит выше, иначе отрежете handshake. Белый список mgmt.

sudo nft -c -f /etc/nftables.conf
sudo systemctl reload nftables

Сценарий B. RouterOS 7

/ip firewall filter add chain=input in-interface-list=WAN connection-state=new protocol=tcp \
  tcp-flags=syn action=accept limit=50,10:packet comment="WAN SYN budget"
/ip firewall filter add chain=input in-interface-list=WAN connection-state=new protocol=tcp \
  tcp-flags=syn action=drop log=yes log-prefix="SYN-LIM"

Порядок: allow VPN UDP выше. connection-limit на dstnat 443 по src.

Сверьте limit= в справке вашей сборки. Не reset-configuration.

Сценарий C. nginx в DMZ

# http {
#   limit_req_zone $binary_remote_addr zone=one:10m rate=8r/s;
# }
# location /login { limit_req zone=one burst=12 nodelay; }

limit_req_status 429. Trust real_ip только свой proxy, иначе все за одним NAT офиса словят лимит — см. NAT src.

Проверка nginx -t, reload. Не stop firewall на web.

Сценарий D. DNS

Рекурсор не на WAN. Если есть — уберите, иначе UDP flood + amplification с вашего IP. Это не «чуть limit», это закрыть 53 с мира кроме своих резолверов.

Сценарий E. Свой сканер/мониторинг

Whitelist 10.0.99.20 в meter. Иначе канарейка ломает алерт.

IPS SYN-flood SID: если режет легитим — detect + perimeter limit, не наоборот.

Откат: bak nft, disable одного limit-правила, не всей цепи.

Два бюджета: публикация 443 и UDP VPN, не один SYN на всех

Снимите baseline легитима: conntrack new/sec на ens18 в рабочий час, rps nginx / и /login отдельно. WAN SYN limit ставьте выше пика легитима с запасом, иначе утро понедельника = ложный «DDoS». UDP 51820/4500 — отдельное правило с более высоким бюджетом: иначе rate «спасёт сайт» и убьёт VPN админов.

nginx limit_req на /login и API, не на статику. Если origin за прокси, лимит по $binary_remote_addr без real_ip банит весь офис как один IP — чините XFF trust, не отключайте limit. Свой мониторинг 10.0.99.20 в whitelist meter. Тест: умеренные SYN на закрытый порт своего WAN, prefix SYN-LIM в syslog, 443 жив. Не устраивайте генератор нагрузки на прод ради скриншота.

Как проверить, что проблема устранена

  1. Лёгкий тест своего WAN: несколько SYN на закрытый порт — drop log SYN-LIM, сервис 443 жив.
  2. Не устраивайте ботнет.
  3. Легитимный логин сайта проходит.
  4. conntrack -S не растёт в потолок при умеренном шуме.
  5. Мониторинг не в бане.
  6. nft/RouterOS/nginx конфиги в SCM.

С офиса откройте сайт, с LTE тоже. 429 на /login при агрессивном F5 — ожидаемо.

Если не помогло

  • Flood объёма канала — нужен провайдер/scrubbing, не только nft.
  • Application slow без высокого pps — не flood.
  • limit_req по $binary_remote_addr = IP прокси.
  • IPv6 отдельный meter.
  • FastTrack обходит limit — исключите публикацию из FastTrack.

Профилактика

  • Базовый WAN SYN budget в шаблоне шлюза.
  • limit_req на login/API с первого дня сайта.
  • Алерт conntrack > порога.
  • Закрытый DNS/NTP recursion.
  • Нагрузочный тест своего стенда, не продакшена клиентов.

FAQ

SYN cookies вместо limit?

Дополнительно, если ОС включены штатно (sysctl net.ipv4.tcp_syncookies — проверьте текущее, не выдумывайте значения). Не отменяет nft.

Cloudflare перед сайтом

Тогда limit на origin только с IP Cloudflare/своего proxy. Иначе origin всё ещё торчит — проверьте nmap своего origin IP.

UDP VPN и limit

Слишком жёсткий limit = «VPN не поднимается». Отдельный бюджет на dst-port VPN.

Можно ли 1000/s на всех?

Бессмысленно как защита. Цифра из измерения легитима + запас, не с потолка блога.

RouterOS queue tree вместо filter limit

QoS не drop flood на input CPU. Для SYN flood нужен filter/raw. Queue — про полосу.