آموزش راه اندازی SearXNG با Docker Compose روی سرور شخصی
با استفاده از Docker Compose و فایل settings.yml موتور جستجوی اختصاصی خود را بسازید. این راهنما شامل تنظیمات Nginx با TLS و نحوه استفاده از API برای اسکریپتها است.
آنچه در حال ساخت آن هستید
میزبانی شخصی SearXNG به شما یک موتور جستجوی خصوصی میدهد که روی سرور خودتان اجرا میشود. SearXNG یک موتور جستجوی متا (metasearch) است: پرسوجوی شما را میگیرد، از موتورهای دیگری مانند Google، Bing، DuckDuckGo و Wikipedia میپرسد و سپس نتایج بازگشتی را در یک صفحه واحد ادغام میکند. هیچ پروفایلی ساخته نمیشود و هیچ کوکی ردیابی تنظیم نمیگردد، زیرا تنها ماشینی که پرسوجوی شما را نگه میدارد، دستگاه خودتان است. اگر راهنماهای قدیمیتری برای پروژهای که صرفاً Searx نامیده میشد پیدا کردهاید، این همان پروژهای است که SearXNG از آن انشعاب (fork) گرفته است. آن پروژه از سپتامبر 2023 بدون پشتیبانی مانده است، زمانی که مخزن اصلی آن اعلام کرد Searx دیگر نگهداری نمیشود و تنها commit انجام شده پس از آن، یک یادداشت مستنداتی در مه 2026، تغییری در این وضعیت ایجاد نکرد. بنابراین قبل از دنبال کردن هر کدام، وضعیت هر دو را بررسی کنید.
پشته (stack) این سرویس کوچک است. دو کانتینر، یک فایل تنظیمات و یک reverse proxy. این سرویس بهراحتی روی یک VPS کوچک اجرا میشود، که این موضوع در مورد همه سرویسهای self-hosted صادق نیست: کتابخانههای عکسی که در مقایسه PhotoPrism و Immich بررسی شدند، حداقل رم مورد نیاز خود را بر اساس ایندکسکننده تعیین میکنند، نه برنامه وب. تصمیم اصلی این است که آیا این نمونه خصوصی است، یعنی فقط شما و اسکریپتهای خودتان به آن دسترسی دارید، یا عمومی است، یعنی هر کسی در اینترنت میتواند از آن استفاده کند. این انتخاب تنظیمات امنیتی را تغییر میدهد، پس قبل از تایپ هر دستوری، آن را مشخص کنید. پاسخ پیشفرض، خصوصی است.
دلیل دومی هم برای اجرای آن وجود دارد. یک نمونه SearXNG با فرمت JSON صحبت میکند، بنابراین هر اسکریپت یا عامل هوش مصنوعی که مینویسید، به یک API جستجوی اختصاصی دسترسی خواهد داشت، بدون نیاز به کلید، بدون صورتحساب به ازای هر پرسوجو و بدون محدودیت سهمیه (quota).
نصب 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 مورد مهمی است. این تنظیم باعث میشود پورت منتشرشده به جای 8080:8080 (که Docker آن را روی تمام آدرسها منتشر میکند)، به 127.0.0.1:8080:8080 تغییر یابد؛ در نتیجه کانتینر فقط روی آدرس loopback پاسخ میدهد و اینترنت نمیتواند مستقیماً به آن دسترسی داشته باشد. اگر از این مرحله بگذرید، کانتینر به محض شروع کار در دسترس عموم قرار میگیرد، زیرا پورت منتشرشده توسط Docker پیش از قوانین فایروال شما قرار میگیرد. مطالعهٔ کامل این تله توصیه میشود: پورتهای منتشرشده Docker قوانین ufw را دور میزنند.
SEARXNG_VERSION=latest برای زمانی که در حال یادگیری هستید مناسب است. روی سروری که برایتان اهمیت دارد، تگ (tag) را ثابت کنید. از اکتبر 2026، تگهای انتشار بر اساس تاریخ هستند و به شکل 2026.10.4-d48c4b555 دیده میشوند، بنابراین استقرار ثابت (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 دادههای نشست و توکنها را امضا میکند. مقدار پیشفرض در نسخه اصلی، رشته متنی ultrasecretkey است و باقی گذاشتن آن به این معناست که هر کسی که این مقدار پیشفرض را بداند، میتواند توکنها را جعل کند. آن را یکبار تغییر دهید و دیگر به آن دست نزنید: تغییر دادن آن در آینده باعث از بین رفتن تمام تنظیمات ذخیرهشده کاربران میشود.
base_url باید آدرس عمومی HTTPS، همراه با اسلش انتهایی باشد. این همان آدرسی است که SearXNG در لینکهایی که تولید میکند، مینویسد. اگر آن را روی localhost باقی بگذارید، لینک «صفحه بعد» در مرورگر کاربر راه دور به دستگاه خودش اشاره کرده و با خطا مواجه میشود.
formats تعیین میکند که وبسرویس چه نوع خروجیهایی تولید کند. json در لیست پیشفرض نیست، بنابراین درخواستهای JSON تا زمانی که آن را اضافه نکنید، با خطای 403 مواجه میشوند. image_proxy: true تصاویر بندانگشتی (thumbnails) نتایج را از طریق سرور شما هدایت میکند، بنابراین سایتهایی که میزبان آن تصاویر هستند، هرگز آدرس بازدیدکنندگان شما را نمیبینند.
valkey.url از نام میزبان valkey استفاده میکند، زیرا این نام سرویس در فایل Compose است و Compose هر دو کانتینر را در یک شبکه قرار میدهد که در آن نام سرویسها قابل حل (resolve) هستند. اگر آن را به localhost اشاره دهید، limiter با خطا مواجه میشود، زیرا در داخل کانتینر core، عبارت localhost به همان کانتینر اشاره دارد.
این secret در یک فایل متنی ساده قرار دارد، بنابراین دایرکتوری اطراف آن را نیز محافظت کنید. chmod 750 /opt/searxng دسترسی سایر کاربران میزبان را محدود میکند. شما همچنین میتوانید core-config/settings.yml را به حالت 600 تغییر دهید بدون اینکه مشکلی ایجاد شود: entrypoint کانتینر رسمی به عنوان root شروع میشود و با باقی ماندن FORCE_OWNERSHIP در مقدار پیشفرض true، دایرکتوری پیکربندی mount شده را پیش از شروع SearXNG به کاربر searxng داخل کانتینر واگذار میکند، بنابراین فایل برای آن قابل خواندن باقی میماند. اثر جانبی این کار در میزبان قابل مشاهده است: همان مرحله، مالک core-config/ را به شناسه کاربری کانتینر تغییر میدهد، بنابراین انتظار داشته باشید که پس از آن برای ویرایش فایل از sudo استفاده کنید.
استک را اجرا کرده و آن را بررسی کنید.
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 باید از قبل به این سرور اشاره کند، زیرا مرجع صدور گواهی (CA) مالکیت را از طریق دریافت یک فایل روی 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 یا یک شبکه خصوصی متصل کنید و اجازه دهید فقط میزبانهای خودتان به آن دسترسی داشته باشند؛ این همان رفتاری است که یک ردیاب موقعیت مکانی خودمیزبان برای endpointای که گوشی شما موقعیتش را به آن گزارش میدهد، نیاز دارد. سپس با ملایمت پرسوجو کنید. SearXNG درخواست شما را به موتورهای جستجوی واقعی ارسال میکند، بنابراین اسکریپتی که صد پرسوجو در ثانیه اجرا میکند، در واقع از Google میخواهد که سرور شما را مسدود کند.
محدودکننده (limiter) و تغییرات برای یک نمونه عمومی
محدودکننده، سیستم دفاعی SearXNG در برابر رباتها است. این سیستم هدرهای درخواست، آدرسها و نرخ درخواستها را پایش میکند و ترافیکی را که خودکار به نظر میرسد، مسدود میسازد. این سیستم برای نگهداری وضعیت به Valkey نیاز دارد، به همین دلیل فایل Compose آن را به همراه دارد.
در یک نمونه خصوصی، 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 = truelink_token = true باعث میشود SearXNG توکنی صادر کند که فقط یک نشست مرورگر واقعی آن را دریافت میکند، که این کار اکثر اسکریپتهای ساده (scrapers) را متوقف میکند. انتظار داشته باشید که یک نمونه عمومی ظرف چند روز آنها را جذب کند. همچنین انتظار خطاهای موتورهای جستجو را داشته باشید، زیرا هرچه ترافیک بیشتری ارسال کنید، موتورهای بالادستی زودتر شروع به بازگرداندن CAPTCHA به آدرس سرور شما میکنند. یک نمونه عمومی SearXNG یک کار مداوم است. یک نمونه خصوصی اینطور نیست، و به همین دلیل است که در اکثر فهرستهای کوتاه مواردی که ارزش self-hosting در سال 2026 را دارند قرار میگیرد. همه موارد موجود در آن فهرستها هم زیرساخت نیستند: بازسازی کتابخانه Jellyfin به شکل یک فروشگاه کرایه فیلم دهه 90 همان کانتینر پشت همان بلاک nginx است، با این تفاوت که به جای یک گردش کاری، به یک شبنشینی در خانه اشاره دارد.
چرا جستجوها نتیجهای برنمیگردانند
/stats را در نمونهٔ خود باز کنید. این صفحه فهرستی از تمام موتورها به همراه نرخ خطا و زمان پاسخدهی آنها را نمایش میدهد و اولین جایی است که هنگام مشاهده نتایج ناقص باید بررسی کنید.
موتوری که با خطاهای "Access denied" یا "CAPTCHA" نمایش داده میشود، آدرس سرور شما را مسدود کرده است. این اتفاق برای آدرسهای موجود در دیتاسنترها رایج است، زیرا موتورهای جستجو فرض میکنند که این آدرسها متعلق به اسکریپرها (scrapers) هستند. در چنین شرایطی، SearXNG موتورِ دارای خطا را برای مدتی معلق میکند تا از تلاش مجدد بیمورد جلوگیری شود؛ بنابراین یک موتور مسدودشده بهآرامی از نتایج شما حذف میشود. آن را در settings.yml غیرفعال کنید یا این کاهش نتایج را بپذیرید. اینها تنها دو گزینه نیستند، زیرا برخی از مسدودسازیهای CAPTCHA راهکاری دارند که پس از راهاندازی مجدد نیز باقی میماند. موتورهای باقیمانده همچنان پاسخ میدهند. خطای 429 یک مورد مبهم است، زیرا میتواند ناشی از محدودکننده (limiter) خودتان باشد یا از طرف یک موتور بالادستی که سرور شما را رد کرده است؛ خط لاگ به شما میگوید که با کدامیک از این دو مورد مواجه هستید، بنابراین پیش از تغییر تنظیمات، ابتدا لاگ را بررسی کنید.
اگر تمام موتورها همزمان شکست میخورند، کانتینر فاقد وضوح نام (name resolution) خروجی فعال است یا مسیری به اینترنت ندارد. این مورد را از داخل کانتینر تست کنید.
docker compose exec core wget -qO- https://duckduckgo.com > /dev/null && echo okهیچ ابزاری روی سیستم به شما اطلاع نمیدهد که چه زمانی این بررسی با شکست مواجه میشود؛ بنابراین آن را از طریق cron اجرا کنید و اجازه دهید در صورت بروز خطا، یک هشدار از طریق سرور ntfy شخصیتان به گوشی شما ارسال شود، بهجای اینکه منتظر بمانید تا متوجه شوید نتایج جستجو ناقص شدهاند.
FAQ
آیا SearXNG جستجوهای من را ناشناس میکند؟
این ابزار هویت شما را از موتورهایی که از آنها پرسوجو میکند مخفی نگه میدارد، زیرا آنها به جای مرورگر شما، سرور شما را در حال ارسال درخواست میبینند. این ابزار جستجو را از سرور شما مخفی نمیکند و سرور شما را نیز از دید آنها پنهان نمیسازد. در یک instance تککاربره، تمام ترافیک آن آدرس متعلق به شماست، بنابراین خودِ آدرس به شناسه تبدیل میشود. ترافیک بین مرورگر شما و instance شما توسط گواهی TLS محافظت میشود. اینکه این وضعیت شما را در برابر ISP، گرداننده یک instance عمومی و خودِ موتورهای جستجو در چه جایگاهی قرار میدهد، در آنچه SearXNG واقعاً مخفی میکند بررسی شده است.
چرا درخواست JSON خطای 403 Forbidden برمیگرداند؟
دو دلیل وجود دارد و هر دو مربوط به پیکربندی هستند. یا json در لیست formats تحت بخش search: در فایل settings.yml وجود ندارد که وضعیت پیشفرض است، یا محدودکننده (limiter) فعال است و اسکریپت شما را به عنوان ربات شناسایی کرده است. ابتدا فرمت را اضافه کنید، با docker compose restart core سرویس را restart کنید و دوباره تلاش کنید. اگر همچنان با خطا مواجه شدید، limiter: false را تنظیم کنید و دسترسی را در سطح reverse proxy کنترل نمایید.
آیا اگر محدودکننده را خاموش نگه دارم، همچنان به container مربوط به Valkey نیاز دارم؟
آن را فعال نگه دارید. SearXNG بدون آن کار میکند، اما بدون آن نمیتوانید بعداً محدودکننده را روشن کنید و همچنین وضعیتهای کوتاهمدت دیگر را نیز در خود نگه میدارد. این container کوچک است و فقط دادههای کششده را ذخیره میکند، بنابراین حذف آن فضای بسیار کمی آزاد میکند و در مقابل، این قابلیت را از شما سلب میکند.
چگونه SearXNG را بهروزرسانی کنم؟
در مسیر /opt/searxng، ابتدا docker compose pull و سپس docker compose up -d را اجرا کنید. Compose هر container که image آن تغییر کرده باشد را بازسازی میکند و دایرکتوری core-config/ شما را دستنخورده باقی میگذارد، بنابراین settings.yml حفظ میشود. از آنجا که use_default_settings: true کلیدهای شما را با مقادیر پیشفرض ارائهشده ادغام میکند، گزینههای جدیدی که در نسخه upstream اضافه شدهاند با مقادیر معقول وارد میشوند و فایل شما را خراب نمیکنند.
آیا چند نفر میتوانند از یک instance مشترک استفاده کنند؟
بله، و این دقیقاً همان حالتی است که باید محدودکننده را روشن کنید و public_instance: true را تنظیم نمایید. تنظیمات برگزیده در مرورگر هر بازدیدکننده ذخیره میشود، بنابراین نیازی به مدیریت حساب کاربری نیست. پس از عمومی کردن آن، به مدت یک هفته /stats را زیر نظر بگیرید، زیرا موتورهای upstream خیلی پیش از آنکه متوجه نبود نتایج شوید، شروع به رد کردن درخواستهای سرور شما میکنند.