Как установить и настроить SearXNG на VPS
Контейнер поднимается за минуту, а дальше начинается настоящая работа: инстанс молча падает на дефолтном secret_key, ссылки в выдаче ведут на http://localhost:8080, а Perplexica вместо JSON получает 403 Forbidden. Установка SearXNG на VPS — это не docker compose up, а десяток решений в settings.yml, от которых зависит, будет поиск работать или молчать. Ниже — весь путь: обязательные параметры, разбор конфига по секциям, движки, лимитер с Valkey, обратный прокси и подключение ИИ-приложений.
Содержание
- Что такое SearXNG и когда он нужен на VPS
- Обязательный минимум: secret_key, base_url и use_default_settings
- settings.yml по секциям: search, server, outgoing
- Движки, категории и bang-синтаксис
- Valkey и лимитер: защита от ботов и от своих же приложений
- Обратный прокси, TLS и подключение ИИ-приложений
- Какой сервер под SearXNG брать в MAATRIX
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Что такое SearXNG и когда он нужен на VPS
SearXNG — метапоисковик: собственного индекса и краулера у него нет. Он принимает запрос, рассылает его параллельно во внешние источники — Google, DuckDuckGo, Brave, Wikipedia, Stack Overflow, GitHub, arXiv и ещё сотню движков из поставки, — разбирает ответы и склеивает их в одну выдачу без рекламы и профилирования. Формально это форк searx, но кодовые базы разошлись давно: старые конфиги searx переносить бессмысленно, половина ключей просто не существует.
Из архитектуры следуют три вещи. Наружу ходит ваш сервер, а не браузер пользователя — отсюда приватность, но и главная боль: датацентровые IP поисковики знают и охотно показывают им капчу вместо результатов. Диск почти не нужен — хранить нечего, ни индекса, ни кэша страниц. Нагрузка — сеть и парсинг HTML: один запрос превращается в десяток параллельных HTTPS-соединений, процессор нужен короткими всплесками, а не постоянно.
На VPS SearXNG чаще всего ставят как поисковый бэкенд для ИИ-приложений: Perplexica, Open WebUI, n8n и самописные RAG-пайплайны ходят к нему за JSON, потому что это единственный способ дать модели свежий веб без платного Serper или SerpAPI. Второй сценарий — личный поисковик для себя и коллег, третий — публичный инстанс из списка searx.space.
Сценарий стоит выбрать до установки: приватный инстанс живёт с limiter: false и без Valkey, публичный обязан включить оба — иначе открытый шлюз бесплатно скрейпит Google для чужих ботов, о чём подробнее в пятой секции.
Обязательный минимум: secret_key, base_url и use_default_settings
Два параметра ломают инстанс молча, если о них забыть.
server.secret_key. В поставке — заглушка, и с ней приложение либо не стартует, либо путает cookie между пользователями. В логе контейнера это выглядит так:
ERROR:searx.webapp: server.secret_key is not changed. Please use something else than ultrasecretkey.
После этого docker compose ps показывает Exited (1). Генерируется один раз командой openssl rand -hex 32 и больше не меняется: ключ подписывает cookie с настройками и токены лимитера, смена сбрасывает их у всех разом. В официальном образе есть переменная SEARXNG_SECRET — скрипт запуска сам подставит значение в settings.yml вместо заглушки, и хранить ключ в YAML, который лежит в git, не придётся.
server.base_url. Полный внешний адрес со схемой и слэшем в конце: https://search.example.com/. По нему строятся ссылки в OpenSearch (кнопка «добавить поиск в браузер»), в RSS и в редиректах после сохранения настроек. Симптом неверного значения: интерфейс открывается по домену, а после «Сохранить» в настройках браузер уезжает на http://localhost:8080/.
Третье — без строки use_default_settings: true ваш settings.yml считается полным набором, и SearXNG стартует вообще без движков: выдача пустая, а в логах ни одной ошибки. Минимальный рабочий файл:
use_default_settings: true
server:
secret_key: "ultrasecretkey" # подставится из SEARXNG_SECRET
base_url: "https://search.example.com/"
limiter: false
image_proxy: true
method: "GET"
Живость проверяется отдельным эндпоинтом без авторизации:
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8080/healthz
200
Порт контейнера стоит публиковать только на 127.0.0.1:8080:8080 — наружу пускает Nginx из шестой секции, открытый 8080 без TLS не нужен.
Развернуть за пару минут
Готовый образ на VPS MAATRIX: NVMe, AMD EPYC, root-доступ. Локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Развернуть SearXNGsettings.yml по секциям: search, server, outgoing
Дефолт рассчитан на анонимный публичный инстанс, а вы настраиваете свой. Разберём параметры, которые реально меняют поведение.
search. default_lang: "ru" — без него русскоязычные запросы регулярно получают англоязычную выдачу. autocomplete: "duckduckgo" включает подсказки; по умолчанию источник не выбран, и подсказки просто молчат. Пара ban_time_on_fail / max_ban_time_on_fail — секунды, на которые упавший движок выпадает из опроса, с удвоением при повторах.
Главная строка — formats. По умолчанию там только html. Пока не добавите json, любой запрос вида /search?q=test&format=json вернёт 403 Forbidden — именно это ловят все, кто подключает Perplexica или Open WebUI:
search:
default_lang: "ru"
formats: [html, json]
server. method: "GET" — по умолчанию форма отправляется POST, и ссылку на результаты нельзя скопировать или дёрнуть из скрипта; для интеграций и шарящихся URL ставят GET. image_proxy: true заворачивает картинки через ваш сервер — хосты изображений не видят IP пользователя, честная плата — трафик и процессор на каждую миниатюру.
outgoing. request_timeout: 3.0 — три секунды на ответ движка по умолчанию. На канале с большими задержками до Европы часть источников не успевает, и выдача выглядит бедной без единой ошибки в логе; поднимать до 5–6 секунд можно, но общий ответ пользователю ждёт самый медленный движок.
Движки, категории и bang-синтаксис
Движок — это описание того, как сформировать запрос к источнику и разобрать ответ. В поставке их больше сотни, включена по умолчанию примерно треть.
Правило слияния неинтуитивное: при use_default_settings: true движки в вашем файле дополняют дефолтные по совпадению имени, а не заменяют список:
engines:
- name: google
timeout: 4.0
weight: 2
- name: wikidata
disabled: true
Для короткого белого списка есть отдельный синтаксис:
use_default_settings:
engines:
keep_only: [google, duckduckgo, brave, wikipedia, github]
Оставлять пять движков вместо сорока разумно: поиск быстрее, а сорок параллельных запросов с одного адреса — верный способ познакомиться с чужой защитой от ботов. weight управляет ранжированием, а shortcut включает bang-синтаксис, ради которого SearXNG часто и ставят: !go пример ищет только в Google, !wp — только в Википедии, :ru новости задаёт язык результатов, а !!go пример с двумя знаками делает редирект прямо в выдачу движка, минуя SearXNG.
Проверять после правок — страница /preferences со временем ответа каждого движка и /stats/errors с недавними отказами. Честное ограничение: часть движков со временем ломается — источники меняют вёрстку, требуют JavaScript или блокируют датацентровые подсети, Google и Bing особенно охотно отвечают серверным адресам капчей. Это условия игры метапоиска, а не поломка вашей установки; разбор пустой выдачи — в статье SearXNG выдаёт пустую выдачу: причины и решение.
Valkey и лимитер: защита от ботов и от своих же приложений
Лимитер — встроенная защита от автоматических запросов: считает обращения с адреса, проверяет заголовки браузера и выдаёт ссылкам скрытый токен, который настоящий браузер подхватывает, а скрипт — нет. Работает он только с внешним хранилищем. Исторически это был Redis; после смены его лицензии SearXNG перешёл на Valkey — в старых руководствах встретите redis: и SEARXNG_REDIS_URL, читайте как valkey: и SEARXNG_VALKEY_URL.
valkey:
url: valkey://searxng-valkey:6379/0
server:
limiter: true
public_instance: false
Если включить limiter: true, а хранилище не поднять, защита молча не работает — инстанс продолжит отвечать всем подряд. Проверяют не по конфигу, а по факту:
docker exec -it searxng-valkey valkey-cli ping
PONG
Тонкая настройка — в отдельном файле /etc/searxng/limiter.toml. Ключевые секции:
[real_ip]
x_for = 1
[botdetection.ip_limit]
link_token = true
[botdetection.ip_lists]
pass_ip = ["172.16.0.0/12"]
x_for = 1 значит «доверять последнему значению в X-Forwarded-For» — одному прокси перед приложением; при неверном значении SearXNG либо забанит всех разом при первом всплеске, либо не забанит никого. link_token = true — самая жёсткая проверка, она отсекает ботов и вместе с ними ваши же приложения. Отсюда правило для смешанного сценария: адреса своих сервисов — в pass_ip, и если Perplexica живёт в той же docker-сети, разрешать нужно её подсеть, а не 127.0.0.1:
docker network inspect searxng_searxng --format '{{range .IPAM.Config}}{{.Subnet}}{{end}}'
Честно: лимитер защищает от неаккуратных ботов, а не от целенаправленной нагрузки. На публичном инстансе за ним всё равно нужны ограничения на уровне Nginx.
Обратный прокси, TLS и подключение ИИ-приложений
Наружу SearXNG выставляют только через прокси с TLS:
server {
listen 443 ssl;
server_name search.example.com;
ssl_certificate /etc/letsencrypt/live/search.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/search.example.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 60s;
}
}
Три заголовка обязательны: без X-Forwarded-For лимитер не увидит клиента, без X-Forwarded-Proto приложение решит, что соединение не зашифровано, и будет строить ссылки на http://, без Host сломается сопоставление с base_url. Сертификат — certbot --nginx -d search.example.com, фаервол закрывает лишнее:
ufw allow 22/tcp
ufw allow 80,443/tcp
ufw deny 8080/tcp
Для приватного инстанса добавьте auth_basic. Оговорка: Basic Auth ломает интеграции, которые не шлют заголовок Authorization, поэтому приложения соединяют с SearXNG не через домен, а по внутреннему адресу, минуя Nginx. Perplexica — в config.toml:
[API_ENDPOINTS]
SEARXNG = "http://searxng:8080"
Open WebUI — переменными: ENABLE_RAG_WEB_SEARCH=true, RAG_WEB_SEARCH_ENGINE=searxng, SEARXNG_QUERY_URL=http://searxng:8080/search?q=<query>. В обоих случаях searxng — имя сервиса в docker-compose, работающее как DNS внутри общей сети; 127.0.0.1 внутри контейнера — это сам контейнер. Сборка связки целиком — в статье про установку Perplexica на VPS.
Проверка одной командой — ответ должен быть JSON, а не HTML:
curl -s 'http://127.0.0.1:8080/search?q=nginx+timeout&format=json' \
| jq '{results: (.results|length), engines: .unresponsive_engines}'
unresponsive_engines полезнее всего — там движки, не ответившие на этот запрос, с причиной. number_of_results часто равен нулю даже при полной выдаче: метапоиск не знает общего числа совпадений и не пытается его выдумать. Пришла HTML-страница с 403 вместо JSON — не добавлен json в search.formats либо сработал лимитер; каталог типовых поломок — в статье про частые ошибки SearXNG на сервере.
Какой сервер под SearXNG брать в MAATRIX
Требования у SearXNG скромные: индекса нет, база не нужна, диск занимает код и логи. Но два ресурса недооценивают.
Честный минимум: 1 vCPU, 2 ГБ RAM, 20 ГБ NVMe. Хватает для личного инстанса на одного-двух человек и пары приложений рядом. Ограничение прямое: один воркер обрабатывает запрос целиком, пока идёт поиск — второй пользователь ждёт; лечится ростом UWSGI_WORKERS, но каждый воркер — отдельный процесс Python, память растёт линейно с их числом. На 1 ГБ ставить не стоит: рядом обычно просятся Valkey, Nginx и контейнер ИИ-приложения, а всплеск при парсинге десятка HTML-ответов — верный визит OOM-киллера.
Комфортный вариант: 2 vCPU, 4 ГБ RAM, 40 ГБ NVMe. Помещаются SearXNG с четырьмя воркерами, Valkey, Nginx с TLS и запас на логи — достаточно для команды и роли поискового бэкенда у нескольких сервисов. Если рядом ещё и локальная модель для Perplexica, считать нужно по ней, а не по поиску — расчёт в статье сколько RAM нужно для SearXNG и Perplexica.
Взять с запасом стоит канал: при image_proxy: true каждая миниатюра в выдаче идёт через ваш сервер, и на активном инстансе картинки дают больше трафика, чем весь остальной поиск.
Локация — Лондон (UK). Для метапоиска локация важнее конфигурации: запросы к движкам уходят с адреса сервера, и поисковики оценивают именно его. Британский IP европейского провайдера получает нормальную выдачу там, где адрес из подсети, замеченной в скрейпинге, — капчу. До дата-центров Google, DuckDuckGo и Brave в Европе из Лондона десятки миллисекунд, и трёхсекундный request_timeout перестаёт быть проблемой; рядом — соседство с GDPR, если инстансом пользуются не только вы. США берут, если рядом на том же сервере живут ИИ-сервисы с американским IP, Франция — альтернатива Лондону с тем же профилем. Россия для SearXNG подходит хуже всего: часть движков с российских адресов отвечает через раз.
Разворачивать вручную не нужно: SearXNG есть в каталоге apps.maatrix.io и ставится автоматически при заказе сервера — на Ubuntu и на Debian. Адрес интерфейса и доступы появляются в личном кабинете, в разделе «Доступ»; остаётся зайти, поправить settings.yml под свой сценарий и подключить приложения. Оплата — картой российского банка, по СБП, криптовалютой или токеном MAAT.
Развернуть за пару минут
Готовый образ на VPS MAATRIX: NVMe, AMD EPYC, root-доступ. Локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Развернуть SearXNGОбсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Частые вопросы
Perplexica и Open WebUI получают 403 вместо результатов. Что не так?
Две причины, обе в конфиге: в search.formats не добавлен json (по умолчанию только html), либо включён лимитер, а адрес приложения не внесён в pass_ip в limiter.toml — при обращении из соседнего контейнера нужна подсеть docker-сети, а не 127.0.0.1. Проверка — curl -s 'http://127.0.0.1:8080/search?q=test&format=json' | head -c 200.
Можно ли обойтись без Valkey?
Да, если инстанс приватный и закрыт фаерволом или Basic Auth — тогда server.limiter: false. Для публичного — нет: без Valkey лимитер не работает, и сервер бесплатно скрейпит Google для чужих ботов, пока движки не начнут отвечать капчей на всё подряд.
Что будет, если сменить secret_key на работающем инстансе?
Не критично, но заметно: ключ подписывает cookie с настройками и токены лимитера, поэтому у всех сбросятся выбранные движки, язык и тема. Меняйте его только при подозрении на утечку и предупредите пользователей.
Нужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.