SSD Nodes Learn Hosting plans →
Посібники Matt ConnorВід Matt Connor · Оновлено 2026-09-05

Як встановити приватний SearXNG на власному VPS

Запустіть SearXNG через Docker Compose: налаштуйте settings.yml і limiter, додайте nginx з TLS та JSON search API для власних скриптів.

Що ви створюєте

Власний SearXNG дає приватну пошукову систему, яка працює на вашому сервері. SearXNG — це метапошукова система: вона отримує ваш запит, надсилає його до інших систем, зокрема Google, Bing, DuckDuckGo і Wikipedia, а потім об’єднує отримані результати на одній сторінці. Профіль не створюється, а tracking cookie не встановлюється, оскільки єдиний комп’ютер, на якому зберігається ваш запит, належить вам. Якщо ви знайшли старіші інструкції для проєкту, який називався просто Searx, то саме від нього походить цей fork. У ньому не було commit із 2023, тому перевірте стан обох проєктів, перш ніж обрати один.

Стек невеликий: два контейнери, один файл налаштувань і один reverse proxy. Він без проблем працюватиме на невеликому VPS. Це стосується не кожного self-hosted сервісу: у порівнянні PhotoPrism та Immich обсяг RAM для бібліотек фотографій визначає indexer, а не web app. Основне рішення полягає в тому, чи буде інстанс приватним, тобто доступним лише вам і вашим скриптам, чи публічним, тобто доступним для запитів будь-кому в інтернеті. Від цього залежать security settings, тому визначтеся до початку налаштування. Значення за замовчуванням — приватний інстанс.

Є ще одна причина запустити власний інстанс. SearXNG підтримує JSON, тому будь-який написаний вами скрипт або AI agent отримує власний search API без ключа, оплати за кожен запит і повідомлень про перевищення квоти.

Встановлення SearXNG за допомогою Docker Compose

Проєкт публікує образ контейнера та файл Compose. Завантажте обидва на новий сервер Ubuntu 24.04, де вже встановлено Docker Engine і плагін Compose. Якщо ви ще не працювали з Docker, почніть із матеріалу Основи Docker Compose на VPS, а потім поверніться сюди.

sudo install -d -o "$USER" -g "$USER" -m 750 /opt/searxng
cd /opt/searxng
mkdir -p core-config
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 визначає два сервіси. core — це сам SearXNG, а valkey — сховище даних у пам’яті, яке використовується для обмеження частоти запитів і короткочасного стану. Воно монтує ./core-config/ у /etc/searxng/ всередині контейнера, тому все налаштоване вами зберігається в одному каталозі на хості.

Тепер відредагуйте .env. Кожен рядок у прикладі, що постачається, закоментований. Саме тому контейнер запускається на порту 8080 на всіх адресах. Розкоментуйте та налаштуйте ці три параметри.

SEARXNG_VERSION=latest
SEARXNG_HOST=127.0.0.1
SEARXNG_PORT=8080

SEARXNG_HOST=127.0.0.1 — найважливіший параметр. Він робить опублікованим порт 127.0.0.1:8080:8080 замість [::]:8080:8080, тому контейнер відповідає лише на loopback-адресі, і з Інтернету до нього неможливо підключитися безпосередньо. Якщо пропустити цей крок, контейнер стане доступним одразу після запуску, оскільки опублікований порт Docker вставляється перед правилами вашого firewall. Цю особливість варто прочитати повністю: опубліковані порти Docker обходять ufw.

SEARXNG_VERSION=latest підходить для навчання. На важливому для вас сервері зафіксуйте тег. Станом на July 2026 теги релізів базуються на даті й мають вигляд 2026.3.25-541c6c3cb, тому розгортання з фіксованою версією оновлюється тоді, коли ви вирішите це зробити, а не коли registry змінить образ. Такий самий підхід корисний для всього, що тривалий час працює на сервері. Саме тому self-hosted ретранслятор RustDesk також використовує фіксовані теги образів: неконтрольоване оновлення сервісу віддаленого доступу дає про себе знати в найгірший момент.

settings.yml: важливі параметри

Створіть core-config/settings.yml до першого запуску. use_default_settings: true вказує SearXNG завантажити власні стандартні параметри, які постачаються з програмою, а потім застосувати лише вказані вами ключі. Тому файл залишається коротким і не ламається після оновлень, які додають нові параметри.

Спочатку згенеруйте секрет, оскільки це значення буде безпосередньо записано у файл.

openssl rand -hex 32
use_default_settings: true

general:
  instance_name: "search.example.com"

server:
  base_url: "https://search.example.com/"
  secret_key: "paste-the-openssl-output-here"
  limiter: false
  public_instance: false
  image_proxy: true

valkey:
  url: valkey://valkey:6379/0

search:
  safe_search: 0
  autocomplete: "duckduckgo"
  formats:
    - html
    - json

secret_key підписує дані сеансів і токенів. Стандартним значенням є літеральний рядок ultrasecretkey. Якщо його залишити, будь-хто, хто знає це значення, зможе підробляти такі токени. Замініть його один раз і більше не змінюйте: подальша зміна видалить усі збережені налаштування.

base_url має бути публічною HTTPS-адресою із завершальною косою рискою. SearXNG використовує її в посиланнях, які генерує. Якщо залишити localhost, посилання «наступна сторінка» у віддаленому браузері вказуватиме на власний комп’ютер користувача й не працюватиме.

formats визначає типи результатів, які повертатиме вебендпойнт. json немає у списку за замовчуванням, тому JSON-запит повертатиме 403, доки ви не додасте цей тип. image_proxy: true передає мініатюри результатів через ваш сервер, тому сайти, на яких зберігаються ці зображення, не бачитимуть адрес ваших відвідувачів.

valkey.url використовує ім’я хоста valkey, оскільки це ім’я сервісу у файлі Compose. Compose розміщує обидва контейнери в одній мережі, де імена сервісів доступні для визначення. Якщо вказати localhost, обмежувач запитів не працюватиме, оскільки всередині контейнера core localhost означає саме цей контейнер.

Секрет зберігається у звичайному файлі, тому захистіть каталог, у якому він міститься, а не лише сам файл. chmod 750 /opt/searxng не дає іншим користувачам хоста отримати доступ. Не встановлюйте для core-config/settings.yml режим 600: контейнер працює від власного непривілейованого користувача, і якщо цей користувач не зможе прочитати файл, SearXNG взагалі не запуститься.

Запустіть стек і перевірте його.

cd /opt/searxng
docker compose up -d
docker compose ps
curl -I http://127.0.0.1:8080/

docker compose ps має показати обидва контейнери у стані running. curl має повернути відповідь HTTP/1.1 200 OK. Якщо відповіді немає, перегляньте docker compose logs core, оскільки помилка YAML у settings.yml відображається там як помилка синтаксичного аналізу із зазначенням рядка.

Розмістіть його за nginx із TLS

Контейнер прослуховує лише loopback-інтерфейс, тому саме nginx робить його доступним. Він також додає захист транспортного рівня (TLS). Запишіть /etc/nginx/sites-available/searxng.

server {
    listen 80;
    server_name search.example.com;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}
sudo ln -s /etc/nginx/sites-available/searxng /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
sudo certbot --nginx -d search.example.com

nginx -t виводить syntax is ok і test is successful перед перезавантаженням. Certbot перезаписує той самий файл, щоб прослуховувати порт 443 із сертифікатом, і додає перенаправлення з порту 80. Запис DNS для search.example.com уже має вказувати на цей сервер, оскільки центр сертифікації підтверджує право власності, завантажуючи файл через HTTP. Повний посібник, зокрема щодо поновлення сертифіката, наведено в посібнику з Certbot і nginx для Ubuntu 24.04.

Ці два заголовки для пересилання не є декоративними. Без X-Forwarded-For і X-Real-IP кожен запит до SearXNG містить адресу проксі, тому обмежувач частоти запитів бачить одного клієнта, який генерує весь трафік, і не може розрізнити відвідувачів.

Чому скриптам і агентам потрібен JSON API для пошуку

Якщо в json указати formats, той самий endpoint, який відображає сторінку, повертає структуровані дані.

curl -s 'http://127.0.0.1:8080/search?q=wireguard+mtu&format=json' \
  | jq -r '.results[0:5][] | .url'

У відповіді ви отримуєте об’єкт із масивом results. Кожен його елемент містить url, title, content і назву рушія, який надав результат, а також answers, infoboxes і suggestions. Цього достатньо, щоб передати дані summariser, перевірці посилань або циклу дослідження. Передавання цих результатів мовній моделі є складнішим кроком, ніж здається, оскільки результати пошуку — це ненадійний текст, який може містити власні інструкції. Саме це детально розглянуто в матеріалі як підключити AI-агента до свого екземпляра SearXNG.

Це важливо для будь-яких систем на основі агентів. Мовна модель має дату завершення навчання, тому для відповідей на запитання про поточні події їй потрібен пошук у реальному часі. Комерційні пошукові API стягують плату за кожен запит і жорстко обмежують частоту запитів. Локальний екземпляр займає один контейнер на сервері, за який ви вже платите, а запити не залишають його. Якщо ви підключаєте інструменти до моделі, те саме міркування стосується запуску MCP-серверів на VPS, де пошуковий інструмент зазвичай додають першим.

Під час використання API дотримуйтеся двох правил. Зробіть екземпляр приватним: прив’яжіть API до loopback-адреси або приватної мережі й дозвольте доступ лише своїм хостам. Потім надсилайте запити з помірною частотою. SearXNG пересилає ваш запит реальним пошуковим системам, тому скрипт, який виконує сто запитів за секунду, фактично просить Google заблокувати ваш сервер.

Лімітер і те, що змінюється для публічного інстансу

Лімітер — це засіб захисту SearXNG від ботів. Він відстежує заголовки запитів, адреси та частоту запитів і відкидає трафік, який має ознаки автоматизованого. Для зберігання цього стану йому потрібен Valkey, тому Valkey включено до Compose file.

У приватному інстансі залиште limiter: false. Ваші власні скрипти за визначенням створюють автоматизований трафік, тому лімітер блокував би саме ті JSON-запити, заради яких ви розгорнули інстанс. Контроль доступу має забезпечувати reverse proxy: пара allow і deny у конфігурації nginx location, HTTP basic authentication або firewall, який дозволяє підключення лише від інших ваших серверів. Якщо потрібно підключатися до приватного інстансу з ноутбука, який переходить між різними мережами, розміщення onion-адреси v3 перед ним є четвертим варіантом, оскільки tor підключається до того самого loopback-порту, не відкриваючи нічого нового для інтернету.

Якщо ви публікуєте інстанс для інших користувачів, увімкніть обидва перемикачі.

server:
  limiter: true
  public_instance: true

Детальніше керування налаштовується в core-config/limiter.toml, який контейнер читає з /etc/searxng/limiter.toml. Записуйте лише ключі, які потрібно змінити. За reverse proxy потрібно оголосити proxy, інакше лімітер сприйматиме адресу nginx як адресу одного клієнта, що створює надмірний трафік.

[botdetection]
trusted_proxies = [
  '127.0.0.0/8',
  '::1',
]

[botdetection.ip_limit]
link_token = true

link_token = true змушує SearXNG видавати токен, який отримує лише справжня browser session. Це блокує більшість простих scraper-ів. Публічний інстанс почне приваблювати їх уже протягом кількох днів. Також очікуйте помилок від пошукових engine-ів, оскільки що більше трафіку ви пересилаєте, то швидше upstream engine-и почнуть повертати CAPTCHA на адресу вашого сервера. Публічний інстанс SearXNG потребує постійного адміністрування. Приватний інстанс — ні, тому він є в більшості коротких списків того, що варто self-host у 2026 році. Водночас не кожен пункт у таких списках є інфраструктурою: перетворення бібліотеки Jellyfin на доступний для прогулянок відеопрокат у стилі 90s — це той самий один контейнер за тим самим блоком nginx, але він орієнтований на вечірній перегляд, а не на робочий процес.

Чому пошук не повертає результатів

Відкрийте /stats у своєму екземплярі. Тут наведено всі рушії, рівень помилок і час відповіді для кожного з них. Це перше місце, яке слід перевірити, коли результатів мало.

Пошуковий рушій із помилками "Access denied" або "CAPTCHA" заблокував адресу вашого сервера. Це типово для адрес із діапазонів дата-центрів, оскільки пошукові системи вважають, що вони належать скрейперам. Після цього SearXNG на певний час призупиняє рушій, який повертає помилки, замість повторної спроби. Тому один заблокований рушій непомітно зникає з результатів пошуку. Вимкніть його в settings.yml або прийміть втрату. Це не єдині варіанти, оскільки для деяких блокувань CAPTCHA є спосіб виправлення, який зберігається після перезапуску. Інші рушії продовжують відповідати. Код 429 є неоднозначним випадком, оскільки він може походити від вашого власного обмежувача або від зовнішнього рушія, який відхиляє запити вашого сервера. Рядок у журналі показує, який саме з цих двох випадків ви маєте, перш ніж ви почнете змінювати налаштування.

Якщо всі рушії одночасно завершуються помилкою, контейнер не може виконувати зовнішнє розпізнавання імен або не має маршруту до інтернету. Перевірте це зсередини контейнера.

docker compose exec core wget -qO- https://duckduckgo.com > /dev/null && echo ok

Система не повідомить вам, коли ця перевірка почне завершуватися помилкою. Тому запускайте її з cron і налаштуйте, щоб помилка надсилала сповіщення на ваш телефон із вашого власного сервера ntfy, замість того щоб чекати, поки ви помітите, що результатів стало мало.

FAQ

Чи робить SearXNG мої пошукові запити анонімними?

SearXNG приховує вашу особу від пошукових систем, до яких надсилає запити, оскільки вони бачать запит від вашого сервера, а не від браузера. Однак сервіс не приховує запити від вашого сервера і не приховує ваш сервер від пошукових систем. В екземплярі для одного користувача весь трафік із цієї адреси належить вам, тому сама адреса стає ідентифікатором. Трафік між браузером і вашим екземпляром захищає TLS-сертифікат. Наслідки цього для взаємодії з вашим ISP, оператором публічного екземпляра та самими пошуковими системами описано в розділі що саме приховує SearXNG.

Чому JSON-запит повертає 403 Forbidden?

Є дві причини, і обидві пов’язані з конфігурацією. Або json відсутній у списку formats під search: у settings.yml, що є типовим станом, або limiter увімкнений і класифікував ваш скрипт як бота. Спочатку додайте цей формат, перезапустіть сервіс за допомогою docker compose restart core, а потім повторіть запит. Якщо помилка не зникне, задайте limiter: false і керуйте доступом на reverse proxy.

Чи потрібен контейнер Valkey, якщо limiter вимкнений?

Залиште його запущеним. SearXNG працює без нього, але без цього контейнера limiter не можна буде ввімкнути пізніше. Крім того, контейнер зберігає інші короткоживучі дані. Контейнер невеликий і зберігає лише кешовані дані, тому його видалення майже нічого не заощаджує, але позбавляє вас цієї можливості.

Як оновити SearXNG?

Виконайте docker compose pull, а потім docker compose up -d у /opt/searxng. Compose повторно створить кожен контейнер, для якого змінився image, і залишить каталог core-config/ без змін, тому settings.yml збережеться. Оскільки use_default_settings: true об’єднує ваші ключі зі стандартними значеннями, які постачаються разом із продуктом, нові параметри, додані upstream, отримують коректні значення замість того, щоб спричинити пошкодження файлу.

Чи можуть кілька людей користуватися одним екземпляром?

Так. У такому випадку потрібно ввімкнути limiter і задати public_instance: true. Налаштування зберігаються у власному браузері кожного відвідувача, тому облікові записи не потрібно адмініструвати. Протягом тижня після відкриття доступу стежте за /stats, оскільки upstream-пошукові системи починають відхиляти запити вашого сервера задовго до того, як ви помітите відсутні результати.