MAATRIX / Блог / SearXNG на сервере: частые ошибки и решения

SearXNG на сервере: частые ошибки и решения

SearXNG на сервере: частые ошибки и решения

MAATRIX

SearXNG поднялся, страница отвечает, а через день это уже не тот SearXNG: контейнер уходит в Restarting, ИИ-агент вместо JSON получает 403, а Google с Bing один за другим показывают в логах «Suspended: too many requests». Ни одна из этих ошибок не баг — задокументированное поведение конкретных версий, и лечится за минуты, если знать слой. Разберём по точным текстам ошибок, строкам settings.yml и командам проверки.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Два уровня «SearXNG не работает»: контейнер и логика поиска

За жалобой «SearXNG не работает» почти всегда стоит один из двух слоёв, а симптом на экране у обоих одинаковый — пустая страница или отсутствие результатов. Слой 1 — контейнер и процесс: SearXNG не стартовал или падает через секунды после запуска, до конфига дело не доходит. Слой 2 — логика поиска: процесс жив и отвечает на /, но конкретный запрос, движок или клиент — curl, ИИ-агент, браузер за прокси — получает не то, что должен.

СимптомСлойГде смотреть
docker compose ps показывает Restarting или Exited1 — процессdocker compose logs -f searxng-core
UI открывается, но curl .../search?format=json — 4032 — формат ответаsearch: в settings.yml
Часть движков молчит, источников в выдаче меньше обычного2 — движки-провайдеры/stats/errors
Разные пользователи видят чужие капчи и ограничения2 — лимитер за проксизаголовки в конфиге Nginx

Три команды перед тем, как лезть в конфиг:

docker compose ps
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8080/healthz
curl -s http://127.0.0.1:8080/stats/errors | head -40

/healthz — тот же адрес, который каждые 30 секунд дёргает встроенный в образ Docker HEALTHCHECK; код 200 значит, что процесс жив, а docker compose ps в этот момент покажет healthy. Не 200 — идите в раздел про контейнер, менять settings.yml рано. 200 есть, а результатов подозрительно мало — вопрос не в контейнере, а в /stats/errors: страница называет по каждому движку причину последнего отказа текстом самого исключения.

Контейнер падает в restart loop: права тома и путаница между uWSGI и Granian

Самая частая причина Restarting — несовпадение прав между тем, что просит образ, и тем, что разрешает ваш docker-compose.yml. Entrypoint-скрипт при старте копирует settings.yml из шаблона, если файла ещё нет в томе, и, если процесс запущен от root, рекурсивно меняет владельца тома на searxng:searxng — по умолчанию, через FORCE_OWNERSHIP=true. Для смены владельца нужна capability CHOWN.

Если вы из соображений безопасности добавили в сервис cap_drop: ALL и не вернули нужные права, entrypoint падает на этом же шаге. В логе будет что-то из этого набора — зависит от версии образа:

cp: can't create '/etc/searxng/uwsgi.ini': Permission denied
chown: /etc/searxng/uwsgi.ini: Operation not permitted
[uwsgi] unable to create the server socket: Operation not permitted

Раньше эти три строки означали попытку создать uwsgi.ini — SearXNG до недавнего времени поднимался через uWSGI. Начиная с образа 2025.7.4-01be261 контейнер перешёл на Granian: uwsgi.ini не используется и его можно удалить после проверки работоспособности. Суть проблемы с правами не изменилась — entrypoint споткнётся не на создании uwsgi.ini, а на chown тома или на попытке Granian занять сокет. Лечится одним из двух способов:

  • убрать cap_drop: ALL из описания сервиса — так собран официальный docker-compose.yml;
  • оставить cap_drop: ALL, но точечно вернуть: cap_add: [CHOWN, SETUID, SETGID].

Второй источник путаницы — устаревшие гайды. Репозиторий searxng-docker с Caddy, на который до сих пор ссылается большинство статей, заархивирован 28 марта 2026 года; актуальный docker-compose.yml лежит в основном репозитории, в каталоге container/, и поднимает два сервиса — searxng-core (searxng/searxng:${SEARXNG_VERSION:-latest}) и searxng-valkey (valkey/valkey:9-alpine). Контейнер redis вместо searxng-valkey в логах — признак старой схемы. И об версиях: SEARXNG_VERSION не семвер, а дата вида 2026.8.22-9fea412, так что latest в проде — плохая идея: между docker compose pull может смениться и сервер приложений, и дефолты settings.yml.

Развернуть за пару минут

Готовый образ на VPS MAATRIX: NVMe, AMD EPYC, root-доступ. Локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Развернуть SearXNG

`403 Forbidden` на `format=json`: ИИ-агент не получает результаты

Это самая частая причина, по которой SearXNG «не работает» именно как бэкенд для ИИ — для Open WebUI, Dify, LangChain, n8n или собственного RAG-пайплайна. Веб-интерфейс на / открывается нормально, а запрос вида:

curl -s "http://127.0.0.1:8080/search?q=test&format=json"

возвращает не JSON, а:

403 Forbidden
You don't have the permission to access the requested resource.

Причина — не блокировка и не баг, а настройка по умолчанию. Формат ответа в settings.yml задаётся списком, и «из коробки» в нём только html:

search:
  formats:
    - html

Пока json нет в этом списке, SearXNG отклоняет такой запрос на уровне приложения — ещё до обращения к движкам. Правка простая:

search:
  formats:
    - html
    - json

Дальше — перезапуск и повторная проверка, уже по коду ответа:

docker compose restart searxng-core
curl -s -o /dev/null -w "%{http_code}\n" "http://127.0.0.1:8080/search?q=test&format=json"
# 200

Не полагайтесь только на код ответа при интеграции с чужими или публичными инстансами: часть честно отдаёт 403, а часть — под видом 200 OK возвращает HTML-страницу проверки на бота вместо JSON, и response.json() в коде агента падает уже не с 403, а с ошибкой разбора. На своём сервере так не будет, но привычку проверять заголовок Content-Type: application/json, а не только статус, стоит оставить — надёжнее, чем ловить JSONDecodeError в рантайме агента.

Движки один за другим уходят в «Suspended: too many requests»

SearXNG не имеет официальных API-ключей ни к Google, ни к Bing — он делает то же, что обычный браузер, только с сервера и в промышленных объёмах. Рано или поздно движок отвечает не результатами, а капчей или кодом «слишком много запросов», и SearXNG сам ставит его на паузу. Длительность паузы жёстко зашита в settings.yml, в блоке suspended_times, и зависит от типа отказа:

ИсключениеТипичная причинаПауза по умолчанию
SearxEngineTooManyRequestsдвижок ответил кодом «too many requests»180 с (3 минуты)
SearxEngineAccessDeniedсайт отклонил сам запрос180 с (3 минуты)
SearxEngineCaptchaдвижок показал капчу3600 с (1 час)
cf_SearxEngineAccessDeniedблокировка именно от Cloudflare86400 с (1 сутки)
recaptcha_SearxEngineCaptchaкапча размечена как reCAPTCHA604800 с (7 суток)
cf_SearxEngineCaptchaкапча за подписью Cloudflare1296000 с (15 суток)

Заметить это просто: в выдаче внезапно на 3-5 источников меньше, чем обычно. Понять причину — через /stats/errors, без похода в логи контейнера.

Хуже, если под паузу разом попадают именно Google и Bing — самые требовательные к репутации IP движки по умолчанию. С дата-центрового адреса, особенно у бюджетного провайдера с «засвеченной» подсетью, они блокируют почти сразу. Обычная капча снимается через час, капча reCAPTCHA — через 7 суток, а капча за подписью Cloudflare — через все 15. Перезапуск контейнера паузу не снимает: таймер живёт в памяти процесса, а не в конфиге.

Практичный выход — не бороться за Google и Bing, а исключить их из списка и опереться на движки, которые переносят серверный трафик спокойнее:

engines:
  - name: google
    disabled: true
  - name: bing
    disabled: true

DuckDuckGo, Brave, Startpage, Mojeek и Wikipedia в среднем реже требуют капчу с серверных подсетей — не потому что «разрешают», а потому что их анти-бот эвристики мягче к чистым IP. Это вопрос адреса сервера, а не только конфига — вернёмся к нему в разделе про выбор сервера.

`secret_key: ultrasecretkey` и лимитер, который не поднимается без Valkey

Свежий settings.yml из шаблона содержит secret_key: "ultrasecretkey" — буквально этот текст, одинаковый на каждой инсталляции в мире. Если файл создаётся автоматически при первом запуске контейнера (тома ещё не было), entrypoint сам подставляет вместо заглушки случайное значение из /dev/urandom. Но если вы принесли settings.yml со стороны — из старого гайда, архивного searxng-docker или через docker cp — заглушка так и остаётся заглушкой. Проверка:

docker compose exec searxng-core grep secret_key /etc/searxng/settings.yml

Ручная замена — тем же способом, что в документации для установки без Docker:

sed -i -e "s/ultrasecretkey/$(openssl rand -hex 32)/g" /etc/searxng/settings.yml

Менее очевидная ловушка — рейт-лимит и бот-детект (server.limiter: true) требуют поднятого Valkey, форка Redis, и без него ведут себя не так, как кажется. По умолчанию в settings.yml стоит valkey: url: false. Включили limiter: true, не указав рабочий url — поведение зависит ещё от одной настройки, public_instance:

  • public_instance: true — процесс явно завершается (sys.exit(1)), и вы получаете тот же restart loop, что и в разделе про права, только с другой причиной;
  • public_instance: false (обычный случай для частного сервера) — SearXNG не падает и не пишет заметной ошибки на старте, а просто тихо не включает лимитер. Единственный след — строка в логе уровня error: The limiter requires Valkey, please consult the documentation.

То есть на закрытом инстансе бот-защита может быть выключена месяцами, а вы об этом не узнаете, пока не начнёте искать специально. Рабочий конфиг для связки с сервисом searxng-valkey:

server:
  limiter: true
valkey:
  url: valkey://searxng-valkey:6379/0

Reverse proxy: не тот IP для лимитера и битые ссылки за Nginx

Если SearXNG стоит за Nginx на своём домене — а для внешнего доступа иначе не имеет смысла — есть три места, где прокси незаметно ломает логику, которая у «голого» контейнера работала штатно.

Первое — заголовки X-Forwarded-For и X-Real-IP. Лимитер и бот-детект решают по IP клиента, и если Nginx их не прокидывает, все запросы приходят с одним адресом — адресом самого Nginx. Итог обратный ожидаемому: не «лимитер блокирует бота», а «один пользователь исчерпал лимит, и капчу теперь видят все», включая вас. Минимальный рабочий блок:

location / {
    proxy_pass http://127.0.0.1:8080;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $host;
}

Второе — server.base_url. Не совпадает с реальным внешним адресом или оставлен как false — внутренние ссылки (пагинация, переход по результату, картинки через прокси-режим) собираются неправильно, и часть UI за доменом не открывается, хотя первая страница выглядит рабочей.

Третье — смешение старого и нового шаблона. В документации рядом лежат два примера: сокетный, для uWSGI (uwsgi_pass unix:///usr/local/searxng/run/socket; с параметрами uwsgi_param), и HTTP-based для контейнера — как в блоке выше. uwsgi_param работает только внутри location с uwsgi_pass; вставили её в блок с proxy_passnginx -t откажется стартовать с nginx: [emerg] unknown directive "uwsgi_param". И не пугайтесь строки X-Forwarded-For header is not set! X-Real-IP header is not set! в логе SearXNG: так бот-детект жалуется на встроенный HEALTHCHECK, который стучится в /healthz напрямую, минуя Nginx. Это шум, а не ошибка конфигурации.

Какой сервер под SearXNG брать в MAATRIX

SearXNG сам по себе — тонкий процесс на Flask поверх Granian: не считает эмбеддинги и не хранит индекс, а параллельно опрашивает внешние движки и разбирает их ответы. Нагрузка не процессорная, а сетевая и по числу соединений: чем активнее вы или ИИ-агент шлёте запросы, тем больше держится параллельных исходящих подключений разом и тем заметнее память на воркер. Разработчики прямо предупреждают не трогать число воркеров Granian вручную — по их словам, это увеличивает расход ресурсов и мешает бот-детекту.

Честный минимум: 1 vCPU, 1-2 ГБ RAM, 20 ГБ NVMe. Такой сервер тянет SearXNG без Valkey — то есть без лимитера, как в разделе выше. Для частного инстанса на одного-двух пользователей или одного ИИ-агента это осознанный компромисс, а не поломка. Поднимаете Valkey, включаете limiter: true, растёт число клиентов — память становится тесной быстрее процессора; точный расчёт под ваш профиль запросов — в статье «Сколько RAM нужно для SearXNG и Perplexica».

Комфортный вариант: 2 vCPU, 4 ГБ RAM, 40 ГБ NVMe. Хватает на SearXNG вместе с searxng-valkey, включённый лимитер, десяток активных движков и разборы /stats/errors — без запаса памяти под них разделы 1 и 4 этой статьи пришлось бы проходить вслепую.

Локация — Великобритания (Лондон). SearXNG — приватная альтернатива поисковикам с трекингом, и держать его под юрисдикцией с понятным режимом персональных данных — продолжение этой идеи, а не формальность. Плюс низкий пинг до остальной Европы, если ИИ-инструмент, который дёргает SearXNG — тот же Perplexica или свой агент на LangChain, — тоже развёрнут в ЕС. На капчи из раздела про движки локация напрямую не влияет: Google одинаково подозрителен к дата-центровым адресам что в Лондоне, что в Нью-Йорке. Но чистый выделенный IP, не засвеченный чужим трафиком, снижает частоту капчи заметнее, чем страна.

При заказе сервера SearXNG из каталога apps.maatrix.io ставится автоматически — на Ubuntu и на Debian, без ручных команд из разделов про контейнер выше: адрес панели и ключи доступа появятся в личном кабинете, в разделе «Доступ». А вот format: json под ИИ-агента, список отключённых движков и связка limiter + valkey — решения по вашей задаче, автоустановка их не примет; разбор из этой статьи остаётся актуальным и для сервера, поднятого через каталог.

Развернуть за пару минут

Готовый образ на VPS MAATRIX: NVMe, AMD EPYC, root-доступ. Локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Развернуть SearXNG

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Частые вопросы

Веб-интерфейс работает, а curl .../search?format=json — всё равно 403. Что не так?

Проверьте, что правили именно тот settings.yml, который смонтирован в контейнер (docker compose exec searxng-core cat /etc/searxng/settings.yml), и что контейнер перезапущен: docker compose restart searxng-core. Исключите обратный прокси — если 403 отдаёт Nginx, а не SearXNG, в теле ответа не будет фразы You don't have the permission..., характерной именно для приложения.

После обновления образа контейнер перестал подниматься, хотя настройки не трогали. В чём может быть дело?

Начиная с образа 2025.7.4-01be261 SearXNG перешёл с uWSGI на Granian; правки в uwsgi.ini при обновлении просто игнорируются, серверные параметры нужно перенести в переменные GRANIAN_*. Заодно проверьте cap_drop: ALL — с новым entrypoint это частая причина падения на chown тома.

Нужен ли Valkey, если SearXNG стоит только для меня одного?

Нет: без него инстанс с public_instance: false работает штатно, просто без рейт-лимита и бот-детекта. Valkey обязателен, как только вы даёте доступ ещё кому-то — коллеге, второму ИИ-агенту — или ставите public_instance: true: тогда без Valkey процесс не запустится вовсе.

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.