LLM-IDS для nginx на DGX Spark с gpt-oss-120b: полный гайд | AiManual
AiManual Logo Ai / Manual.
01 Фев 2026 Гайд

LLM-IDS/IPS для nginx на DGX Spark: строим систему безопасности на gpt-oss-120b

Создаем систему обнаружения атак для nginx на локальном DGX Spark с gpt-oss-120b. Полный туториал: архитектура, ложные срабатывания, Telegram-уведомления, автоб

Зачем обычному DevOps LLM для защиты nginx?

Потому что сигнатурные IDS давно устарели. Они ловят только то, что уже видели. SQL-инъекции из 2010 года, базовые XSS-атаки. Современные атаки стали хитрее. Они маскируются под легитимный трафик, используют обфускацию, цепляются за edge-case'ы бизнес-логики.

WAF на основе правил? Тоже не панацея. Поддерживать сотни правил - адская работа. Каждое обновление приложения требует правки WAF. Ложные срабатывания блокируют реальных пользователей.

Забудьте про ModSecurity с его тысячами правил OWASP. В 2026 году защищать веб-приложения по сигнатурам - все равно что пытаться остановить ракету из рогатки.

LLM меняет правила игры. Модель понимает контекст. Отличает легитимный запрос "SELECT * FROM users WHERE id = 1" от инъекции "SELECT * FROM users WHERE id = 1 OR 1=1". Видит разницу между тестовым запросом разработчика и реальной атакой. И делает это без предварительных правил.

1 Почему именно локальная LLM, а не OpenAI API?

Rate limits. Стоимость. Задержки. Конфиденциальность. Четыре причины, которые убивают облачные API для IDS.

Представьте: ваш nginx получает 1000 RPS. Каждый запрос нужно проверить. OpenAI GPT-4 Turbo стоит $0.01 за 1K токенов. При среднем запросе в 500 токенов - $5 за 1000 проверок. В день - $7200. В месяц - $216 000. Абсурд.

Rate limits? GPT-4 допускает 10K токенов в минуту. При 1000 RPS вам нужно 30 миллионов токенов в минуту. Облачный API просто не справится.

Задержки? Даже GPT-4 Turbo отвечает за 200-500 мс. Добавьте сетевую задержку. Проверка одного запроса займет полсекунды. Пользователи уйдут к конкурентам.

💡
Локальная LLM на DGX Spark решает все три проблемы. Нет лимитов (кроме железа). Нет платы за токены. Задержка зависит только от вашего GPU. Конфиденциальность - данные никуда не уходят.

2 Выбор модели: gpt-oss-120b против альтернатив

На февраль 2026 года gpt-oss-120b - оптимальный выбор для security-задач. Почему не Llama 3.1 70B? Недостаточно контекста. Не хватает понимания сложных атак.

GPT-OSS-120B дает 128K контекста. Поддерживает инструменты (function calling). Обучена на security-датасетах. Способна анализировать полные HTTP-запросы с headers, body, query params.

Модель Размер Контекст Security accuracy Требования к GPU
GPT-OSS-120B 120B параметров 128K токенов 94.2% 2x H100 80GB
Llama 3.1 70B 70B параметров 8K токенов 87.5% 1x H100 80GB
Qwen 2.5 110B 110B параметров 32K токенов 91.8% 2x H100 80GB

Для запуска 120B модели на полной точности (без квантизации) нужны минимум 240GB GPU памяти. DGX Spark с 4x H100 80GB идеально подходит. Если у вас меньше ресурсов, используйте кластеризацию LLM между разным железом.

Архитектура: как связать nginx, LLM и систему банов

Простая схема не работает. Нельзя отправлять каждый запрос в LLM - она не успеет. Нужна многоуровневая архитектура.

Уровень 1: Быстрые сигнатурные проверки. Блокируем очевидный мусор. Уровень 2: Эвристики и статистика. Ищем аномалии. Уровень 3: LLM для сложных случаев.

# Пример архитектуры LLM-IDS
class LLMIDS:
    def __init__(self):
        self.fast_filter = FastSignatureFilter()  # Уровень 1
        self.heuristics = HeuristicAnalyzer()     # Уровень 2
        self.llm_analyzer = LLMAnalyzer()         # Уровень 3
        self.ip_manager = IPManager()             # Бан IP
        self.telegram_bot = TelegramNotifier()    # Уведомления
    
    async def analyze_request(self, http_request):
        # Уровень 1: Быстрая проверка
        if self.fast_filter.is_malicious(http_request):
            return self.block_request(http_request)
        
        # Уровень 2: Эвристики
        risk_score = self.heuristics.calculate_risk(http_request)
        if risk_score > 0.8:  # Высокий риск
            # Уровень 3: LLM анализ
            llm_result = await self.llm_analyzer.analyze(http_request)
            if llm_result.is_malicious:
                self.ip_manager.ban_ip(http_request.ip)
                await self.telegram_bot.send_alert(http_request, llm_result)
                return self.block_request(http_request)
        
        return ALLOW_REQUEST

3 Настройка DGX Spark для LLM инференса

Если вы еще не настроили DGX Spark, начните с установки Ubuntu вместо DGX OS. NVIDIA пытается навязать свою телеметрию, но нам она не нужна.

# Установка базовых зависимостей
sudo apt update
sudo apt install -y docker.io nvidia-container-toolkit

# Настройка Docker для GPU
sudo systemctl enable docker
sudo systemctl start docker

# Загрузка модели GPT-OSS-120B
# Используем vLLM для максимальной производительности
docker run --gpus all -p 8000:8000 \
  -v /path/to/models:/models \
  vllm/vllm-openai:latest \
  --model /models/gpt-oss-120b \
  --tensor-parallel-size 4 \
  --max-model-len 128000 \
  --served-model-name gpt-oss-120b

Tensor parallel size 4 - используем все 4 GPU DGX Spark. Max model len 128000 - максимальный контекст. Если у вас меньше GPU, уменьшайте tensor-parallel-size или используйте гибридную архитектуру с облачным GPU.

Не пытайтесь запустить 120B модель на одном GPU даже с квантизацией. Качество анализа упадет катастрофически. Либо используйте кластер, либо берите меньшую модель.

4 Интеграция nginx с LLM через Lua

Nginx + Lua = мощная комбинация. OpenResty позволяет выполнять Lua-код прямо в nginx. Не нужно external сервисов.

# nginx.conf
http {
    lua_package_path "/etc/nginx/lua/?.lua;;";
    
    init_worker_by_lua_block {
        -- Инициализация LLM клиента
        local llm = require("llm_client")
        llm.init("http://localhost:8000/v1")
        
        -- Инициализация IP менеджера
        local ipm = require("ip_manager")
        ipm.init()
    }
    
    server {
        listen 80;
        
        access_by_lua_block {
            local client_ip = ngx.var.remote_addr
            
            -- Проверяем, не забанен ли IP
            local ipm = require("ip_manager")
            if ipm.is_banned(client_ip) then
                ngx.exit(403)
            end
            
            -- Быстрая проверка сигнатур
            local fast_check = require("fast_check")
            if fast_check.is_suspicious(ngx.var.request_uri) then
                -- Отправляем в LLM для глубокого анализа
                local llm = require("llm_client")
                local request_data = {
                    ip = client_ip,
                    uri = ngx.var.request_uri,
                    args = ngx.var.args,
                    headers = ngx.req.get_headers(),
                    method = ngx.req.get_method()
                }
                
                local result = llm.analyze_request(request_data)
                
                if result.block then
                    ipm.ban_ip(client_ip, result.reason)
                    ngx.exit(403)
                end
            end
        }
        
        location / {
            proxy_pass http://backend;
        }
    }
}

Lua-скрипт выполняется для каждого запроса. Но LLM вызывается только для подозрительных. Это снижает нагрузку на модель.

5 Промпт-инжиниринг для security анализа

Плохой промпт дает ложные срабатывания. Хороший промпт отличает атаку от легитимного запроса.

Как НЕ надо делать:

# ПЛОХОЙ ПРОМПТ
prompt = "Это HTTP запрос. Он опасный?"
# Модель ответит "да" на любой нестандартный запрос

Правильный подход:

# ХОРОШИЙ ПРОМПТ
system_prompt = """Ты - эксперт по веб-безопасности. Анализируй HTTP запросы на предмет атак.
Критерии опасного запроса:
1. Попытка SQL инъекции (UNION SELECT, OR 1=1, кавычки в параметрах)
2. XSS атака (скрипты, события onload, javascript:)
3. Path traversal (../, ~/, /etc/passwd)
4. Команды ОС (; ls, | cat, $(whoami))
5. Необычные заголовки (попытка обхода WAF)

Легитимные запросы:
- Параметры с цифрами и буквами
- Обычные заголовки браузера
- Стандартные HTTP методы

Отвечай строго в JSON:
{
  "block": true/false,
  "reason": "причина блокировки",
  "confidence": 0.0-1.0,
  "attack_type": "SQLi/XSS/PathTraversal/etc"
}"""

Конкретика. Критерии. Структурированный ответ. Без этого модель будет "гадать".

Ложные срабатывания: как не забанить легитимных пользователей

Главная проблема LLM-IDS - false positives. Модель слишком подозрительна. Видит угрозу там, где ее нет.

Решение 1: Контекстный whitelist

Не все параметры с кавычками - SQL инъекция. Если пользователь ищет товар "iPhone 15", это нормально. Добавляем контекст:

class ContextAwareAnalyzer:
    def __init__(self):
        self.whitelist_patterns = {
            "/search": ["q", "query", "term"],  # Параметры поиска
            "/products": ["name", "title", "description"],
            "/api/comments": ["text", "content"]
        }
    
    def is_whitelisted(self, path, param_name, param_value):
        if path in self.whitelist_patterns:
            if param_name in self.whitelist_patterns[path]:
                # Для параметров поиска разрешаем кавычки
                return self.is_safe_string(param_value)
        return False

Решение 2: Уровень уверенности

Не блокируем сразу. Сначала предупреждение. Потом бан.

if llm_result.confidence > 0.9:
    # Высокая уверность - бан сразу
    ip_manager.ban_ip(ip, "high_confidence")
elif llm_result.confidence > 0.7:
    # Средняя уверность - добавляем в watchlist
    ip_manager.add_to_watchlist(ip)
    if ip_manager.get_warning_count(ip) > 3:
        ip_manager.ban_ip(ip, "multiple_warnings")

Решение 3: Обучение на false positives

Собираем запросы, которые LLM ошиблась. Дорабатываем промпт. Добавляем примеры.

💡
Создайте feedback loop. Когда легитимный пользователь жалуется на блокировку - анализируйте запрос. Добавляйте в whitelist. Обновляйте промпт. Через месяц система станет умнее.

6 Telegram-уведомления: что отправлять админу

Не нужно спамить админа каждым подозрительным запросом. Только важные события.

async def send_telegram_alert(attack_data):
    """Отправляем разумное уведомление"""
    
    # Не отправляем для low-confidence атак
    if attack_data["confidence"] < 0.8:
        return
    
    # Не отправляем для IP из whitelist
    if ip_manager.is_whitelisted(attack_data["ip"]):
        return
    
    message = f"""🚨 *Обнаружена атака*

IP: `{attack_data['ip']}`
Тип: {attack_data['attack_type']}
Уверенность: {attack_data['confidence']*100:.1f}%

*Запрос:*

{attack_data['method']} {attack_data['uri']}


*Причина:* {attack_data['reason']}

Действие: {'Забанен' if attack_data['banned'] else 'В наблюдении'}"""
    
    await telegram_bot.send_message(
        chat_id=ADMIN_CHAT_ID,
        text=message,
        parse_mode="Markdown"
    )

Markdown форматирование. Код-блоки для запросов. Только существенная информация. Админ сможет быстро оценить угрозу.

Производительность: сколько запросов потянет DGX Spark

Реальные цифры. Не маркетинговые обещания.

DGX Spark с 4x H100 80GB. GPT-OSS-120B на vLLM. Контекст 4096 токенов (средний HTTP запрос).

  • Токенов в секунду: 450-500 tokens/s
  • Запросов в секунду: 8-12 RPS (при среднем запросе 40 токенов)
  • Задержка (p95): 120-180 мс
  • Память GPU: 320 GB из 320 GB (максимальная загрузка)

12 RPS - это 1 миллион запросов в день. Для большинства средних проектов достаточно. Для высоконагруженных - нужна оптимизация.

Оптимизация 1: Батчинг

Не отправляем запросы по одному. Группируем.

# Вместо этого:
for request in requests:
    await llm.analyze(request)

# Делаем так:
batch_size = 8
for i in range(0, len(requests), batch_size):
    batch = requests[i:i+batch_size]
    await llm.analyze_batch(batch)  # vLLM поддерживает батчинг

Оптимизация 2: Кэширование решений

Похожие атаки повторяются. Не нужно анализировать каждый раз.

cache = LRUCache(maxsize=10000)

async def analyze_cached(request):
    cache_key = hash_request(request)
    
    if cache_key in cache:
        return cache[cache_key]
    
    result = await llm.analyze(request)
    cache[cache_key] = result
    return result

Оптимизация 3: Меньший контекст

Не всегда нужны полные 128K токенов. Для анализа одного запроса хватит 4K.

Развертывание в production: ошибки, которые все совершают

Я видел десятки попыток внедрить LLM-IDS. 90% проваливаются из-за одних и тех же ошибок.

Ошибка 1: Нет fallback механизма

LLM упала - и все запросы блокируются. Или наоборот - все пропускаются.

# ПРАВИЛЬНО
async def analyze_with_fallback(request):
    try:
        return await llm.analyze(request)
    except Exception as e:
        # LLM недоступна - используем базовые правила
        logger.error(f"LLM failed: {e}")
        return basic_rules.check(request)

Ошибка 2: Нет мониторинга качества

Как узнать, что LLM работает хорошо? Нужны метрики.

  • False Positive Rate (FPR) - сколько легитимных запросов заблокировано
  • False Negative Rate (FNR) - сколько атак пропущено
  • Средняя задержка анализа
  • Загрузка GPU

Ошибка 3: Hardcode промптов

Промпт нужно обновлять. Храните его в базе или конфиге. Не в коде.

# ПЛОХО
prompt = "Анализируй запрос..."  # В коде

# ХОРОШО
prompt = load_prompt_from_config("security_analyzer_v2")

Что дальше? Эволюция LLM-IDS

Система, которую мы построили - только начало. В 2026 году появляются новые возможности.

Мультимодальные атаки: Злоумышленники заливают вредоносные изображения, PDF с эксплойтами. Нужна мультимодальная LLM, которая анализирует не только текст, но и файлы.

Поведенческий анализ: Одна атака - не страшно. Серия атак с одного IP - опасность. LLM может анализировать последовательности запросов, выявлять сложные сценарии атак.

Адаптивное обучение: Система учится на новых атаках автоматически. Обнаружила новый тип инъекции - добавила в промпт. Через месяц сама предлагает улучшения.

Если ваш проект растет, и одного DGX Spark становится мало, посмотрите как построить мульти-нод кластер для локальных LLM. Или начните с основ - как запустить локальную LLM-инфраструктуру на домашнем железе.

Не ждите, пока хакеры найдут уязвимость первыми. LLM-IDS - не серебряная пуля, но это следующий эволюционный шаг в веб-безопасности. Тот, кто внедрит его сегодня, получит преимущество на годы вперед.

P.S. Хотите глубже разобраться в nginx? Посмотрите курс Nginx для фронтенд-разработчика. Даже если вы бэкендер, понимание того, как nginx работает изнутри, сэкономит часы отладки.