Cara Self-Host SearXNG untuk Pencarian Privat
Jalankan SearXNG di VPS sendiri dengan Docker Compose. Panduan ini mencakup settings.yml, limiter, nginx dengan TLS, dan API pencarian JSON untuk skrip Anda.
Yang Anda bangun
Self-hosting SearXNG memberi Anda mesin pencari privat yang berjalan di server milik Anda sendiri. SearXNG adalah metasearch engine: aplikasi ini menerima kueri Anda, mengirimkannya ke mesin pencari lain seperti Google, Bing, DuckDuckGo, dan Wikipedia, lalu menggabungkan hasilnya menjadi satu halaman hasil. Tidak ada profil yang dibuat dan tidak ada cookie pelacakan yang dipasang, karena hanya mesin milik Anda yang menyimpan kueri tersebut. Jika Anda menemukan panduan lama untuk proyek yang hanya disebut Searx, itulah proyek asal fork ini, dan proyek tersebut tidak memiliki commit sejak 2023. Karena itu, periksa status keduanya sebelum mengikuti salah satunya.
Stack ini sederhana. Dua container, satu file pengaturan, dan satu reverse proxy. Stack ini dapat berjalan dengan baik pada VPS kecil, tetapi hal itu tidak berlaku untuk setiap service self-hosted: pustaka foto yang dibandingkan dalam PhotoPrism dan Immich menetapkan kebutuhan RAM minimumnya berdasarkan indexer, bukan aplikasi web. Keputusan utamanya adalah apakah instance tersebut bersifat privat, yang berarti hanya Anda dan skrip milik Anda yang dapat mengaksesnya, atau publik, yang berarti siapa pun di internet dapat menggunakannya untuk melakukan kueri. Pilihan ini mengubah pengaturan keamanan, jadi tentukan sebelum mengetik apa pun. Jawaban defaultnya adalah privat.
Ada alasan kedua untuk menjalankan instance ini. Instance SearXNG menyediakan antarmuka JSON, sehingga skrip atau agen AI yang Anda tulis dapat menggunakan search API milik Anda sendiri, tanpa key, biaya per kueri, atau email tentang batas kuota.
Instal SearXNG dengan Docker Compose
Proyek ini menerbitkan image container dan file Compose. Tarik keduanya ke server Ubuntu 24.04 baru yang sudah memiliki Docker Engine dan plugin Compose. Jika Docker masih baru bagi Anda, mulai dengan Dasar-dasar Docker Compose pada VPS, lalu kembali ke sini.
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 .envFile Compose mendefinisikan dua service. core adalah SearXNG, sedangkan valkey adalah penyimpanan data dalam memori yang digunakan untuk rate limiting dan state berumur pendek. File ini me-mount ./core-config/ ke /etc/searxng/ di dalam container, sehingga semua konfigurasi yang Anda buat berada dalam satu direktori tersebut di host.
Sekarang edit .env. Setiap baris dalam contoh yang disertakan diberi komentar. Karena itu, container berjalan pada port 8080 di semua alamat. Hapus tanda komentar dan tetapkan ketiga nilai berikut.
SEARXNG_VERSION=latest
SEARXNG_HOST=127.0.0.1
SEARXNG_PORT=8080SEARXNG_HOST=127.0.0.1 adalah bagian yang penting. Nilai ini membuat port yang dipublikasikan menjadi 127.0.0.1:8080:8080, bukan [::]:8080:8080, sehingga container hanya menjawab pada alamat loopback dan Internet tidak dapat mengaksesnya secara langsung. Jika langkah ini dilewati, container langsung terekspos saat start karena port Docker yang dipublikasikan dimasukkan sebelum aturan firewall Anda. Baca penjelasan lengkap tentang jebakan ini: port Docker yang dipublikasikan melewati ufw.
SEARXNG_VERSION=latest cukup digunakan selama Anda masih mempelajarinya. Pada server yang penting bagi Anda, tetapkan tag secara eksplisit. Per Juli 2026, tag rilis menggunakan tanggal dan berbentuk 2026.3.25-541c6c3cb. Dengan demikian, deployment yang menggunakan tag tetap akan di-upgrade saat Anda memutuskan, bukan saat registry berubah tanpa kendali Anda. Disiplin yang sama bermanfaat untuk komponen lain yang harus berjalan dalam jangka panjang di server. Karena itu, relay RustDesk yang di-host sendiri juga menetapkan tag image: upgrade tanpa pengawasan pada service akses jarak jauh dapat muncul pada saat yang paling buruk.
settings.yml: bagian yang penting
Buat core-config/settings.yml sebelum start pertama. use_default_settings: true memberi tahu SearXNG untuk memuat default bawaan yang disertakan, lalu hanya menerapkan key yang Anda tulis. Dengan demikian, file Anda tetap singkat dan tetap berfungsi setelah upgrade yang menambahkan opsi baru.
Buat secret terlebih dahulu karena nilainya akan langsung dimasukkan ke file.
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 menandatangani data session dan token. Default bawaan adalah string literal ultrasecretkey. Jika dibiarkan, siapa pun yang mengetahui default tersebut dapat memalsukan token itu. Ganti sekali, lalu jangan ubah lagi: perubahan setelahnya akan menghapus semua preferensi yang tersimpan.
base_url harus berupa alamat HTTPS publik dengan trailing slash. SearXNG menulis alamat ini ke dalam link yang direndernya. Jika tetap mengarah ke localhost, link "next page" pada browser remote akan mengarah ke mesin milik pembaca sendiri dan gagal.
formats menentukan jenis output yang akan dihasilkan endpoint web. json tidak termasuk dalam daftar default, sehingga request JSON mengembalikan 403 sampai Anda menambahkannya. image_proxy: true merutekan thumbnail hasil melalui server Anda, sehingga situs yang meng-host gambar tersebut tidak pernah melihat alamat pengunjung Anda.
valkey.url menggunakan hostname valkey karena itulah nama service dalam file Compose. Compose menempatkan kedua container pada satu network sehingga nama service dapat di-resolve. Arahkan ke localhost dan limiter akan gagal karena di dalam container core, localhost adalah container tersebut.
Secret disimpan dalam file biasa. Karena itu, lindungi direktori di sekitarnya, bukan file itu sendiri. chmod 750 /opt/searxng mencegah user lain pada host mengaksesnya. Jangan memperketat core-config/settings.yml ke mode 600: container berjalan sebagai user non-root miliknya sendiri, dan file yang tidak dapat dibacanya akan membuat SearXNG gagal start sepenuhnya.
Start stack tersebut lalu periksa hasilnya.
cd /opt/searxng
docker compose up -d
docker compose ps
curl -I http://127.0.0.1:8080/docker compose ps seharusnya menampilkan kedua container dengan state running. curl seharusnya merespons HTTP/1.1 200 OK. Jika tidak memberikan respons, baca docker compose logs core karena kesalahan YAML dalam settings.yml akan muncul di sana sebagai parse error yang menyebutkan nomor baris.
Tempatkan di belakang nginx dengan TLS
Container hanya mendengarkan pada loopback. Karena itu, nginx membuatnya dapat dijangkau sekaligus menambahkan keamanan lapisan transport (TLS). Tulis /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 mencetak syntax is ok dan test is successful sebelum Anda memuat ulang konfigurasi. Certbot menulis ulang file yang sama agar mendengarkan pada 443 dengan sertifikat dan menambahkan pengalihan dari port 80. Catatan DNS untuk search.example.com harus sudah mengarah ke server ini karena otoritas sertifikat membuktikan kepemilikan dengan mengambil sebuah file melalui HTTP. Panduan lengkap, termasuk perpanjangan sertifikat, tersedia di panduan Certbot dan nginx untuk Ubuntu 24.04.
Kedua header penerusan tersebut bukan sekadar dekorasi. Tanpa X-Forwarded-For dan X-Real-IP, setiap permintaan yang tiba di SearXNG membawa alamat proxy. Akibatnya, pembatas laju menganggap satu klien menghasilkan seluruh trafik dan tidak dapat membedakan para pengunjung.
Mengapa skrip dan agen memerlukan API pencarian JSON
Dengan json dalam formats, endpoint yang sama untuk merender halaman juga mengembalikan data terstruktur.
curl -s 'http://127.0.0.1:8080/search?q=wireguard+mtu&format=json' \
| jq -r '.results[0:5][] | .url'Anda menerima sebuah objek dengan array results. Setiap entri memuat url, title, content, dan engine yang menyediakannya, serta answers, infoboxes, dan suggestions. Data tersebut cukup untuk memasok summariser, pemeriksa tautan, atau loop riset. Meneruskan hasil tersebut ke model bahasa merupakan langkah yang dampaknya lebih besar daripada yang terlihat, karena hasil pencarian adalah teks yang tidak tepercaya dan dapat membawa instruksi sendiri. Hal ini dibahas secara rinci dalam mengarahkan agen AI ke instance SearXNG Anda.
Hal ini penting untuk segala sesuatu yang berbentuk agen. Model bahasa memiliki batas waktu data pelatihan, sehingga memerlukan pencarian langsung untuk menjawab pertanyaan tentang kondisi saat ini. Selain itu, API pencarian komersial mengenakan biaya per kueri dan menerapkan rate limit yang ketat. Instance lokal hanya memerlukan satu container pada server yang sudah Anda bayar, dan kueri tidak pernah meninggalkan server tersebut. Jika Anda menghubungkan tools ke model, alasan yang sama mendorong menjalankan server MCP pada VPS, karena search tool biasanya menjadi tools pertama yang ditambahkan orang.
Ada dua aturan untuk penggunaan API. Jaga agar instance tetap privat. Bind sisi API ke alamat loopback atau jaringan privat, lalu izinkan hanya host Anda sendiri yang mengaksesnya. Setelah itu, kirim kueri secara wajar. SearXNG meneruskan permintaan Anda ke engine pencarian sebenarnya, sehingga skrip yang menjalankan seratus kueri per detik dapat membuat Google memblokir server Anda.
Limiter dan perubahan untuk instance publik
Limiter adalah pertahanan bot SearXNG. Limiter memantau header permintaan, alamat, dan laju permintaan, lalu menjatuhkan trafik yang terlihat otomatis. Limiter memerlukan Valkey untuk menyimpan status tersebut. Karena itu, Valkey disertakan dalam file Compose.
Pada instance privat, pertahankan limiter: false. Skrip Anda sendiri secara definisi merupakan trafik otomatis. Karena itu, limiter akan memblokir panggilan JSON yang menjadi tujuan instance tersebut. Kendali akses merupakan tugas reverse proxy: gunakan pasangan allow dan deny dalam location nginx, autentikasi dasar HTTP, atau firewall yang hanya mengizinkan server lain milik Anda. Jika Anda perlu mengakses instance privat dari laptop yang berpindah-pindah jaringan, letakkan alamat onion v3 di depannya sebagai opsi keempat. tor terhubung ke port loopback yang sama tanpa mengekspos apa pun yang baru ke Internet.
Jika Anda memublikasikan instance untuk orang lain, aktifkan kedua switch.
server:
limiter: true
public_instance: truePengaturan yang lebih terperinci terdapat dalam core-config/limiter.toml, yang dibaca container dari /etc/searxng/limiter.toml. Tulis hanya kunci yang ingin Anda ubah. Jika berada di belakang proxy, Anda harus mendeklarasikan proxy tersebut. Jika tidak, limiter akan menganggap alamat nginx Anda sebagai satu-satunya klien yang melakukan penyalahgunaan.
[botdetection]
trusted_proxies = [
'127.0.0.0/8',
'::1',
]
[botdetection.ip_limit]
link_token = truelink_token = true membuat SearXNG mengeluarkan token yang hanya akan diambil oleh sesi browser sungguhan. Hal ini menghentikan sebagian besar scraper sederhana. Instance publik biasanya akan mulai menarik scraper dalam hitungan hari. Perkirakan juga munculnya error engine. Semakin banyak trafik yang Anda teruskan, semakin cepat engine upstream mulai mengirim CAPTCHA ke alamat server Anda. Instance SearXNG publik memerlukan pemeliharaan berkelanjutan. Instance privat tidak memerlukannya. Karena itu, instance privat biasanya termasuk dalam daftar singkat hal-hal yang layak di-self-host pada 2026. Tidak semua entri dalam daftar tersebut merupakan infrastruktur: membangun ulang library Jellyfin sebagai toko rental tahun 90-an yang dapat dijelajahi menggunakan container yang sama di balik blok nginx yang sama, tetapi diarahkan pada suasana malam, bukan alur kerja.
Mengapa pencarian tidak menghasilkan apa pun
Buka /stats pada instance Anda. Bagian ini mencantumkan setiap engine beserta tingkat error dan waktu responsnya. Ini adalah tempat pertama yang harus diperiksa ketika hasil pencarian terlihat sedikit.
Engine yang menampilkan error "Access denied" atau "CAPTCHA" telah memblokir alamat server Anda. Hal ini umum terjadi pada alamat dalam rentang data center karena mesin pencari menganggap alamat tersebut milik scraper. SearXNG kemudian menangguhkan engine yang gagal selama jangka waktu tertentu, bukan langsung mencobanya lagi. Akibatnya, satu engine yang diblokir diam-diam tidak lagi menyumbang hasil. Nonaktifkan engine tersebut di settings.yml atau terima berkurangnya hasil. Namun, hanya itu bukan satu-satunya pilihan, karena sebagian pemblokiran CAPTCHA dapat diperbaiki secara permanen setelah restart. Engine lainnya tetap memberikan respons. Kode 429 merupakan kasus yang ambigu karena dapat berasal dari limiter Anda sendiri atau dari engine upstream yang menolak server Anda. Baris log menunjukkan sumbernya sebelum Anda mulai mengubah pengaturan.
Jika semua engine gagal secara bersamaan, container tidak memiliki resolusi nama outbound yang berfungsi atau tidak memiliki rute ke Internet. Uji kondisi tersebut dari dalam container.
docker compose exec core wget -qO- https://duckduckgo.com > /dev/null && echo okTidak ada komponen pada server yang akan memberi tahu Anda ketika pemeriksaan tersebut mulai gagal. Karena itu, jalankan pemeriksaan dari cron dan biarkan kegagalan mengirimkan alert ke ponsel Anda melalui server ntfy milik Anda sendiri, bukan menunggu hingga Anda menyadari bahwa hasil pencarian mulai sedikit.
FAQ
Apakah SearXNG membuat pencarian saya anonim?
SearXNG menyembunyikan identitas Anda dari engine yang dikuerinya karena engine tersebut melihat server Anda yang mengirimkan permintaan, bukan browser Anda. Namun, SearXNG tidak menyembunyikan kueri dari server Anda dan tidak menyembunyikan server Anda dari engine tersebut. Pada instance untuk satu pengguna, seluruh trafik dari alamat tersebut berasal dari Anda, sehingga alamat itu sendiri menjadi pengenal. Trafik antara browser dan instance Anda dilindungi oleh sertifikat TLS. Dampaknya terhadap ISP Anda, operator instance publik, dan engine itu sendiri dijelaskan dalam apa yang sebenarnya disembunyikan SearXNG.
Mengapa permintaan JSON mengembalikan 403 Forbidden?
Ada dua penyebab, dan keduanya terkait konfigurasi. json mungkin tidak ada dalam daftar formats di bawah search: dalam settings.yml, yang merupakan kondisi default, atau limiter aktif dan mengklasifikasikan skrip Anda sebagai bot. Tambahkan format tersebut terlebih dahulu, lalu restart dengan docker compose restart core dan coba lagi. Jika masih gagal, tetapkan limiter: false dan kendalikan akses pada reverse proxy.
Apakah saya memerlukan container Valkey jika limiter tetap dinonaktifkan?
Biarkan container tersebut tetap berjalan. SearXNG dapat berfungsi tanpanya, tetapi limiter tidak dapat diaktifkan nanti tanpa container tersebut, dan container itu juga menyimpan state lain yang berumur pendek. Container ini berukuran kecil dan hanya menyimpan data cache, sehingga menghapusnya hanya menghemat sedikit ruang dan menghilangkan opsi bagi Anda.
Bagaimana cara memperbarui SearXNG?
Jalankan docker compose pull lalu docker compose up -d dalam /opt/searxng. Compose akan membuat ulang setiap container yang image-nya berubah dan membiarkan direktori core-config/ tetap utuh, sehingga settings.yml tetap tersedia. Karena use_default_settings: true menggabungkan key Anda dengan default yang disertakan, opsi yang ditambahkan upstream akan memperoleh nilai yang sesuai tanpa merusak file.
Apakah beberapa orang dapat menggunakan satu instance bersama-sama?
Ya. Untuk kondisi tersebut, aktifkan limiter dan tetapkan public_instance: true. Preferensi disimpan di browser masing-masing pengunjung, sehingga tidak ada akun yang perlu dikelola. Pantau /stats selama seminggu setelah instance dibuka untuk akses publik karena engine upstream mulai menolak server Anda jauh sebelum Anda menyadari bahwa hasil pencarian berkurang.