Własna wyszukiwarka SearXNG przez Docker Compose
Instrukcja konfiguracji SearXNG na własnym serwerze VPS. Dowiedz się jak poprawnie przygotować plik settings.yml, skonfigurować Nginx z TLS oraz wykorzystać API do zapytań.
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 i Wikipedia, a następnie łączy wyniki na jednej stronie. Nie tworzy profilu użytkownika i nie ustawia plików cookie śledzących, ponieważ jedynym urządzeniem przechowującym zapytanie jest Twój serwer. Jeśli natrafiłeś na starsze poradniki dotyczące projektu o nazwie Searx, wiedz, że jest to projekt, z którego wywodzi się obecny, a w którym nie wprowadzono żadnych zmian od 2023 roku, dlatego sprawdź stan obu projektów przed wyborem instrukcji.
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 hostowanego samodzielnie oprogramowania: biblioteki zdjęć porównane w PhotoPrism kontra Immich ustalają minimalne zapotrzebowanie na pamięć RAM na podstawie indeksatora, a nie samej aplikacji webowej. Kluczową decyzją jest to, czy instancja ma być prywatna, co oznacza, że dostęp masz tylko Ty i Twoje skrypty, czy publiczna, co pozwala każdemu użytkownikowi Internetu na wysyłanie zapytań. Wybór ten wpływa na ustawienia bezpieczeństwa, więc podejmij go przed rozpoczęciem konfiguracji. Domyślnym ustawieniem jest tryb prywatny.
Istnieje drugi powód, dla którego warto uruchomić własną instancję. SearXNG obsługuje format JSON, dzięki czemu każdy skrypt lub agent AI zyskuje dostęp do własnego API wyszukiwania, bez konieczności używania kluczy, opłat za zapytanie czy limitów narzucanych przez dostawców.
Instalacja SearXNG przy użyciu Docker Compose
Projekt udostępnia obraz kontenera oraz plik Compose. Pobierz oba elementy na świeży serwer z systemem 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 .envPlik Compose definiuje dwie usługi. core to sam SearXNG, a valkey to magazyn danych w pamięci RAM, używany do ograniczania liczby żądań (rate limiting) oraz przechowywania krótkotrwałego stanu. Montuje on ./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 wszystkich adresach. Odkomentuj i ustaw te trzy parametry.
SEARXNG_VERSION=latest
SEARXNG_HOST=127.0.0.1
SEARXNG_PORT=8080SEARXNG_HOST=127.0.0.1 jest kluczowy. Sprawia on, że opublikowany port to 127.0.0.1:8080:8080 zamiast [::]:8080:8080, dzięki czemu kontener odpowiada tylko na adresie loopback i nie jest bezpośrednio dostępny z Internetu. Pomiń ten krok, a kontener zostanie wystawiony w momencie uruchomienia, ponieważ opublikowany port Dockera jest wstawiany przed reguły firewalla. Warto zapoznać się z tym zagrożeniem w całości: opublikowane porty Dockera omijają ufw.
SEARXNG_VERSION=latest jest dopuszczalne podczas nauki. Na serwerze produkcyjnym przypnij konkretną wersję (tag). Według stanu na lipiec 2026 tagi wydań są oparte na dacie i wyglądają jak 2026.3.25-541c6c3cb, więc przypięte wdrożenie aktualizuje się wtedy, gdy zdecydujesz, a nie wtedy, gdy zmieni się obraz w rejestrze. Ta sama dyscyplina opłaca 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 potrafi wystąpić w najmniej odpowiednim momencie.
settings.yml: istotne elementy
Utwórz core-config/settings.yml przed pierwszym uruchomieniem. use_default_settings: true instruuje SearXNG, aby wczytał dostarczone domyślne ustawienia, a następnie zastosował tylko wskazane klucze. Dzięki temu plik pozostaje krótki i jest zgodny z nowymi wersjami oprogramowania, które wprowadzają dodatkowe opcje.
Najpierw wygeneruj klucz tajny, ponieważ wartość ta trafia bezpośrednio do pliku.
openssl rand -hex 32use_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
- jsonsecret_key służy do podpisywania danych sesji i tokenów. Domyślną wartością jest ciąg znaków ultrasecretkey. Pozostawienie go oznacza, że każdy, kto zna tę wartość, może sfałszować tokeny. Zmień go raz i nie modyfikuj później: zmiana spowoduje utratę wszystkich zapisanych preferencji użytkowników.
base_url musi być publicznym adresem HTTPS, wraz z końcowym ukośnikiem. Jest to adres, który SearXNG umieszcza w generowanych linkach. Pozostawienie wartości wskazującej na 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 danych wyjściowych będzie generować endpoint webowy. 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 przesyła miniatury wyników przez Twój serwer, dzięki czemu witryny hostujące te obrazy nigdy nie poznają 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, w której nazwy usług są rozpoznawane. Wskazanie na localhost spowoduje błąd limitera, ponieważ wewnątrz kontenera core adres localhost odnosi się do samego kontenera.
Klucz tajny znajduje się w zwykłym pliku tekstowym, dlatego należy zabezpieczyć katalog, w którym się znajduje, zamiast samego pliku. chmod 750 /opt/searxng ogranicza dostęp innym użytkownikom hosta. Nie należy zaostrzać uprawnień core-config/settings.yml do trybu 600: kontener działa jako własny użytkownik bez uprawnień, a brak możliwości odczytu pliku uniemożliwi uruchomienie SearXNG.
Uruchom stos i sprawdź jego działanie.
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 nie otrzymasz odpowiedzi, sprawdź docker compose logs core, ponieważ błędy składni YAML w settings.yml pojawiają się tam jako błędy parsowania wskazujące konkretną linię.
Umieszczenie za nginx z obsługą TLS
Kontener nasłuchuje wyłącznie na interfejsie loopback, dlatego to nginx zapewnia dostępność usługi oraz szyfrowanie 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.comnginx -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 tym proces odnawiania certyfikatów, znajduje się w przewodniku Certbot i nginx dla Ubuntu 24.04.
Dwa nagłówki przekazujące informacje 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 liczby żądań (rate limiter) widzi cały ruch jako pochodzący od jednego klienta 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. Kwestię tę 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 potrzebuje wyszukiwania na żywo, aby odpowiadać na pytania dotyczące teraźniejszości, a komercyjne API wyszukiwarek pobierają opłaty za zapytanie i nakładają surowe limity. Lokalna instancja to koszt jednego kontenera na serwerze, za który już płacisz, a zapytania nigdy go nie opuszczają. Jeśli integrujesz narzędzia z modelem, ta sama logika 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 stronę API z adresem pętli zwrotnej (loopback) lub siecią prywatną, aby dostęp miały tylko Twoje własne hosty. Następnie wysyłaj zapytania w sposób umiarkowany. SearXNG przekazuje żądanie do rzeczywistych wyszukiwarek, więc skrypt wykonujący sto zapytań na sekundę naraża Twój serwer na zablokowanie przez Google.
Limiter oraz zmiany w przypadku instancji publicznej
Limiter stanowi mechanizm ochrony SearXNG przed botami. Monitoruje on nagłówki żądań, adresy oraz częstotliwość zapytań, odrzucając ruch noszący znamiona automatyzacji. 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ą ruch automatyczny, więc limiter 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 serwera 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 lokalnym bez wystawiania usług do Internetu.
W przypadku udostępnienia instancji publicznie, należy włączyć oba przełączniki.
server:
limiter: true
public_instance: trueBardziej szczegółowa konfiguracja znajduje się w core-config/limiter.toml, który kontener odczytuje z /etc/searxng/limiter.toml. Należy w nim umieścić tylko te klucze, które wymagają zmiany. W środowisku za proxy konieczne jest zadeklarowanie proxy, w przeciwnym razie limiter potraktuje adres serwera nginx jako pojedynczego, nadużywającego zasobów klienta.
[botdetection]
trusted_proxies = [
'127.0.0.0/8',
'::1',
]
[botdetection.ip_limit]
link_token = truelink_token = true sprawia, że SearXNG generuje token pobierany wyłącznie przez 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ększy ruch jest przekazywany, tym szybciej zewnętrzne wyszukiwarki zaczną zwracać CAPTCHA dla adresu IP serwera. Publiczna instancja SearXNG wymaga ciągłej obsługi. Instancja prywatna nie, dlatego znajduje się na większości krótkich list rzeczy wartych samodzielnego hostowania w 2026. Nie każdy wpis na takich listach dotyczy infrastruktury: 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, a nie na optymalizację pracy.
Dlaczego wyszukiwania nie zwracają wyników
Otwórz /stats w swojej instancji. Znajduje się tam lista wszystkich silników wraz ze wskaźnikiem błędów i czasem odpowiedzi; jest to pierwsze miejsce, które należy sprawdzić, gdy wyniki wyszukiwania są niepełne.
Silnik wyświetlający błędy „Access denied” lub „CAPTCHA” zablokował adres serwera. Jest to częste w przypadku adresów z zakresów centrów danych, ponieważ wyszukiwarki zakładają, że należą one do scraperów. SearXNG zawiesza następnie taki silnik na określony czas zamiast ponawiać żądania. Zablokowany silnik przestaje więc być uwzględniany w wynikach bez wyraźnego komunikatu. Należy wyłączyć go w settings.yml albo zaakceptować brak tego źródła. Nie są to jedyne możliwości, ponieważ niektóre blokady CAPTCHA można usunąć w sposób zachowywany po restarcie. Pozostałe silniki nadal odpowiadają. Kod 429 jest przypadkiem niejednoznacznym, ponieważ może pochodzić z własnego limitera albo z silnika upstream odrzucającego żądania z serwera. Przed zmianą ustawień należy sprawdzić wiersz dziennika wskazujący, z którym z tych dwóch przypadków ma się do czynienia.
Jeśli wszystkie silniki zawodzą jednocześnie, kontener nie ma działającego wychodzącego rozpoznawania nazw lub trasy do Internetu. Przetestuj to z wnętrza kontenera.
docker compose exec core wget -qO- https://duckduckgo.com > /dev/null && echo okŻaden mechanizm wewnątrz systemu nie powiadomi Cię, gdy ten test zacznie kończyć się niepowodzeniem, dlatego uruchom go przez cron i pozwól, aby błąd wysłał powiadomienie na Twój telefon z własnego serwera ntfy, zamiast czekać, aż zauważysz, że wyniki stały się niepełne.
FAQ
Czy SearXNG zapewnia anonimowość wyszukiwania?
Ukrywa tożsamość użytkownika przed wyszukiwarkami, ponieważ otrzymują one żądania z serwera, a nie z przeglądarki. Nie ukrywa jednak zapytania przed serwerem, ani serwera przed wyszukiwarkami. W przypadku instancji dla jednego użytkownika cały ruch z danego adresu IP jest przypisany do niego, więc sam adres staje się identyfikatorem. Ruch między przeglądarką a instancją jest chroniony certyfikatem TLS. Kwestia ochrony przed dostawcą usług internetowych (ISP), operatorem publicznej instancji oraz samymi wyszukiwarkami została omówiona 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 stanem domyślnym, albo włączony jest ogranicznik (limiter), który zaklasyfikował skrypt jako bota. Należy dodać format, zrestartować usługę za pomocą docker compose restart core i spróbować ponownie. Jeśli problem nadal występuje, należy ustawić limiter: false i kontrolować dostęp 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 stany. Kontener jest niewielki i przechowuje tylko dane w pamięci podręcznej, więc jego usunięcie przynosi znikome oszczędności, a pozbawia możliwości konfiguracji.
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 zachowane. Ponieważ use_default_settings: true scala klucze użytkownika z domyślnymi ustawieniami, nowe opcje dodane w aktualizacjach otrzymują rozsądne wartości 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 ustawić public_instance: true. Preferencje są przechowywane w przeglądarce każdego użytkownika, więc nie ma potrzeby zarządzania kontami. Należy monitorować /stats przez tydzień po udostępnieniu instancji, ponieważ wyszukiwarki mogą zacząć odrzucać żądania z serwera na długo przed tym, jak zauważalne stanie się ograniczenie wyników.