SSD Nodes Learn Hosting plans →
Przewodniki Matt ConnorAutor: Matt Connor

Jak zainstalować SearXNG przez Docker Compose

Skonfiguruj prywatną wyszukiwarkę SearXNG na własnym serwerze VPS. Poradnik obejmuje edycję settings.yml, konfigurację nginx z TLS oraz obsługę API dla własnych skryptów.

Co budujesz

Samodzielne hostowanie SearXNG zapewnia prywatną wyszukiwarkę działającą na własnym serwerze. SearXNG to metawyszukiwarka: pobiera zapytanie, wysyła je do innych wyszukiwarek, takich jak Google, Bing, DuckDuckGo czy Wikipedia, a następnie łączy wyniki na jednej stronie. Nie tworzy profilu użytkownika ani nie zapisuje plików cookie śledzących, ponieważ jedyną maszyną przechowującą zapytanie jest Twój serwer. Jeśli natrafiłeś na starsze poradniki dotyczące projektu o nazwie Searx, jest to projekt, z którego wywodzi się obecny. Nie jest on utrzymywany od września 2023 roku, kiedy to w repozytorium ogłoszono zakończenie wsparcia, a jedyny commit od tego czasu, będący notatką w dokumentacji z maja 2026, tego nie zmienił. Dlatego sprawdź stan obu projektów przed skorzystaniem z poradnika.

Stos technologiczny jest niewielki. Dwa kontenery, jeden plik ustawień, jeden reverse proxy. Usługa bez problemu współdzieli zasoby małego VPS, co nie jest regułą w przypadku każdego oprogramowania self-hosted: biblioteki zdjęć porównywane w PhotoPrism kontra Immich wyznaczają minimalne zużycie pamięci RAM na podstawie indeksatora, a nie samej aplikacji webowej. Kluczową decyzją jest to, czy instancja ma być prywatna (dostępna tylko dla Ciebie i Twoich skryptów), czy publiczna (dostępna dla każdego w Internecie). Wybór ten wpływa na konfigurację bezpieczeństwa, więc podejmij go przed rozpoczęciem pracy. Domyślną opcją jest instancja prywatna.

Istnieje drugi powód, aby uruchomić własną instancję. SearXNG obsługuje format JSON, dzięki czemu każdy skrypt lub agent AI zyskuje własny interfejs API do wyszukiwania, bez konieczności używania kluczy, opłat za zapytanie czy limitów kwotowych.

Instalacja SearXNG przy użyciu Docker Compose

Projekt udostępnia obraz kontenera oraz plik Compose. Pobierz oba elementy na świeży serwer Ubuntu 24.04, na którym zainstalowano już Docker Engine oraz wtyczkę Compose. Jeśli Docker jest nowym zagadnieniem, zacznij od podstaw Docker Compose na VPS, a następnie wróć do tego miejsca.

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

Plik Compose definiuje dwie usługi. core to sam SearXNG, a valkey to pamięć podręczna w RAM, używana do ograniczania liczby żądań (rate limiting) oraz przechowywania krótkotrwałego stanu. Montuje ona ./core-config/ w lokalizacji /etc/searxng/ wewnątrz kontenera, dzięki czemu cała konfiguracja znajduje się w tym jednym katalogu na hoście.

Teraz edytuj .env. Każda linia w dostarczonym przykładzie jest zakomentowana, dlatego kontener uruchamia się na porcie 8080 na każdym adresie. Odkomentuj i ustaw te trzy parametry.

SEARXNG_VERSION=latest
SEARXNG_HOST=127.0.0.1
SEARXNG_PORT=8080

SEARXNG_HOST=127.0.0.1 jest kluczowy. Sprawia on, że opublikowany port to 127.0.0.1:8080:8080, a nie domyślne 8080:8080, które Docker publikuje na każdym adresie. Dzięki temu kontener odpowiada tylko na adresie loopback, a Internet nie ma do niego bezpośredniego dostępu. Pominięcie tego kroku spowoduje wystawienie kontenera na świat w momencie startu, ponieważ opublikowany port Dockera jest wstawiany przed reguły firewalla. Warto zapoznać się z pełnym opisem tego zagrożenia: opublikowane porty Dockera omijają ufw.

SEARXNG_VERSION=latest jest dopuszczalne na etapie nauki. Na serwerze produkcyjnym należy przypiąć konkretną wersję (tag). Według stanu na październik 2026 tagi wydań są oparte na dacie i wyglądają jak 2026.10.4-d48c4b555. Dzięki temu aktualizacja wdrożenia następuje wtedy, gdy administrator podejmie taką decyzję, a nie w momencie zmiany w rejestrze. Ta sama dyscyplina sprawdza się w przypadku każdego innego długo działającego oprogramowania, dlatego własny przekaźnik RustDesk również korzysta z przypiętych tagów obrazów: automatyczna aktualizacja usługi zdalnego dostępu może spowodować awarię w najmniej odpowiednim momencie.

settings.yml: kluczowe elementy

Utwórz core-config/settings.yml przed pierwszym uruchomieniem. use_default_settings: true instruuje SearXNG, aby wczytał domyślne ustawienia dostarczone z oprogramowaniem, a następnie zastosował tylko te klucze, które zostały zdefiniowane. Dzięki temu plik pozostaje krótki i jest zgodny z nowymi wersjami po aktualizacji.

Najpierw wygeneruj klucz tajny, ponieważ jego wartość jest bezpośrednio wpisywana do pliku.

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 służy do podpisywania danych sesji i tokenów. Domyślną wartością jest ciąg znaków ultrasecretkey. Pozostawienie go w tej postaci umożliwia każdemu, kto zna tę wartość, sfałszowanie tokenów. Zmień go raz i nie modyfikuj później: zmiana klucza unieważni wszystkie zapisane preferencje użytkowników.

base_url musi zawierać publiczny adres HTTPS wraz z końcowym ukośnikiem. Jest to adres, który SearXNG umieszcza w generowanych linkach. Pozostawienie wartości localhost spowoduje, że linki do "następnej strony" w przeglądarce zdalnej będą wskazywać na maszynę użytkownika, co zakończy się błędem.

formats określa, jakie typy wyjścia będzie generować punkt końcowy web. json nie znajduje się na domyślnej liście, więc żądania JSON będą zwracać błąd 403, dopóki nie zostanie dodane. image_proxy: true kieruje miniatury wyników przez Twój serwer, dzięki czemu witryny hostujące te obrazy nie widzą adresów IP Twoich użytkowników.

valkey.url używa nazwy hosta valkey, ponieważ jest to nazwa usługi w pliku Compose. Compose umieszcza oba kontenery w jednej sieci, gdzie nazwy usług są rozpoznawane. Wskazanie na localhost spowoduje błąd limitera, ponieważ wewnątrz kontenera core adres localhost odnosi się do tego kontenera.

Klucz tajny znajduje się w zwykłym pliku tekstowym, dlatego należy zabezpieczyć również katalog, w którym się znajduje. chmod 750 /opt/searxng ogranicza dostęp innym użytkownikom hosta. Można również zaostrzyć uprawnienia core-config/settings.yml do trybu 600 bez negatywnego wpływu na działanie: punkt wejścia oficjalnego kontenera uruchamia się jako root i, przy pozostawieniu FORCE_OWNERSHIP na domyślnej wartości true, przekazuje zamontowany katalog konfiguracyjny użytkownikowi searxng wewnątrz kontenera przed uruchomieniem SearXNG. Dzięki temu plik pozostaje dla niego czytelny. Efektem ubocznym na hoście jest zmiana właściciela core-config/ na identyfikator użytkownika kontenera, dlatego edycja pliku po tym fakcie będzie wymagać użycia sudo.

Uruchom stos i sprawdź jego stan.

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

docker compose ps powinno wykazać, że oba kontenery są w stanie running. curl powinno odpowiedzieć HTTP/1.1 200 OK. Jeśli odpowiedź nie nadchodzi, sprawdź docker compose logs core, ponieważ błędy składni YAML w settings.yml są tam raportowane jako błędy parsowania ze wskazaniem numeru linii.

Umieszczenie za Nginx z TLS

Kontener nasłuchuje wyłącznie na interfejsie loopback, dlatego to Nginx zapewnia dostępność usługi oraz dodaje zabezpieczenie warstwy transportowej (TLS). Utwórz plik /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 wyświetla syntax is ok oraz test is successful przed przeładowaniem konfiguracji. Certbot nadpisuje ten sam plik, aby nasłuchiwać na porcie 443 z użyciem certyfikatu oraz dodaje przekierowanie z portu 80. Rekord DNS dla search.example.com musi już wskazywać na ten serwer, ponieważ urząd certyfikacji weryfikuje własność domeny poprzez pobranie pliku przez HTTP. Pełna instrukcja, włącznie z odnawianiem certyfikatów, znajduje się w przewodniku Certbot i Nginx dla Ubuntu 24.04.

Dwa nagłówki przekierowujące nie są opcjonalne. Bez X-Forwarded-For oraz X-Real-IP każde żądanie docierające do SearXNG zawiera adres proxy, przez co mechanizm ograniczania szybkości (rate limiter) widzi jednego klienta generującego cały ruch i nie jest w stanie odróżnić poszczególnych użytkowników.

Dlaczego skrypty i agenty wymagają API wyszukiwania w formacie JSON

Dzięki json w formats, ten sam punkt końcowy, który renderuje stronę, zwraca ustrukturyzowane dane.

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

Otrzymywany jest obiekt z tablicą results, gdzie każdy wpis zawiera url, title, content oraz silnik, który dostarczył wynik, wraz z answers, infoboxes oraz suggestions. Jest to wystarczające, aby zasilić narzędzie do podsumowań, weryfikator linków lub pętlę badawczą. Przekazanie tych wyników do modelu językowego jest krokiem bardziej złożonym, niż się wydaje, ponieważ wyniki wyszukiwania są niezaufanym tekstem, który może zawierać własne instrukcje, co szczegółowo omawia skierowanie agenta AI na własną instancję SearXNG.

Ma to znaczenie dla każdego rozwiązania opartego na agentach. Model językowy posiada datę odcięcia wiedzy, więc wymaga wyszukiwania na żywo, aby odpowiadać na pytania dotyczące teraźniejszości, a komercyjne API wyszukiwarek pobierają opłaty za zapytanie i stosują surowe limity. Lokalna instancja kosztuje tyle, co jeden kontener na serwerze, za który już płacisz, a zapytania nigdy go nie opuszczają. Jeśli integrujesz narzędzia z modelem, to samo rozumowanie przemawia za uruchamianiem serwerów MCP na VPS, gdzie narzędzie wyszukiwania jest zazwyczaj pierwszym dodawanym elementem.

Obowiązują dwie zasady korzystania z API. Utrzymuj instancję prywatną, więc powiąż stronę API z adresem pętli zwrotnej (loopback) lub siecią prywatną i zezwól na dostęp tylko własnym hostom; jest to takie samo podejście, jakiego samodzielnie hostowany lokalizator wymaga dla punktu końcowego, do którego telefon przesyła swoją pozycję. Następnie wysyłaj zapytania w sposób umiarkowany. SearXNG przekazuje żądanie do rzeczywistych wyszukiwarek, więc skrypt wykonujący sto zapytań na sekundę spowoduje zablokowanie serwera przez Google.

Ogranicznik oraz zmiany w instancji publicznej

Ogranicznik to mechanizm ochrony SearXNG przed botami. Monitoruje on nagłówki żądań, adresy oraz częstotliwość zapytań, odrzucając ruch wyglądający na zautomatyzowany. Do przechowywania tego stanu wymagany jest Valkey, dlatego plik Compose zawiera jego definicję.

W przypadku instancji prywatnej należy zachować limiter: false. Własne skrypty z definicji generują zautomatyzowany ruch, więc ogranicznik blokowałby dokładnie te wywołania JSON, dla których instancja została stworzona. Kontrolę dostępu należy powierzyć reverse proxy: parze allow i deny w pliku location nginx, uwierzytelnianiu HTTP Basic lub zaporze sieciowej dopuszczającej ruch tylko z określonych serwerów. Jeśli zachodzi potrzeba dostępu do instancji prywatnej z laptopa zmieniającego sieci, skonfigurowanie adresu v3 onion stanowi czwartą opcję, ponieważ Tor łączy się z tym samym portem loopback bez wystawiania usług do Internetu.

W przypadku udostępnienia instancji publicznie, należy włączyć oba przełączniki.

server:
  limiter: true
  public_instance: true

Bardziej precyzyjna kontrola znajduje się w core-config/limiter.toml, który kontener odczytuje z /etc/searxng/limiter.toml. Należy zdefiniować tylko te klucze, które mają zostać zmienione. W środowisku za proxy konieczne jest zadeklarowanie proxy, w przeciwnym razie ogranicznik potraktuje adres nginx jako pojedynczego, nadużywającego klienta.

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

[botdetection.ip_limit]
link_token = true

link_token = true powoduje, że SearXNG wydaje token pobierany wyłącznie przez rzeczywistą sesję przeglądarki, co zatrzymuje większość prostych skraperów. Należy oczekiwać, że instancja publiczna przyciągnie je w ciągu kilku dni. Należy również spodziewać się błędów silników, ponieważ im więcej ruchu jest przekazywane, tym szybciej zewnętrzne silniki zaczną zwracać CAPTCHA dla adresu serwera. Publiczna instancja SearXNG wymaga ciągłej obsługi. Instancja prywatna nie, dlatego znajduje się na większości krótkich list rzeczy, które warto hostować samodzielnie w 2026. Nie każdy wpis na tych listach to infrastruktura: przebudowa biblioteki Jellyfin na wzór wypożyczalni kaset z lat 90. to ten sam kontener za tym samym blokiem nginx, ukierunkowany na wieczorny relaks zamiast na pracę.

Dlaczego wyszukiwania nie zwracają wyników

Otwórz /stats na swojej instancji. Znajduje się tam lista wszystkich silników wraz z ich wskaźnikiem błędów oraz czasem odpowiedzi; jest to pierwsze miejsce, które należy sprawdzić, gdy wyniki wydają się niepełne.

Silnik oznaczony błędem "Access denied" lub "CAPTCHA" oznacza, że adres Twojego serwera został zablokowany. Jest to częste zjawisko w przypadku adresów z zakresów centrów danych, ponieważ wyszukiwarki zakładają, że należą one do skraperów. SearXNG zawiesza wtedy działanie takiego silnika na określony czas zamiast ponawiać próby, więc zablokowany silnik po prostu znika z wyników. Wyłącz go w settings.yml lub zaakceptuj jego brak. To nie jedyne rozwiązania, ponieważ niektóre blokady CAPTCHA można obejść w sposób trwały. Pozostałe silniki nadal odpowiadają. Kod 429 jest przypadkiem niejednoznacznym, ponieważ może pochodzić z Twojego własnego limitera lub od silnika nadrzędnego odrzucającego połączenie z Twojego serwera, a wpis w dzienniku pozwala ustalić, z którym z tych przypadków masz do czynienia przed przystąpieniem do zmiany ustawień.

Jeśli wszystkie silniki zawodzą jednocześnie, kontener nie ma działającego rozpoznawania nazw dla ruchu wychodzącego lub nie ma trasy do Internetu. Przetestuj to z wnętrza kontenera.

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

Żaden element systemu nie poinformuje Cię o awarii tego sprawdzenia, dlatego uruchom je przez cron i pozwól, aby błąd wysłał powiadomienie na Twój telefon z Twojego własnego serwera ntfy, zamiast czekać, aż zauważysz, że wyniki stały się niepełne.

FAQ

Czy SearXNG zapewnia anonimowość wyszukiwania?

SearXNG ukrywa tożsamość użytkownika przed wyszukiwarkami, ponieważ otrzymują one żądania z serwera, a nie bezpośrednio z przeglądarki. Rozwiązanie to nie ukrywa jednak zapytań przed samym serwerem, ani nie ukrywa serwera przed wyszukiwarkami. W przypadku instancji jednoosobowej cały ruch z danego adresu IP jest przypisany do jednego użytkownika, co czyni ten adres identyfikatorem. Ruch między przeglądarką a instancją jest chroniony certyfikatem TLS. Szczegółowe informacje na temat poziomu prywatności wobec dostawcy usług internetowych (ISP), operatora publicznej instancji oraz samych wyszukiwarek znajdują się w co faktycznie ukrywa SearXNG.

Dlaczego żądanie JSON zwraca błąd 403 Forbidden?

Istnieją dwie przyczyny, obie wynikają z konfiguracji. Albo json brakuje na liście formats w sekcji search: w pliku settings.yml (co jest ustawieniem domyślnym), albo aktywny jest ogranicznik (limiter), który zaklasyfikował skrypt jako bota. Należy dodać format, zrestartować usługę za pomocą docker compose restart core i ponowić próbę. Jeśli błąd nadal występuje, należy ustawić limiter: false i zarządzać dostępem na poziomie reverse proxy.

Czy kontener Valkey jest potrzebny, jeśli ogranicznik jest wyłączony?

Należy pozostawić go uruchomionego. SearXNG działa bez niego, ale włączenie ogranicznika w późniejszym czasie będzie niemożliwe, a kontener przechowuje również inne krótkotrwałe dane stanu. Kontener jest niewielki i przechowuje tylko dane w pamięci podręcznej, więc jego usunięcie przynosi znikome oszczędności, a pozbawia użytkownika dodatkowych funkcji.

Jak zaktualizować SearXNG?

Należy wykonać docker compose pull, a następnie docker compose up -d w katalogu /opt/searxng. Docker Compose odtworzy każdy kontener, którego obraz uległ zmianie, pozostawiając katalog core-config/ nienaruszony, dzięki czemu settings.yml zostanie zachowany. Ponieważ use_default_settings: true scala klucze użytkownika z domyślnymi ustawieniami, nowe opcje dodane w aktualizacjach otrzymują rozsądne wartości domyślne zamiast powodować błędy w pliku.

Czy z jednej instancji może korzystać kilka osób?

Tak, jest to przypadek, w którym należy włączyć ogranicznik i skonfigurować public_instance: true. Preferencje są przechowywane w przeglądarce każdego użytkownika, więc nie ma potrzeby zarządzania kontami. Przez tydzień po udostępnieniu instancji należy monitorować /stats, ponieważ wyszukiwarki mogą zacząć odrzucać żądania z serwera na długo przed tym, zanim zauważalne staną się braki w wynikach wyszukiwania.

Czy ten artykuł był przydatny?