Как исправить ошибку 429 в SearXNG
Ошибка 429 в SearXNG возникает из-за локального лимитера или блокировки IP на стороне поисковых систем. Изучите лог, чтобы определить источник проблемы и применить верное решение.
Почему SearXNG возвращает ошибки 429
Самостоятельно развернутый экземпляр SearXNG возвращает ошибки 429 по двум не связанным между собой причинам, и ограничение скорости, которое вам нужно исправить, обычно не то, о котором вы думаете. Первая причина — локальная: собственный ограничитель SearXNG решил, что запрос поступил от бота, и ответил Too Many Requests статусом 429. Вторая причина — вышестоящая: поисковая система отклонила IP-адрес вашего сервера, что доходит до ваших пользователей в виде страницы результатов с отсутствующими данными, а не в виде ошибки 429.
Для этих двух случаев нет общего решения. Ограничитель — ваш, поэтому вы можете его изменить. Блокировка вышестоящей системой происходит на стороне Google, поэтому никакие изменения в вашем settings.yml её не снимут. Лог покажет, с какой именно проблемой вы столкнулись, примерно за минуту, поэтому начните с него.
Это руководство предполагает использование установки в контейнере, описанной в самостоятельно развернутом экземпляре SearXNG на вашем VPS. Все названия настроек ниже взяты из актуальной документации и исходного кода проекта, проверенных в августе 2026 года.
Изучите лог перед изменением настроек
Воспроизведите проблему, оставив окно с логами открытым.
cd ./searxng/
docker compose logs -f searxng-coreСообщения ограничителя поступают от логгера с именем searx.limiter и содержат IP-адрес. Срабатывание блокирующего списка записывается как BLOCK 203.0.113.10: matched BLOCKLIST, а срабатывание разрешающего списка — как PASS 203.0.113.10: matched PASSLIST. Если ограничитель не может получить доступ к хранилищу счетчиков, в логе появляется запись The limiter requires Valkey, please consult the documentation, что означает, что подсчет запросов полностью прекращен.
Каждая отдельная проверка бота записывается на уровне debug, поэтому по умолчанию вы её не увидите. Включите debug для проведения теста в settings.yml:
general:
debug: trueПосле этого в лог будут добавляться строки вида NOT OK (http_accept_language) рядом с клиентской сетью, указывающие на не пройденную проверку. Не забудьте выключить этот режим после завершения, так как разработчики не рекомендуют использовать рабочие экземпляры с включенным уровнем debug.
Ошибки движка выглядят иначе. В них вместо IP-адреса указывается имя движка, и наиболее распространенной ошибкой является таймаут:
HTTP requests timeout (search duration : 3.1 s, timeout: 3.0 s)Для этого также предусмотрена отдельная страница. Если параметр enable_metrics оставлен со значением по умолчанию true, ваш экземпляр записывает ошибки движка в /stats/errors, а /preferences отображает список движков, которые отвечают в данный момент. Если /stats/errors переполнен, а в логе отсутствуют строки searx.limiter, значит, проблема не в ограничителе.
Зафиксируйте версию перед началом отладки
Конфигурация контейнера от разработчика состоит из двух файлов.
mkdir -p ./searxng/core-config/
cd ./searxng/
curl -fsSL \
-O https://raw.githubusercontent.com/searxng/searxng/master/container/docker-compose.yml \
-O https://raw.githubusercontent.com/searxng/searxng/master/container/.env.example
cp -i .env.example .envФайл compose загружает docker.io/searxng/searxng:${SEARXNG_VERSION:-latest}. Неустановленная переменная означает latest, а latest приводит к тому, что экземпляр меняется без вашего ведома при следующем docker compose pull, поэтому настройки, работавшие на прошлой неделе, могут перестать соответствовать коду, который их считывает. Теги SearXNG содержат дату и хеш коммита. Пример тега в официальном .env.example по состоянию на август 2026 года — 2026.3.25-541c6c3cb, поэтому укажите конкретный тег в .env:
SEARXNG_VERSION=2026.3.25-541c6c3cbПроверьте опубликованные теги и зафиксируйте тот релиз, который вы фактически протестировали, а затем проводите отладку на стабильной версии. Тот же файл .env содержит ваш секретный ключ, поэтому ознакомьтесь с принципами работы файлов окружения и секретов в Docker Compose перед тем, как отправлять этот каталог в репозиторий.
Для работы ограничителя требуется Valkey
Ограничитель считает запросы для каждого клиента, поэтому эти счётчики нужно совместно использовать между рабочими процессами. Для хранения данных используется Valkey — поддерживаемый форк Redis. В старых руководствах по SearXNG этот параметр обозначен как redis:. Текущие версии считывают valkey:, поэтому имя ключа нужно копировать из актуальной документации, а не из старой публикации. Некоторые такие страницы относятся к ещё более раннему периоду и описывают Searx, а не SearXNG. Это другой код с другим ограничителем. Поэтому перед копированием блока конфигурации определите, для какого из двух проектов написана страница.
use_default_settings: true
server:
secret_key: "change-this-value"
limiter: true
public_instance: false
valkey:
url: valkey://searxng-valkey:6379/0В исходном файле compose уже запущен сервис searxng-valkey на базе образа docker.io/valkey/valkey:9-alpine, поэтому данное имя хоста корректно разрешается внутри сети compose. Это же значение можно задать через переменную окружения SEARXNG_VALKEY_URL; также поддерживается URL Unix-сокета (unix:///path/to/socket.sock?db=0), если SearXNG и Valkey работают на одном хосте.
Поведение системы при отсутствии хранилища зависит от другого ключа. При public_instance: false ограничитель записывает ошибку Valkey в лог и отключается, поэтому экземпляр продолжает работать без ограничения частоты запросов. При public_instance: true процесс вызывает sys.exit(1), так как открытый экземпляр с неработающей защитой от ботов в течение суток начнет получать CAPTCHA (полностью автоматизированный публичный тест Тьюринга для различения компьютеров и людей) от всех поисковых движков. Если контейнер уходит в цикл перезагрузки сразу после настройки public_instance: true, причина именно в этом, а последняя строка перед каждым завершением процесса указывает на Valkey.
Что именно учитывает ограничитель
The data behind this chart
[
{
"label": "Burst, normal client",
"max_requests": 15,
"window": "20 seconds"
},
{
"label": "Burst, flagged client",
"max_requests": 2,
"window": "20 seconds"
},
{
"label": "Sustained, normal client",
"max_requests": 150,
"window": "10 minutes"
},
{
"label": "Sustained, flagged client",
"max_requests": 10,
"window": "10 minutes"
},
{
"label": "Any non-HTML format",
"max_requests": 4,
"window": "1 hour"
},
{
"label": "Flagged requests before block",
"max_requests": 3,
"window": "30 days"
}
]Обычный клиент может выполнить 15 запросов в течение 20-секундного окна всплеска и 150 в течение 10-минутного окна. Как только запрос помечается как подозрительный, лимит для этого клиента снижается до 2 на окно всплеска. Последняя строка — самая строгая: после 3 помеченных запросов в течение 30-дневного окна этот адрес перенаправляется на стартовую страницу вместо поиска, а в лог записывается BLOCK: too many request from ... in SUSPICIOUS_IP_WINDOW (redirect to /).
Эти числа являются константами в searx/botdetection/ip_limit.py. Они не являются настройками, и limiter.toml не позволяет их изменять, поэтому для их корректировки необходимо редактировать исходный код. То, чем /etc/searxng/limiter.toml действительно управляет, — это префиксы адресов, используемые для группировки клиентов, список доверенных прокси, опциональная проверка токена ссылки, а также списки разрешённых и заблокированных адресов.
Запрос помечается как подозрительный на основе проверок заголовков, и каждая проверка имеет имя, которое вы увидите в отладочном логе:
http_accept: заголовокAcceptне содержитtext/html.http_accept_encoding: заголовокAccept-Encodingне содержит ниgzip, ниdeflate.http_accept_language: отсутствует заголовокAccept-Language.http_connection: заголовокConnectionустановлен вclose.http_user_agent:User-Agentотсутствует или соответствует известному шаблону бота.http_sec_fetch: заголовокSec-Fetch-ModeилиSec-Fetch-Destне соответствует тому, что отправляет браузер.
Браузер отправляет все эти заголовки. Обычный вызов curl не отправляет почти ни одного из них, поэтому написанный вручную тестовый запрос помечается при первой же попытке, в то время как тот же поиск работает во вкладке браузера. Именно поэтому ситуация «в браузере работает, а мой скрипт получает 429» является ожидаемым результатом, а не загадкой.
За reverse proxy ограничитель блокирует всех пользователей одновременно
Это самая частая причина сбоя в работе экземпляра. SearXNG получает адрес клиента из первого недоверенного IP в X-Forwarded-For, затем переходит к X-Real-IP, а в конечном итоге использует адрес, с которого было установлено соединение. Решение о том, доверять ли этим заголовкам, определяется параметром trusted_proxies в файле limiter.toml.
Если адрес вашего прокси отсутствует в этом списке, заголовки игнорируются, и все посетители отображаются с адресом прокси. В результате они используют общий счетчик, и весь сайт блокируется, как только общее количество запросов превышает 150 за 10 минут. Один пользователь, несколько раз обновивший страницу с результатами, приведет к блокировке всех остальных.
Чрезмерное доверие еще опаснее. Если в списке указан публичный диапазон, любой посетитель может отправить собственный заголовок X-Forwarded-For и выбирать новую «личность» для каждого запроса, что фактически отключает ограничитель для всех, кто знает об этой возможности. Указывайте только тот адрес, с которого подключается ваш прокси. В Docker это обычно адрес мостовой сети внутри 172.16.0.0/12, и эта строка поставляется закомментированной.
[botdetection]
ipv4_prefix = 32
ipv6_prefix = 48
trusted_proxies = [
'127.0.0.0/8',
'::1',
'172.16.0.0/12',
]Прокси также должен передавать заголовки. Nginx не добавляет их автоматически:
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header Connection $http_connection;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}Caddy и Traefik устанавливают заголовки пересылки автоматически, поэтому с ними вам нужно выполнить только часть настройки, связанную с trusted_proxies. Компромиссы при выборе решения описаны в выборе reverse proxy для self-hosted сервиса. Чтобы проверить корректность настройки, включите debug, выполните один поиск с телефона через мобильный интернет и убедитесь, что в строке лога указан адрес вашего телефона, а не адрес прокси.
Ваш агент получает четыре API-запроса в час
Вывод в формате JSON по умолчанию отключен, поэтому для агента его необходимо добавить:
search:
formats:
- html
- jsonТеперь снова изучите строку таблицы. Любой запрос, запрашивающий формат, отличный от HTML, учитывается в собственном окне: 4 запросов на 1 hour для каждого адреса. Исследовательский агент расходует этот лимит за одну задачу, и каждый последующий вызов возвращает 429. Увеличение лимита не является решением, так как это число жестко задано в исходном коде.
Правильный способ исправления — сообщить ограничителю, что этот клиент не является сторонним. Добавьте его адрес в список разрешенных в limiter.toml:
[botdetection.ip_lists]
block_ip = []
pass_ip = [
'10.8.0.0/24',
]
pass_searxng_org = truepass_ip имеет приоритет над всеми остальными методами, поэтому клиент из списка разрешенных также пропускает проверки заголовков, и обычный вызов curl будет работать. Ограничивайте диапазон настолько, насколько это возможно, и отдавайте предпочтение подсети VPN или сети контейнеров, а не чему-либо маршрутизируемому. Другой правильный способ — полностью исключить агента из публичного пути: направьте его на адрес контейнера во внутренней сети, где прокси-сервер и его ограничитель не видят трафик. Настройка этого процесса описана в предоставлении AI-агенту навыка поиска SearXNG.
Вариант, которого следует избегать — направление агента на публичный экземпляр, запущенный кем-то другим. Это самый быстрый способ добиться блокировки IP-адреса волонтера вышестоящими поисковыми системами, и именно поэтому формат JSON по умолчанию отключен.
Когда поисковые системы блокируют запросы
The data behind this chart
[
{
"label": "SearxEngineTooManyRequests",
"suspended_seconds": 3600,
"roughly": "1 hour"
},
{
"label": "SearxEngineAccessDenied",
"suspended_seconds": 86400,
"roughly": "1 day"
},
{
"label": "SearxEngineCaptcha",
"suspended_seconds": 86400,
"roughly": "1 day"
},
{
"label": "recaptcha_SearxEngineCaptcha",
"suspended_seconds": 604800,
"roughly": "7 days"
},
{
"label": "cf_SearxEngineCaptcha",
"suspended_seconds": 1296000,
"roughly": "15 days"
}
]Если движок отвечает собственным кодом 429 или страницей CAPTCHA, SearXNG вызывает именованное исключение и на некоторое время прекращает отправлять запросы этому движку. Ответ «слишком много запросов» приостанавливает его на 3600 секунд. Обычная CAPTCHA или ответ об отказе в доступе приостанавливает его на 1 day. CAPTCHA, предоставленная через Cloudflare, приостанавливает его на 15 days, то есть на самый длительный срок по умолчанию в этом списке, поскольку такой ответ означает, что блокировка действует на периферии и повторные попытки не помогут. Какая из трёх строк CAPTCHA сработала, определяет, что стоит попробовать дальше, а для ошибок CAPTCHA есть отдельный набор исправлений, если известно, какое исключение записал ваш экземпляр.
Обычные сбои используют другие настройки. Тайм-аут или ошибка парсинга приостанавливают движок на короткий срок, определяемый параметром search.ban_time_on_fail (по умолчанию 5 секунд), который ограничен значением search.max_ban_time_on_fail в 120 секунд. Таким образом, медленный движок восстанавливается самостоятельно в течение пары минут, тогда как заблокированный движок отключается на часы. Эта разница объясняет симптом, который пользователи называют случайным: результаты поиска отображаются корректно, а затем результаты одного из движков пропадают до конца дня.
Прежде чем искать виноватых, стоит устранить тайм-ауты. Значение request_timeout по умолчанию составляет 2.0 секунды, что является довольно жестким ограничением для небольшого VPS, расположенного далеко от ближайшего пограничного сервера поисковой системы.
outgoing:
request_timeout: 3.0
max_request_timeout: 10.0
engines:
- name: bing
timeout: 5.0request_timeout является значением по умолчанию для каждого движка, max_request_timeout — это верхний предел, а отдельный движок может иметь собственный параметр timeout. Увеличение этих значений повышает задержку страницы ради уменьшения количества сбоев, поэтому изменяйте их с шагом в полсекунды и следите за /stats/errors, вместо того чтобы сразу устанавливать значение 10.
Если движок действительно блокирует ваш IP-адрес, удалите его. Каждый поиск ожидает ответа от самого медленного движка, поэтому сохранение постоянно приостановленного движка увеличивает задержку и не дает никаких результатов.
use_default_settings:
engines:
remove:
- googleПримените изменения с помощью docker compose restart searxng-core, затем выполните несколько поисковых запросов и перезагрузите /stats/errors. Пустая страница после пяти минут реального использования означает, что изменения сработали.
IP-адрес дата-центра будет распознан как бот
Ваш VPS-адрес принадлежит диапазону хостинг-провайдера, и крупные поисковые системы классифицируют такие диапазоны как автоматизированные. Некоторые из них выдают CAPTCHA на каждый запрос с такого адреса, независимо от корректности заголовков или низкой частоты запросов. Никакие настройки в settings.yml не изменят эту оценку. Тот факт, что поисковые системы видят ваш сервер вместо пользователя, вводящего запрос, — это и есть основной компромисс в вопросе приватности, на который вы идете при самостоятельном хостинге. Стоит ознакомиться с тем, насколько SearXNG на самом деле скрывает данные, прежде чем полагать, что он обеспечивает большую анонимность.
Что вы можете изменить, так это выбор поисковых систем и статус публичности вашего экземпляра. Частный экземпляр, используемый одним домохозяйством, редко вызывает срабатывание защиты. Публичный экземпляр на IP-адресе хостинга будет постоянно получать блокировки от наиболее строгих поисковых систем, и это нормальное поведение программного обеспечения, а не ошибка в вашей конфигурации. SearXNG может направлять запросы к поисковым системам через прокси с помощью outgoing.proxies или outgoing.using_tor_proxy, что перенаправляет трафик на другой адрес. Выходные узлы и дешевые прокси-пулы имеют еще более низкий рейтинг доверия, чем диапазоны хостинг-провайдеров, поэтому будьте готовы к тому, что это ухудшит качество результатов поиска.
Мониторинг экземпляра для оперативного реагирования
SearXNG отвечает на своем порту, даже если все движки приостановлены. Поэтому проверка доступности, которая отслеживает только код ответа, будет показывать статус «в сети», хотя экземпляр не выдает результатов. Проверяйте содержимое: выполните реальный поисковый запрос и ищите ожидаемое слово в теле ответа. Мониторинг ключевых слов в Uptime Kuma выполняет эту задачу без дополнительных инструментов. Также отслеживайте /stats/errors после каждого обновления версии, так как движки меняют HTML-разметку, что приводит к поломке парсеров вне зависимости от ограничений частоты запросов.
FAQ
Почему SearXNG возвращает 429 каждому посетителю после того, как я поместил его за reverse proxy?
Потому что ограничитель считает прокси-сервер клиентом. SearXNG считывает X-Forwarded-For только в том случае, если адрес подключения указан в trusted_proxies в файле /etc/searxng/limiter.toml. Если адрес не указан, все посетители используют один счетчик, и они все вместе превышают лимит в 150 запросов за 10 минут. Добавьте адрес, с которого подключается ваш прокси (в Docker это обычно диапазон моста 172.16.0.0/12), и убедитесь, что прокси отправляет заголовки X-Real-IP и X-Forwarded-For. Никогда не указывайте диапазон, который вы не контролируете, так как доверенная сеть позволяет любому посетителю установить этот заголовок и выбирать новую личность для каждого запроса.
Сколько API-запросов в час разрешает ограничитель SearXNG?
Четыре запроса на IP-адрес в час. Любой запрос, запрашивающий формат, отличный от HTML, учитывается в отдельном часовом окне, и этот лимит задан в searx/botdetection/ip_limit.py, а не в limiter.toml, поэтому его нельзя увеличить через конфигурацию. Агент или скрипт выполняет это за одну задачу. Добавьте адрес клиента в pass_ip в limiter.toml или обращайтесь к экземпляру через внутреннюю сеть, где ограничитель не видит запрос.
Почему результаты поиска приходят пустыми без ошибки 429?
Поисковые движки блокируют ваш сервер, а не ваших пользователей. Откройте /stats/errors на вашем экземпляре: там указан каждый движок, который выдал ошибку, и причина. Запись о CAPTCHA или отказе в доступе означает, что движок заблокировал IP-адрес вашего сервера. SearXNG приостанавливает работу движка на час после ответа о слишком большом количестве запросов и на день после появления CAPTCHA. Никакие локальные настройки не снимут блокировку на стороне вышестоящего сервиса, поэтому удалите движки, которые блокируют ваш адрес, и оставьте те, которые отвечают.
Стоит ли включать ограничитель на приватном экземпляре?
Если к экземпляру никто, кроме вас, не обращается, оставьте limiter: false. Это добавляет зависимость от Valkey и блокирует ваши собственные скрипты, при этом защищая от трафика, которого у вас нет. Включайте его сразу, как только экземпляр получает публичный адрес, вместе с public_instance: true. Эта пара работает согласованно: при public_instance: true и неработающем Valkey процесс завершается со статусом 1, вместо того чтобы работать без защиты.