SearXNG self-host করুন: নিজের private search engine
Docker Compose দিয়ে VPS-এ SearXNG চালান: settings.yml, limiter, TLS-সহ nginx এবং আপনার script থেকে ব্যবহারযোগ্য JSON search API কনফিগার করার ধাপ দেখুন।
আপনি যা তৈরি করছেন
নিজের server-এ চালানো একটি private search engine পেতে SearXNG self-host করুন। SearXNG একটি metasearch engine: এটি আপনার query নিয়ে Google, Bing, DuckDuckGo এবং Wikipedia-এর মতো অন্য engine-এ পাঠায়, তারপর পাওয়া ফল একত্র করে একটি result page দেখায়। কোনো profile তৈরি হয় না এবং কোনো tracking cookie সেট করা হয় না, কারণ আপনার query সংরক্ষণ করে এমন একমাত্র machine হলো আপনার নিজেরটি। শুধু Searx নামে পরিচিত পুরোনো guide পেয়ে থাকলে সেটিই সেই project, যেখান থেকে এই project fork করা হয়েছে। 2023 সালের September থেকে এটি unmaintained; তখন এর নিজস্ব repository ঘোষণা করেছিল যে Searx আর maintained নয়। এরপর 2026 সালের May-তে documentation note হিসেবে করা একমাত্র commit-ও এই অবস্থার পরিবর্তন করেনি। তাই কোনো একটি অনুসরণ করার আগে দুটির অবস্থাই পরীক্ষা করুন।
এই stack ছোট। দুটি container, একটি settings file এবং একটি reverse proxy। এটি একটি ছোট VPS-এ সহজেই চলবে। তবে প্রতিটি self-hosted service-এর ক্ষেত্রে এমনটি নয়: PhotoPrism এবং Immich-এর তুলনায় photo library-গুলোর RAM-এর ন্যূনতম চাহিদা web app নয়, indexer নির্ধারণ করে। আসল সিদ্ধান্ত হলো instance-টি private হবে কি না। Private হলে শুধু আপনি এবং আপনার নিজের script এতে পৌঁছাতে পারবে। Public হলে Internet-এর যে কেউ query পাঠাতে পারবে। এই পছন্দ security setting পরিবর্তন করে। তাই কিছু type করার আগে সিদ্ধান্ত নিন। Default হিসেবে private বেছে নিন।
এটি চালানোর দ্বিতীয় একটি কারণ আছে। একটি SearXNG instance JSON ব্যবহার করে। তাই আপনার লেখা যেকোনো script বা AI agent এমন একটি search API পায়, যার নিয়ন্ত্রণ আপনার নিজের কাছে থাকে। কোনো key লাগে না, প্রতি query-র জন্য billing হয় না এবং quota-সংক্রান্ত mail আসে না।
Docker Compose দিয়ে SearXNG ইনস্টল করুন
প্রকল্পটি একটি container image এবং একটি Compose file প্রকাশ করে। আগে থেকেই Docker Engine এবং Compose plugin ইনস্টল করা একটি নতুন Ubuntu 24.04 server-এ দুটিই নিয়ে আসুন। Docker আপনার জন্য নতুন হলে VPS-এ Docker Compose-এর প্রাথমিক ধারণা দিয়ে শুরু করুন, তারপর এখানে ফিরে আসুন।
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 .envCompose file-এ দুটি service নির্ধারিত আছে। core হলো SearXNG নিজেই, আর valkey হলো rate limiting এবং স্বল্পস্থায়ী state-এর জন্য ব্যবহৃত একটি in-memory data store। এটি container-এর ভেতরে /etc/searxng/ হিসেবে ./core-config/ mount করে। তাই আপনি যে সব configuration সেট করেন, সেগুলো host-এর ওই একটি directory-তেই থাকে।
এখন .env সম্পাদনা করুন। সরবরাহ করা উদাহরণের প্রতিটি line comment করা আছে। এ কারণেই container-টি প্রতিটি address-এ port 8080-এ start হয়। এই তিনটি line uncomment করে মান নির্ধারণ করুন।
SEARXNG_VERSION=latest
SEARXNG_HOST=127.0.0.1
SEARXNG_PORT=8080SEARXNG_HOST=127.0.0.1-ই গুরুত্বপূর্ণ। এটি published port-কে একটি bare 8080:8080-এর বদলে 127.0.0.1:8080:8080 হিসেবে নির্ধারণ করে। Docker bare 8080:8080-কে প্রতিটি address-এ publish করে। ফলে container-টি শুধু loopback address-এ সাড়া দেয় এবং Internet থেকে সরাসরি এতে পৌঁছানো যায় না। এই ধাপ বাদ দিলে container start হওয়ার সঙ্গে সঙ্গেই Internet-এ উন্মুক্ত হয়ে যায়, কারণ published Docker port আপনার firewall rule-এর আগে কার্যকর হয়। এই ঝুঁকিটি বিস্তারিত পড়া উচিত: published Docker port ufw-এর নিয়ম এড়িয়ে যায়।
আপনি শেখার সময় SEARXNG_VERSION=latest ব্যবহার করতে পারেন। গুরুত্বপূর্ণ server-এ tag নির্দিষ্ট করে দিন। October 2026 অনুযায়ী release tag-গুলো date ভিত্তিক এবং 2026.10.4-d48c4b555-এর মতো দেখতে। তাই pinned deployment registry-তে পরিবর্তন হলেই নয়, আপনি সিদ্ধান্ত নিলে upgrade হবে। Server-এ দীর্ঘ সময় চালু থাকা অন্য সব কিছুর ক্ষেত্রেও একই শৃঙ্খলা উপকারী। এই কারণেই self-hosted RustDesk relay-ও তার image tag নির্দিষ্ট করে। remote access service-এ unattended upgrade হলে সেটি সবচেয়ে অনুপযুক্ত সময়ে সমস্যার জানান দিতে পারে।
settings.yml: গুরুত্বপূর্ণ অংশ
প্রথমবার start করার আগে core-config/settings.yml তৈরি করুন। use_default_settings: true SearXNG-কে আগে তার নিজস্ব shipped default load করতে এবং এরপর শুধু আপনার লেখা key প্রয়োগ করতে বলে। তাই আপনার file ছোট থাকে এবং নতুন option যোগ হওয়া upgrade-এর পরেও কাজ করে।
আগে secret generate করুন, কারণ value সরাসরি 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 session ও token data sign করে। shipped default হলো আক্ষরিক string ultrasecretkey। এটি অপরিবর্তিত রাখলে ওই default জানা যে কেউ token forge করতে পারে। একবার এটি replace করুন, তারপর আর পরিবর্তন করবেন না। পরে পরিবর্তন করলে সংরক্ষিত সব preference মুছে যাবে।
base_url অবশ্যই trailing slash-সহ public HTTPS address হতে হবে। SearXNG render করা link-এ এই address লিখে। এটি localhost-এ রেখে দিলে remote browser-এ "next page" link পাঠকের নিজের machine-কে নির্দেশ করবে এবং কাজ করবে না।
formats web endpoint কোন output type তৈরি করবে তা নির্ধারণ করে। json default list-এ নেই। তাই এটি যোগ না করা পর্যন্ত JSON request 403 return করবে। image_proxy: true result thumbnail আপনার server-এর মাধ্যমে route করে। ফলে ওই image host করা site-গুলো আপনার visitor-দের address দেখতে পায় না।
valkey.url hostname হিসেবে valkey ব্যবহার করে, কারণ Compose file-এ এটিই service name। Compose উভয় container-কে একই network-এ রাখে, যেখানে service name resolve হয়। এটিকে localhost-এ point করলে limiter ব্যর্থ হবে, কারণ core container-এর ভিতরে localhost হলো সেই container নিজেই।
secret একটি plain file-এ থাকে। তাই এর আশপাশের directory-ও সুরক্ষিত করুন। chmod 750 /opt/searxng অন্য host user-দের প্রবেশ ঠেকায়। আপনি core-config/settings.yml-এর mode 600-এ আরও কঠোর করতে পারেন। এতে কিছু নষ্ট হবে না। Official container-এর entrypoint root হিসেবে start করে। এরপর FORCE_OWNERSHIP default true রেখে দিলে SearXNG start হওয়ার আগে mounted config directory-টির ownership container-এর নিজস্ব searxng user-এর কাছে হস্তান্তর করে। ফলে file-টি ওই user-এর জন্য readable থাকে। এর প্রভাব host-এ দেখা যায়: একই ধাপে core-config/-এর owner container-এর user ID-তে পরিবর্তিত হয়। তাই পরে file edit করতে sudo ব্যবহার করার প্রয়োজন হবে।
Stack start করে এটি পরীক্ষা করুন।
cd /opt/searxng
docker compose up -d
docker compose ps
curl -I http://127.0.0.1:8080/docker compose ps-এ উভয় container-এর state running দেখানো উচিত। curl-এর উত্তর HTTP/1.1 200 OK হওয়া উচিত। কোনো উত্তর না পেলে docker compose logs core পড়ুন। settings.yml-এ YAML ভুল থাকলে সেখানে line উল্লেখ করে parse error দেখা যাবে।
nginx-এর পেছনে TLS-সহ চালান
Container-টি শুধু loopback-এ listen করে। তাই nginx এটিকে পৌঁছানো সম্ভব করে এবং transport layer security (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.comReload করার আগে nginx -t, syntax is ok এবং test is successful প্রিন্ট করে। Certbot একই ফাইলটি পুনর্লিখে certificate-সহ 443 port-এ listen করার ব্যবস্থা করে এবং port 80 থেকে redirect যোগ করে। search.example.com-এর DNS record আগে থেকেই এই server-এ নির্দেশ করতে হবে, কারণ certificate authority HTTP-এর মাধ্যমে একটি file fetch করে ownership যাচাই করে। Renewal-সহ সম্পূর্ণ নির্দেশনা Ubuntu 24.04-এর Certbot ও nginx guide-এ রয়েছে।
দুটি forwarding header শুধুমাত্র আনুষ্ঠানিকতার জন্য নয়। X-Forwarded-For এবং X-Real-IP না থাকলে SearXNG-এ আসা প্রতিটি request-এ proxy address থাকে। ফলে rate limiter মনে করে একজন client-ই সব traffic তৈরি করছে এবং visitor-দের আলাদা করতে পারে না।
কেন script এবং agent-এর JSON search API প্রয়োজন
json-কে formats-এর সঙ্গে ব্যবহার করলে, page render করা একই endpoint structured data ফেরত দেয়।
curl -s 'http://127.0.0.1:8080/search?q=wireguard+mtu&format=json' \
| jq -r '.results[0:5][] | .url'আপনি একটি results array-সহ object পান। প্রতিটি entry-তে url, title, content এবং ফলাফল সরবরাহকারী engine থাকে। এর সঙ্গে answers, infoboxes এবং suggestions-ও থাকে। একটি summariser, link checker বা research loop চালানোর জন্য এটুকুই যথেষ্ট। এই ফলাফল language model-এ পাঠানো যতটা সহজ মনে হয়, আসলে তার চেয়ে বেশি জটিল। Search result হলো untrusted text, এবং এর মধ্যে নিজস্ব instruction থাকতে পারে। আপনার SearXNG instance-এ AI agent নির্দেশ করা বিষয়টি বিস্তারিতভাবে এই ঝুঁকি সামলায়।
Agent-ভিত্তিক যেকোনো ব্যবস্থার জন্য এটি গুরুত্বপূর্ণ। Language model-এর training cutoff থাকে। তাই বর্তমান বিষয়ের প্রশ্নের উত্তর দিতে তার live search প্রয়োজন। Commercial search API প্রতি query-র জন্য খরচ নেয় এবং কঠোর rate limit প্রয়োগ করে। আপনি ইতিমধ্যে যে server-এর জন্য অর্থ দিচ্ছেন, সেখানে একটি local instance চালাতে শুধু একটি container লাগে। Query-গুলোও সেই server-এর বাইরে যায় না। কোনো model-এ tool যুক্ত করলে একই যুক্তিতে VPS-এ MCP server চালানো প্রাসঙ্গিক হয়। সাধারণত search tool-ই মানুষ প্রথমে যোগ করে।
API ব্যবহারের ক্ষেত্রে 2টি নিয়ম মানুন। Instance-টি private রাখুন। API side-কে loopback address বা private network-এ bind করুন, যাতে শুধু আপনার নিজস্ব host-গুলো সেখানে পৌঁছাতে পারে। আপনার phone যে endpoint-এ নিজের অবস্থান পাঠায়, self-hosted location tracker-এর ক্ষেত্রেও একইভাবে endpoint সুরক্ষিত রাখতে হয়। এরপর ধীরে query পাঠান। SearXNG আপনার request-টি প্রকৃত search engine-এ forward করে। তাই প্রতি second-এ 100টি query চালানো কোনো script আসলে Google-কে আপনার server block করতে বলছে।
সীমারক, এবং public instance-এর ক্ষেত্রে যা পরিবর্তিত হয়
সীমারকটি SearXNG-এর bot প্রতিরোধ ব্যবস্থা। এটি request header, address এবং request rate পর্যবেক্ষণ করে। স্বয়ংক্রিয় মনে হওয়া traffic এটি বাদ দেয়। এই অবস্থা ধরে রাখতে এর Valkey প্রয়োজন। তাই Compose file-এ Valkey অন্তর্ভুক্ত থাকে।
Private instance-এ limiter: false রাখুন। আপনার নিজের script-গুলো সংজ্ঞা অনুযায়ী automated traffic। তাই instance যে JSON call-এর জন্য তৈরি, limiter ঠিক সেই call-গুলোই block করবে। এর পরিবর্তে access control reverse proxy-এর দায়িত্ব দিন: nginx location-এ একটি allow ও deny জোড়া, HTTP basic authentication, অথবা এমন firewall যা শুধু আপনার অন্য server-গুলোকে অনুমতি দেয়। বিভিন্ন network-এর মধ্যে পরিবর্তনশীল laptop থেকে private instance-এ পৌঁছাতে হলে এর সামনে একটি v3 onion address বসানো চতুর্থ বিকল্প। কারণ tor কোনো নতুন কিছু Internet-এ প্রকাশ না করেই একই loopback port-এ সংযোগ করে।
অন্যদের জন্য instance প্রকাশ করলে উভয় switch চালু করুন।
server:
limiter: true
public_instance: trueআরও সূক্ষ্ম নিয়ন্ত্রণ core-config/limiter.toml-এ থাকে। Container এটি /etc/searxng/limiter.toml থেকে পড়ে। আপনি শুধু যে key-গুলো পরিবর্তন করতে চান, সেগুলো লিখবেন। Proxy-এর পেছনে থাকলে proxy ঘোষণা করতেই হবে। তা না হলে limiter আপনার nginx address-কে abusive client হিসেবে গণ্য করবে।
[botdetection]
trusted_proxies = [
'127.0.0.0/8',
'::1',
]
[botdetection.ip_limit]
link_token = truelink_token = true SearXNG-কে এমন একটি token তৈরি করতে বলে, যা শুধু প্রকৃত browser session সংগ্রহ করবে। এতে অধিকাংশ সাধারণ scraper বন্ধ হয়। Public instance চালুর কয়েক দিনের মধ্যেই scraper আসতে পারে। Engine error-এর জন্যও প্রস্তুত থাকুন। আপনি যত বেশি traffic forward করবেন, upstream engine-গুলো তত দ্রুত আপনার server address-এ CAPTCHA পাঠানো শুরু করবে। Public SearXNG instance পরিচালনা একটি চলমান কাজ। Private instance-এর ক্ষেত্রে তা নয়। এই কারণে 2026 সালে self-host করার উপযোগী বিষয়গুলোর সংক্ষিপ্ত তালিকায় এটি থাকে। তবে ওই তালিকার প্রতিটি বিষয় infrastructure নয়: Jellyfin library-কে হাঁটা যায় এমন 90s-এর rental store হিসেবে পুনর্গঠন করাও একই nginx block-এর পেছনে একই container চালায়, শুধু কোনো workflow-এর বদলে একটি সন্ধ্যার দিকে নির্দেশ করে।
অনুসন্ধানে কোনো ফলাফল না আসার কারণ
আপনার instance-এ /stats খুলুন। এখানে প্রতিটি engine-এর error rate এবং response time তালিকাভুক্ত থাকে। ফলাফল কম মনে হলে এটিই প্রথমে পরীক্ষা করার জায়গা।
কোনো engine-এ "Access denied" বা "CAPTCHA" error দেখা গেলে সেটি আপনার server address block করেছে। Data centre range-এর address-এর ক্ষেত্রে এটি সাধারণ ঘটনা, কারণ search engine-গুলো ধরে নেয় যে এগুলো scraper-এর। এরপর SearXNG ব্যর্থ engine-টিতে আবার request না পাঠিয়ে নির্দিষ্ট সময়ের জন্য সেটিকে suspend করে। ফলে block হওয়া একটি engine নীরবে আপনার ফলাফল থেকে বাদ পড়ে। settings.yml-এ সেটি disable করুন অথবা এই ঘাটতি মেনে নিন। তবে এটিই একমাত্র দুটি উপায় নয়, কারণ কিছু CAPTCHA block-এর এমন সমাধান আছে যা restart-এর পরও কার্যকর থাকে। বাকি engine-গুলো তখনও response দেবে। 429 হলো অস্পষ্ট পরিস্থিতি, কারণ এটি আপনার নিজের limiter থেকে আসতে পারে, অথবা upstream engine আপনার server প্রত্যাখ্যান করার কারণেও আসতে পারে। Settings পরিবর্তন করার আগে log line দেখে বুঝে নিন আপনি এই দুটির কোনটির মুখোমুখি হয়েছেন।
সব engine একসঙ্গে ব্যর্থ হলে container-এ কার্যকর outbound name resolution নেই, অথবা Internet-এ যাওয়ার কোনো route নেই। Container-এর ভেতর থেকে এটি পরীক্ষা করুন।
docker compose exec core wget -qO- https://duckduckgo.com > /dev/null && echo okএই পরীক্ষা ব্যর্থ হওয়া শুরু করলে box-এর কোনো কিছু আপনাকে জানাবে না। তাই cron থেকে এটি চালান এবং ফলাফল কমে যাওয়া লক্ষ্য করার অপেক্ষা না করে নিজের ntfy server থেকে আপনার phone-এ alert পাঠান।
FAQ
SearXNG কি আমার সার্চগুলোকে বেনামী রাখে?
এটি যে সার্চ ইঞ্জিনগুলোতে কোয়েরি পাঠায়, তাদের কাছ থেকে আপনার পরিচয় গোপন রাখে, কারণ তারা আপনার ব্রাউজারের পরিবর্তে আপনার সার্ভার থেকে অনুরোধটি আসতে দেখে। এটি আপনার সার্ভারের কাছে কোয়েরিটি গোপন করে না এবং তাদের কাছে আপনার সার্ভারকেও গোপন করে না। একটি সিঙ্গেল-ইউজার ইনস্ট্যান্সে সেই ঠিকানা থেকে আসা সমস্ত ট্রাফিক আপনার, তাই ঠিকানাটি নিজেই আপনার পরিচয় বহনকারী হয়ে ওঠে। আপনার ব্রাউজার এবং আপনার ইনস্ট্যান্সের মধ্যকার ট্রাফিক TLS certificate দ্বারা সুরক্ষিত। আপনার ISP, পাবলিক ইনস্ট্যান্সের অপারেটর এবং সার্চ ইঞ্জিনগুলোর ক্ষেত্রে আপনি কতটা সুরক্ষিত, তা SearXNG আসলে কী গোপন করে অংশে বিস্তারিত আলোচনা করা হয়েছে।
কেন একটি JSON অনুরোধ 403 Forbidden ত্রুটি দেখায়?
এর দুটি কারণ থাকতে পারে এবং উভয়ই কনফিগারেশন সংক্রান্ত। হয় settings.yml ফাইলের search: সেকশনের অধীনে formats তালিকায় json অনুপস্থিত (যা ডিফল্ট অবস্থা), অথবা লিমিটার চালু আছে এবং এটি আপনার স্ক্রিপ্টকে বট হিসেবে চিহ্নিত করেছে। প্রথমে ফরম্যাটটি যোগ করুন, docker compose restart core দিয়ে রিস্টার্ট করুন এবং তারপর আবার চেষ্টা করুন। যদি এরপরও ব্যর্থ হয়, তবে limiter: false সেট করুন এবং রিভার্স প্রক্সিতে অ্যাক্সেস নিয়ন্ত্রণ করুন।
আমি যদি লিমিটার বন্ধ রাখি, তবে কি আমার Valkey কন্টেইনারটি প্রয়োজন?
এটি চালু রাখুন। SearXNG এটি ছাড়াই কাজ করে, কিন্তু এটি ছাড়া পরবর্তীতে লিমিটার চালু করা সম্ভব নয় এবং এটি অন্যান্য স্বল্পস্থায়ী তথ্যও সংরক্ষণ করে। কন্টেইনারটি ছোট এবং এটি শুধু cached data সংরক্ষণ করে, তাই এটি সরিয়ে ফেললে খুব সামান্যই সাশ্রয় হয় কিন্তু আপনি এই সুবিধাটি হারাবেন।
আমি কীভাবে SearXNG আপডেট করব?
/opt/searxng ডিরেক্টরিতে গিয়ে প্রথমে docker compose pull এবং তারপর docker compose up -d চালান। Compose এমন যেকোনো কন্টেইনার পুনরায় তৈরি করে যার ইমেজ পরিবর্তিত হয়েছে এবং আপনার core-config/ ডিরেক্টরিটিকে অক্ষত রাখে, তাই settings.yml টিকে থাকে। যেহেতু use_default_settings: true আপনার কি (keys) গুলোকে ডিফল্ট সেটিংসের সাথে মার্জ করে, তাই আপস্ট্রিম থেকে নতুন কোনো অপশন যোগ করা হলে তা ফাইলটি নষ্ট না করে সঠিক মান নিয়ে যুক্ত হয়।
একাধিক ব্যক্তি কি একটি ইনস্ট্যান্স শেয়ার করতে পারে?
হ্যাঁ, এবং সেই ক্ষেত্রেই আপনি লিমিটার চালু করবেন এবং public_instance: true সেট করবেন। পছন্দগুলো (preferences) প্রতিটি ভিজিটরের নিজস্ব ব্রাউজারে সংরক্ষিত থাকে, তাই এখানে কোনো অ্যাকাউন্ট ম্যানেজ করার প্রয়োজন নেই। এটি সবার জন্য উন্মুক্ত করার পর এক সপ্তাহ ধরে /stats পর্যবেক্ষণ করুন, কারণ ফলাফল আসা বন্ধ হওয়ার অনেক আগেই আপস্ট্রিম সার্চ ইঞ্জিনগুলো আপনার সার্ভারকে ব্লক করা শুরু করতে পারে।