آموزش راه اندازی SearXNG با Docker Compose
با استفاده از Docker Compose و تنظیمات nginx، موتور جستجوی شخصی SearXNG را روی VPS اجرا کنید. این راهنما شامل پیکربندی settings.yml، محدودکننده درخواست و API برای اسکریپتها است.
آنچه میسازید
میزبانی شخصی SearXNG به شما یک موتور جستجوی خصوصی میدهد که روی سرور خودتان اجرا میشود. SearXNG یک موتور جستجوی متا (metasearch) است: پرسوجوی شما را میگیرد، از موتورهای دیگر مانند Google، Bing، DuckDuckGo و Wikipedia میپرسد و سپس نتایج دریافتی را در یک صفحه واحد ادغام میکند. هیچ پروفایلی ساخته نمیشود و هیچ کوکی ردیابی تنظیم نمیگردد، زیرا تنها ماشینی که پرسوجوی شما را نگه میدارد، دستگاه خودتان است. اگر راهنماهای قدیمیتری برای پروژهای که صرفاً Searx نامیده میشد پیدا کردهاید، این همان پروژهای است که SearXNG از آن منشعب شده است؛ آن پروژه از سال 2023 هیچ commit جدیدی نداشته است، بنابراین پیش از دنبال کردن هر کدام، وضعیت هر دو را بررسی کنید.
پشته نرمافزاری کوچک است. دو کانتینر، یک فایل تنظیمات و یک reverse proxy. این سرویس بهراحتی روی یک VPS کوچک اجرا میشود، که این موضوع درباره همه سرویسهای self-hosted صادق نیست: کتابخانههای عکس که در مقایسه PhotoPrism و Immich بررسی شدند، حداقل رم مورد نیاز خود را بر اساس ایندکسکننده تعیین میکنند، نه برنامه وب. تصمیم اصلی این است که آیا این نمونه خصوصی است، یعنی فقط شما و اسکریپتهای خودتان به آن دسترسی دارید، یا عمومی است، یعنی هر کسی در اینترنت میتواند از آن استفاده کند. این انتخاب تنظیمات امنیتی را تغییر میدهد، پس پیش از تایپ هر دستوری آن را مشخص کنید. پاسخ پیشفرض، خصوصی است.
دلیل دومی هم برای اجرای آن وجود دارد. یک نمونه SearXNG با فرمت JSON صحبت میکند، بنابراین هر اسکریپت یا عامل هوش مصنوعی که مینویسید، به یک API جستجوی اختصاصی دسترسی خواهد داشت؛ بدون نیاز به کلید، بدون صورتحساب به ازای هر پرسوجو و بدون محدودیتهای سهمیهبندی.
نصب SearXNG با Docker Compose
این پروژه یک image کانتینر و یک فایل Compose منتشر میکند. هر دو را روی یک سرور تازه Ubuntu 24.04 که Docker Engine و پلاگین Compose را دارد، دریافت (pull) کنید. اگر با 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 یک ذخیرهساز داده در حافظه (in-memory) است که برای محدودسازی نرخ (rate limiting) و وضعیتهای کوتاهمدت استفاده میشود. این فایل ./core-config/ را در مسیر /etc/searxng/ داخل کانتینر mount میکند، بنابراین تمام تنظیمات شما در همان یک دایرکتوری روی میزبان (host) قرار میگیرد.
اکنون .env را ویرایش کنید. تمام خطوط در نمونهٔ ارائهشده کامنت شدهاند، به همین دلیل کانتینر روی پورت 8080 در تمام آدرسها اجرا میشود. کامنت این سه مورد را بردارید و آنها را تنظیم کنید.
SEARXNG_VERSION=latest
SEARXNG_HOST=127.0.0.1
SEARXNG_PORT=8080SEARXNG_HOST=127.0.0.1 مورد مهمی است. این گزینه پورت منتشرشده را به 127.0.0.1:8080:8080 به جای [::]:8080:8080 تغییر میدهد، بنابراین کانتینر فقط روی آدرس loopback پاسخ میدهد و اینترنت نمیتواند مستقیماً به آن دسترسی داشته باشد. اگر از این مرحله بگذرید، کانتینر به محض شروع کار در معرض دید قرار میگیرد، زیرا پورت منتشرشدهٔ Docker پیش از قوانین فایروال شما قرار میگیرد. خواندن کامل این تله توصیه میشود: پورتهای منتشرشده Docker از ufw عبور میکنند.
SEARXNG_VERSION=latest برای زمانی که در حال یادگیری هستید مناسب است. روی سروری که برایتان اهمیت دارد، تگ را ثابت (pin) کنید. از ژوئیه 2026، تگهای انتشار بر اساس تاریخ هستند و به شکل 2026.3.25-541c6c3cb دیده میشوند، بنابراین استقرار ثابت (pinned) زمانی ارتقا مییابد که شما تصمیم بگیرید، نه زمانی که رجیستری تغییر کند. همین نظم برای هر چیز دیگری که طولانیمدت روی سرور باقی میماند نتیجهبخش است، به همین دلیل است که یک relay خودمیزبان RustDesk نیز تگهای image خود را ثابت میکند: ارتقای خودکار یک سرویس دسترسی از راه دور، در بدترین زمان ممکن خود را نشان میدهد.
فایل settings.yml: بخشهای مهم
پیش از اولین اجرا، core-config/settings.yml را ایجاد کنید. use_default_settings: true به SearXNG دستور میدهد که تنظیمات پیشفرض خود را بارگذاری کرده و سپس فقط کلیدهایی که شما نوشتهاید را اعمال کند؛ بنابراین فایل شما کوتاه باقی میماند و در هنگام ارتقا که گزینههای جدیدی اضافه میشود، دچار مشکل نمیشود.
ابتدا secret را تولید کنید، زیرا مقدار آن مستقیماً در فایل قرار میگیرد.
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) و توکنها را امضا میکند. مقدار پیشفرض ارائهشده، رشته متنی ultrasecretkey است و باقی گذاشتن آن به این معناست که هر کسی که این مقدار پیشفرض را بداند، میتواند توکنها را جعل کند. آن را یکبار تغییر دهید و سپس به حال خود رها کنید: تغییر دادن آن در آینده باعث از بین رفتن تمام تنظیمات ذخیرهشده کاربران میشود.
base_url باید آدرس عمومی HTTPS، همراه با اسلش انتهایی باشد. این همان مقداری است که SearXNG در لینکهایی که تولید میکند، مینویسد. اگر آن را روی localhost باقی بگذارید، لینک «صفحه بعد» در مرورگر کاربر راه دور به ماشین خودِ کاربر اشاره کرده و با خطا مواجه میشود.
formats تعیین میکند که وبسرویس چه نوع خروجیهایی تولید کند. json در لیست پیشفرض نیست، بنابراین درخواستهای JSON تا زمانی که آن را اضافه نکنید، با خطای 403 مواجه میشوند. image_proxy: true تصاویر بندانگشتی (thumbnails) نتایج را از طریق سرور شما هدایت میکند، بنابراین سایتهایی که میزبان آن تصاویر هستند، هرگز آدرس IP بازدیدکنندگان شما را نمیبینند.
در valkey.url از نام میزبان valkey استفاده شده است، زیرا این نام سرویس در فایل Compose است و Compose هر دو کانتینر را در یک شبکه قرار میدهد که در آن نام سرویسها قابل حل (resolve) هستند. اگر آن را به localhost اشاره دهید، محدودکننده (limiter) از کار میافتد، زیرا در داخل کانتینر core، عبارت localhost به خودِ همان کانتینر اشاره دارد.
از آنجا که secret در یک فایل متنی ساده قرار دارد، به جای خودِ فایل، دایرکتوری اطراف آن را محافظت کنید. chmod 750 /opt/searxng دسترسی سایر کاربران میزبان را محدود میکند. مجوز core-config/settings.yml را به 600 محدود نکنید: کانتینر با کاربر بدون امتیاز (unprivileged) خود اجرا میشود و فایلی که نتواند آن را بخواند، باعث میشود 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 در آنجا به صورت خطای تجزیه (parse error) همراه با شماره خط نمایش داده میشوند.
قرار دادن آن پشت 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.comnginx -t قبل از reload کردن، syntax is ok و test is successful را چاپ میکند. Certbot همان فایل را بازنویسی میکند تا روی پورت 443 با گواهی گوش دهد و یک redirect از پورت 80 اضافه میکند. رکورد DNS برای search.example.com باید از قبل به این سرور اشاره کند، زیرا مرجع صدور گواهی، مالکیت را از طریق دریافت یک فایل از طریق HTTP تأیید میکند. راهنمای کامل، شامل تمدید گواهی، در راهنمای Certbot و Nginx برای Ubuntu 24.04 موجود است.
دو هدر forwarding صرفاً تزئینی نیستند. بدون X-Forwarded-For و X-Real-IP، هر درخواستی که به SearXNG میرسد، آدرس پروکسی را حمل میکند؛ بنابراین محدودکننده نرخ (rate limiter) تصور میکند یک کلاینت تمام ترافیک را ایجاد میکند و نمیتواند بازدیدکنندگان را از هم تشخیص دهد.
چرا اسکریپتها و عاملها به API جستجوی JSON نیاز دارند
با استفاده از 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 قرار دارد. این اطلاعات برای تغذیه یک خلاصهساز، بررسیکننده لینک یا یک حلقه پژوهشی کافی است. سپردن این نتایج به یک مدل زبانی، گامی بزرگتر از آن چیزی است که به نظر میرسد، زیرا نتایج جستجو متنی غیرقابلاعتماد هستند که میتوانند دستورالعملهای خاص خود را داشته باشند؛ موضوعی که در اشاره کردن یک عامل هوش مصنوعی به نمونه SearXNG خود بهطور مفصل بررسی شده است.
این موضوع برای هر چیزی که ماهیت عامل (agent) دارد، اهمیت دارد. یک مدل زبانی دارای تاریخ انقضای آموزش است، بنابراین برای پاسخ به سوالات درباره زمان حال به جستجوی زنده نیاز دارد، و APIهای جستجوی تجاری برای هر پرسوجو هزینه دریافت کرده و محدودیتهای نرخ (rate limit) شدیدی اعمال میکنند. یک نمونه محلی تنها هزینه یک کانتینر روی سروری را دارد که از قبل برای آن هزینه پرداخت کردهاید و پرسوجوها هرگز از آن خارج نمیشوند. اگر در حال متصل کردن ابزارها به یک مدل هستید، همین استدلال باعث میشود که اجرای سرورهای MCP روی یک VPS را در نظر بگیرید، جایی که ابزار جستجو معمولاً اولین ابزاری است که افراد اضافه میکنند.
دو قانون برای استفاده از API وجود دارد. نمونه خود را خصوصی نگه دارید؛ بنابراین سمت API را به آدرس loopback یا یک شبکه خصوصی bind کنید و اجازه دهید فقط میزبانهای خودتان به آن دسترسی داشته باشند. سپس با ملایمت از آن پرسوجو کنید. SearXNG درخواست شما را به موتورهای جستجوی واقعی ارسال میکند، بنابراین اسکریپتی که صد پرسوجو در ثانیه اجرا میکند، در واقع از Google میخواهد که سرور شما را مسدود کند.
محدودکننده (Limiter) و تغییرات لازم برای یک نمونه عمومی (Public Instance)
محدودکننده، سیستم دفاعی SearXNG در برابر رباتها است. این بخش هدرهای درخواست، آدرسها و نرخ درخواستها را پایش کرده و ترافیکی که به نظر خودکار میرسد را مسدود میکند. این سیستم برای نگهداری وضعیت (State) به Valkey نیاز دارد، به همین دلیل فایل Compose آن را به همراه دارد.
در یک نمونه خصوصی (Private Instance)، گزینه limiter: false را فعال نگه دارید. اسکریپتهای شخصی شما طبق تعریف، ترافیک خودکار محسوب میشوند؛ بنابراین محدودکننده دقیقاً همان فراخوانیهای JSON که برای آن نمونه را ساختهاید، مسدود خواهد کرد. در عوض، کنترل دسترسی وظیفه reverse proxy است: استفاده از یک جفت allow و deny در فایل location مربوط به nginx، احراز هویت HTTP basic، یا یک فایروال که فقط به سایر سرورهای شما اجازه ورود میدهد. اگر نیاز دارید از لپتاپی که بین شبکههای مختلف جابهجا میشود به یک نمونه خصوصی دسترسی پیدا کنید، قرار دادن یک آدرس v3 onion در مقابل آن گزینه چهارم است، زیرا tor به همان پورت loopback متصل میشود بدون اینکه چیزی را در اینترنت اکسپوز کند.
اگر نمونه را برای استفاده عموم منتشر میکنید، هر دو سوئیچ را روشن کنید.
server:
limiter: true
public_instance: trueکنترل دقیقتر در core-config/limiter.toml قرار دارد که کانتینر آن را در مسیر /etc/searxng/limiter.toml میخواند. شما فقط کلیدهایی را که میخواهید تغییر دهید در آن بنویسید. در پشت یک پروکسی، حتماً باید پروکسی را اعلام کنید، در غیر این صورت محدودکننده آدرس nginx شما را به عنوان تنها کلاینت مخرب شناسایی میکند.
[botdetection]
trusted_proxies = [
'127.0.0.0/8',
'::1',
]
[botdetection.ip_limit]
link_token = trueگزینه link_token = true باعث میشود SearXNG توکنی صادر کند که فقط یک نشست مرورگر واقعی آن را دریافت میکند؛ این کار اکثر اسکریپرهای ساده را متوقف میکند. انتظار داشته باشید که یک نمونه عمومی ظرف چند روز آنها را به خود جذب کند. همچنین انتظار خطاهای موتورهای جستجو را داشته باشید، زیرا هرچه ترافیک بیشتری ارسال کنید، موتورهای بالادستی زودتر شروع به بازگرداندن CAPTCHA به آدرس سرور شما میکنند. یک نمونه عمومی SearXNG کاری مداوم است. اما یک نمونه خصوصی اینطور نیست، و به همین دلیل است که در اکثر لیستهای کوتاه مواردی که ارزش self-hosting در سال 2026 را دارند قرار میگیرد. ضمناً، همه موارد موجود در آن لیستها زیرساختی نیستند: بازسازی کتابخانه Jellyfin به شکل یک فروشگاه کرایه فیلم دهه 90، همان کانتینر پشت همان بلاک nginx است، با این تفاوت که به جای یک گردش کاری (workflow)، برای گذراندن یک عصر در خانه تنظیم شده است.
چرا جستجوها نتیجهای برنمیگردانند
/stats را در نمونه (instance) خود باز کنید. این بخش فهرستی از تمام موتورها به همراه نرخ خطا و زمان پاسخدهی آنها را نمایش میدهد و اولین جایی است که هنگام کمبود نتایج باید بررسی کنید.
موتوری که با خطای «Access denied» یا «CAPTCHA» نمایش داده میشود، آدرس سرور شما را مسدود کرده است. این وضعیت برای آدرسهای واقع در بازههای مرکز داده رایج است، زیرا موتورهای جستوجو فرض میکنند این آدرسها به scraperها تعلق دارند. سپس SearXNG موتور ناموفق را برای مدتی تعلیق میکند و بهجای تلاش مجدد، آن را کنار میگذارد؛ در نتیجه، یک موتور مسدودشده بدون ایجاد خطای آشکار از نتایج شما حذف میشود. آن را در settings.yml غیرفعال کنید یا حذف آن را بپذیرید. این دو، تنها گزینههای شما نیستند، زیرا برخی مسدودسازیهای CAPTCHA راهحلی دارند که پس از restart نیز باقی میماند. موتورهای باقیمانده همچنان پاسخ میدهند. خطای 429 مورد مبهم است، زیرا ممکن است از limiter خودتان یا از موتور بالادستی ناشی شود که سرور شما را رد میکند؛ خط موجود در log مشخص میکند با کدامیک از این دو وضعیت روبهرو هستید، پیش از آنکه تغییر تنظیمات را شروع کنید.
اگر تمام موتورها همزمان با شکست مواجه شدند، کانتینر فاقد قابلیت حل نام (name resolution) خروجی است یا مسیری به اینترنت ندارد. این مورد را از داخل کانتینر تست کنید.
docker compose exec core wget -qO- https://duckduckgo.com > /dev/null && echo okهیچ ابزاری روی سرور به شما اطلاع نمیدهد که چه زمانی این بررسی با شکست مواجه میشود؛ بنابراین آن را از طریق cron اجرا کنید و اجازه دهید در صورت بروز خطا، یک هشدار از طریق سرور ntfy شخصیتان به گوشی شما ارسال شود تا مجبور نباشید منتظر بمانید تا متوجه شوید نتایج جستجو کاهش یافتهاند.
FAQ
آیا SearXNG جستجوهای من را ناشناس میکند؟
این ابزار هویت شما را از موتورهایی که از آنها پرسوجو میکند مخفی نگه میدارد، زیرا آنها بهجای مرورگر شما، سرور شما را بهعنوان منبع درخواست میبینند. این ابزار پرسوجوی شما را از سرور خودتان مخفی نمیکند و سرور شما را نیز از دید موتورهای جستجو پنهان نمیسازد. در یک نمونه (instance) تککاربره، تمام ترافیک آن آدرس متعلق به شماست، بنابراین خودِ آدرس به شناسه تبدیل میشود. ترافیک بین مرورگر شما و نمونهتان توسط گواهی TLS محافظت میشود. اینکه این وضعیت شما را در برابر ISP، گرداننده یک نمونه عمومی و خودِ موتورهای جستجو در چه جایگاهی قرار میدهد، در آنچه SearXNG واقعاً مخفی میکند بررسی شده است.
چرا یک درخواست JSON خطای 403 Forbidden برمیگرداند؟
دو دلیل وجود دارد و هر دو به پیکربندی مربوط میشوند. یا json در لیست formats تحت بخش search: در فایل settings.yml وجود ندارد که وضعیت پیشفرض است، یا محدودکننده (limiter) فعال است و اسکریپت شما را بهعنوان یک ربات شناسایی کرده است. ابتدا فرمت را اضافه کنید، با docker compose restart core سرویس را مجدداً راهاندازی کنید و سپس دوباره تلاش کنید. اگر همچنان با خطا مواجه شدید، limiter: false را تنظیم کرده و دسترسی را در سطح reverse proxy کنترل کنید.
آیا اگر محدودکننده را خاموش نگه دارم، همچنان به کانتینر Valkey نیاز دارم؟
آن را در حال اجرا نگه دارید. SearXNG بدون آن کار میکند، اما بدون آن نمیتوانید محدودکننده را بعداً فعال کنید و همچنین وضعیتهای کوتاهمدت دیگر را نیز در خود نگه میدارد. این کانتینر کوچک است و فقط دادههای کششده را ذخیره میکند، بنابراین حذف آن فضای بسیار کمی آزاد میکند و در عوض گزینه استفاده از محدودکننده را از شما میگیرد.
چگونه SearXNG را بهروزرسانی کنم؟
دستور docker compose pull و سپس docker compose up -d را در /opt/searxng اجرا کنید. Compose هر کانتینری که ایمیج آن تغییر کرده باشد را بازسازی میکند و دایرکتوری core-config/ شما را دستنخورده باقی میگذارد، بنابراین settings.yml حفظ میشود. از آنجا که use_default_settings: true کلیدهای شما را با مقادیر پیشفرض ارائهشده ادغام میکند، گزینههای جدیدی که در نسخه upstream اضافه شدهاند با مقادیر معقول وارد میشوند و فایل شما را خراب نمیکنند.
آیا چندین نفر میتوانند از یک نمونه مشترک استفاده کنند؟
بله، و این دقیقاً همان موردی است که باید محدودکننده را روشن کرده و public_instance: true را تنظیم کنید. تنظیمات برگزیده (Preferences) در مرورگر هر بازدیدکننده ذخیره میشود، بنابراین نیازی به مدیریت حساب کاربری نیست. پس از عمومی کردن سرویس، به مدت یک هفته /stats را زیر نظر بگیرید، زیرا موتورهای جستجوی upstream خیلی پیش از آنکه متوجه نتایج ناقص شوید، شروع به مسدود کردن سرور شما میکنند.