نصب SearXNG شخصی با Docker Compose و TLS
با Docker Compose، SearXNG را روی VPS خود اجرا کنید؛ از settings.yml و limiter تا nginx با TLS و JSON API برای فراخوانی در scriptهای شخصی.
چیزی که میسازید
با self-host کردن SearXNG، یک موتور جستوجوی خصوصی خواهید داشت که روی سرور خودتان اجرا میشود. SearXNG یک موتور metasearch است: پرسوجوی شما را دریافت میکند، آن را برای موتورهای دیگری مانند Google، Bing، DuckDuckGo و Wikipedia میفرستد و سپس پاسخها را در یک صفحه نتایج ادغام میکند. هیچ پروفایلی ساخته نمیشود و هیچ کوکی ردیابی تنظیم نمیشود، زیرا تنها ماشینی که پرسوجوی شما را نگه میدارد، متعلق به خودتان است.
این پشته کوچک است: دو container، یک فایل تنظیمات و یک reverse proxy. تصمیم اصلی این است که نمونه شما خصوصی باشد؛ یعنی فقط شما و scriptهای خودتان به آن دسترسی داشته باشید، یا عمومی باشد؛ یعنی هر فردی در اینترنت بتواند از آن پرسوجو کند. این انتخاب تنظیمات امنیتی را تغییر میدهد، بنابراین پیش از وارد کردن هر چیزی آن را مشخص کنید. پاسخ پیشفرض، حالت خصوصی است.
دلیل دیگری نیز برای اجرای نمونه شخصی وجود دارد. یک نمونه SearXNG با JSON کار میکند؛ بنابراین هر script یا AI agent که بنویسید، یک API جستوجو در اختیار دارید که متعلق به خودتان است و به key، هزینه برای هر پرسوجو یا پیام مربوط به quota نیاز ندارد.
نصب SearXNG با Docker Compose
این پروژه یک container image و یک فایل Compose منتشر میکند. هر دو را روی یک سرور جدید Ubuntu 24.04 دریافت کنید که Docker Engine و Compose plugin را از قبل دارد. اگر 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 یک data store درونحافظهای است که برای محدودسازی نرخ و نگهداری state کوتاهمدت استفاده میشود. این فایل ./core-config/ را در مسیر /etc/searxng/ داخل container mount میکند؛ بنابراین تمام تنظیماتی که انجام میدهید در همان یک directory روی host قرار میگیرند.
اکنون .env را ویرایش کنید. تمام خطوط موجود در نمونه ارائهشده comment شدهاند؛ به همین دلیل container روی port 8080 و روی همه addressها شروع به کار میکند. این سه مورد را uncomment و تنظیم کنید.
SEARXNG_VERSION=latest
SEARXNG_HOST=127.0.0.1
SEARXNG_PORT=8080SEARXNG_HOST=127.0.0.1 مورد مهم است. این گزینه port منتشرشده را به 127.0.0.1:8080:8080 بهجای [::]:8080:8080 تبدیل میکند؛ بنابراین container فقط روی loopback address پاسخ میدهد و اینترنت نمیتواند مستقیماً به آن دسترسی داشته باشد. اگر این مورد را نادیده بگیرید، container بلافاصله پس از شروع در معرض دسترسی قرار میگیرد، چون یک Docker port منتشرشده پیش از قوانین firewall شما قرار میگیرد. این نکته مهم است و باید متن کامل آن را بخوانید: portهای منتشرشده Docker از ufw عبور میکنند.
SEARXNG_VERSION=latest برای زمان یادگیری مناسب است. در سروری که برایتان اهمیت دارد، tag را ثابت کنید. در July 2026، tagهای release بر اساس تاریخ هستند و به شکل 2026.3.25-541c6c3cb دیده میشوند؛ بنابراین deployment ثابت فقط زمانی ارتقا پیدا میکند که شما تصمیم بگیرید، نه زمانی که registry بدون اطلاع شما تغییر کند.
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 دادههای نشست و token را امضا میکند. مقدار پیشفرض همراه آن، رشتهٔ تحتاللفظی ultrasecretkey است. باقی گذاشتن این مقدار به هر کسی که آن پیشفرض را بداند امکان جعل آن tokenها را میدهد. آن را یکبار جایگزین کنید و سپس تغییرش ندهید؛ تغییر مقدار در آینده همهٔ ترجیحات ذخیرهشده را حذف میکند.
base_url باید نشانی عمومی HTTPS، همراه با slash انتهایی، باشد. SearXNG از این مقدار در linkهایی که تولید میکند استفاده میکند. اگر آن را روی localhost بگذارید، link «صفحهٔ بعد» در مرورگر راه دور به رایانهٔ خود کاربر اشاره میکند و کار نمیکند.
formats تعیین میکند endpoint وب چه نوع خروجیهایی تولید کند. json در فهرست پیشفرض وجود ندارد؛ بنابراین درخواست JSON تا زمانی که آن را اضافه نکنید، پاسخ 403 برمیگرداند. image_proxy: true تصویرهای بندانگشتی نتایج را از طریق server شما عبور میدهد؛ بنابراین سایتهایی که آن تصویرها را میزبانی میکنند، نشانی بازدیدکنندگان شما را نمیبینند.
valkey.url از hostname با مقدار valkey استفاده میکند، زیرا این نام service در فایل Compose است و Compose هر دو container را در یک network قرار میدهد؛ در این network نامهای service قابل resolve هستند. آن را روی localhost تنظیم نکنید، زیرا limiter از کار میافتد. داخل container مربوط به core، مقدار localhost به همان container اشاره میکند.
secret در یک فایل ساده قرار دارد. بنابراین بهجای خود فایل، از directory پیرامون آن محافظت کنید. chmod 750 /opt/searxng دسترسی سایر userهای host را مسدود میکند. core-config/settings.yml را روی mode 600 تنظیم نکنید؛ container با user غیرممتاز خودش اجرا میشود و اگر نتواند فایل را بخواند، SearXNG اصلاً راهاندازی نمیشود.
stack را راهاندازی و وضعیت آن را بررسی کنید.
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 را بخوانید، زیرا خطای YAML در settings.yml بهصورت خطای parse همراه با شمارهٔ خط نمایش داده میشود.
آن را با TLS پشت nginx قرار دهید
کانتینر فقط روی 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 پیش از بارگذاری مجدد، syntax is ok و test is successful را چاپ میکند. Certbot همان فایل را بازنویسی میکند تا روی 443 با یک گواهی به درخواستها گوش دهد و یک تغییر مسیر از port 80 اضافه میکند. رکورد DNS مربوط به search.example.com باید از قبل به این سرور اشاره کند، زیرا مرجع صدور گواهی با دریافت یک فایل از طریق HTTP مالکیت را اثبات میکند. راهنمای کامل، شامل تمدید گواهی، در راهنمای Certbot و nginx برای Ubuntu 24.04 آمده است.
دو سرآیند forwarding تزئینی نیستند. بدون X-Forwarded-For و X-Real-IP، هر درخواست ورودی به SearXNG نشانی proxy را حمل میکند؛ بنابراین محدودکننده نرخ، یک client را مسئول تمام traffic میبیند و نمیتواند بازدیدکنندگان را از یکدیگر تشخیص دهد.
چرا اسکریپتها و agentها به 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، در خود دارد. این اطلاعات برای تغذیه یک summariser، link checker یا حلقه پژوهشی کافی است.
این موضوع برای هر چیزی که ساختار agent دارد اهمیت دارد. یک مدل زبانی cutoff آموزشی دارد؛ بنابراین برای پاسخدادن به پرسشهای مربوط به زمان حال به جستوجوی زنده نیاز دارد. از طرفی، APIهای تجاری جستوجو برای هر query هزینه دریافت میکنند و rate limit شدیدی دارند. یک نمونه محلی فقط به یک container روی سروری نیاز دارد که پیشتر هزینه آن را میپردازید و queryها هرگز از آن خارج نمیشوند. اگر در حال اتصال ابزارها به یک مدل هستید، همین منطق درباره اجرای سرورهای MCP روی یک VPS نیز صدق میکند؛ ابزار جستوجو معمولاً نخستین ابزاری است که افراد اضافه میکنند.
برای استفاده از API دو قاعده وجود دارد. نمونه را خصوصی نگه دارید؛ برای این کار، بخش API را به نشانی loopback یا یک شبکه خصوصی bind کنید و فقط به hostهای خودتان اجازه دسترسی بدهید. سپس queryها را با نرخ پایین ارسال کنید. SearXNG درخواست شما را به موتورهای جستوجوی واقعی forward میکند؛ بنابراین اسکریپتی که در هر ثانیه صد query اجرا میکند، از Google میخواهد سرور شما را block کند.
محدودکننده و تغییرات لازم برای یک نمونه عمومی
محدودکننده، سازوکار دفاعی SearXNG در برابر رباتها است. این سازوکار سرآیندهای درخواست، نشانیها و نرخ درخواستها را بررسی میکند و ترافیکی را که خودکار به نظر برسد، حذف میکند. برای نگهداری این وضعیت به Valkey نیاز دارد؛ به همین دلیل فایل Compose آن را نیز راهاندازی میکند.
در یک نمونه خصوصی، limiter: false را نگه دارید. اسکریپتهای خودکار شما ذاتاً ترافیک خودکار هستند؛ بنابراین محدودکننده دقیقاً همان فراخوانیهای JSON را مسدود میکند که نمونه را برای آنها ساختهاید. کنترل دسترسی باید بر عهده reverse proxy باشد: یک جفت allow و deny در location مربوط به nginx، احراز هویت پایه HTTP، یا فایروالی که فقط به سرورهای دیگر شما اجازه ورود میدهد.
اگر نمونه را برای افراد دیگر منتشر میکنید، هر دو گزینه را فعال کنید.
server:
limiter: true
public_instance: trueکنترل دقیقتر در core-config/limiter.toml قرار دارد؛ کانتینر این فایل را از /etc/searxng/limiter.toml میخواند. فقط کلیدهایی را بنویسید که میخواهید تغییر دهید. اگر پشت proxy هستید، باید proxy را اعلام کنید؛ در غیر این صورت، محدودکننده نشانی nginx شما را بهعنوان تنها کاربر سوءاستفادهگر در نظر میگیرد.
[botdetection]
trusted_proxies = [
'127.0.0.0/8',
'::1',
]
[botdetection.ip_limit]
link_token = truelink_token = true باعث میشود SearXNG توکنی صادر کند که فقط یک نشست واقعی مرورگر آن را دریافت میکند؛ این کار بیشتر scraperهای ساده را متوقف میکند. انتظار داشته باشید که یک نمونه عمومی ظرف چند روز مورد توجه آنها قرار بگیرد. همچنین انتظار خطاهای موتور را داشته باشید، زیرا هرچه ترافیک بیشتری ارسال کنید، موتورهای upstream زودتر CAPTCHA را برای نشانی سرور شما برمیگردانند. نگهداری یک نمونه عمومی SearXNG کاری مستمر است. نمونه خصوصی چنین وضعیتی ندارد؛ به همین دلیل در بیشتر فهرستهای کوتاه موارد ارزشمند برای میزبانی شخصی در 2026 قرار میگیرد.
چرا جستوجوها هیچ نتیجهای برنمیگردانند
/stats را روی instance خود باز کنید. این بخش همه engineها را همراه با نرخ خطا و زمان پاسخ آنها فهرست میکند و نخستین جایی است که باید هنگام کم بودن نتایج بررسی کنید.
engineای که خطای «Access denied» یا «CAPTCHA» نشان میدهد، آدرس server شما را مسدود کرده است. این وضعیت برای آدرسهای موجود در بازههای data centre رایج است، زیرا موتورهای جستوجو فرض میکنند این آدرسها به scraperها تعلق دارند. سپس SearXNG، بهجای تلاش مجدد، engine ناموفق را برای مدتی به حالت تعلیق درمیآورد. در نتیجه، یک engine مسدودشده بدون اعلام صریح از نتایج شما حذف میشود. آن را در settings.yml غیرفعال کنید یا این کاهش را بپذیرید. engineهای باقیمانده همچنان پاسخ میدهند.
اگر همه engineها همزمان ناموفق باشند، container قابلیت فعال برای name resolution خروجی یا routeی به اینترنت ندارد. این وضعیت را از داخل container آزمایش کنید.
docker compose exec core wget -qO- https://duckduckgo.com > /dev/null && echo okFAQ
آیا SearXNG جستوجوهای من را ناشناس میکند؟
این نرمافزار هویت شما را از موتورهایی که به آنها درخواست میفرستد پنهان میکند، زیرا آن موتورها بهجای مرورگر شما، سرورتان را بهعنوان درخواستکننده میبینند. اما عبارت جستوجو را از سرور شما پنهان نمیکند و سرورتان را نیز از آن موتورها مخفی نمیکند. در یک نمونه با یک کاربر، تمام ترافیک آن نشانی متعلق به شماست؛ بنابراین خود نشانی به شناسه تبدیل میشود. ترافیک بین مرورگر شما و نمونهتان با گواهی TLS محافظت میشود.
چرا یک درخواست JSON پاسخ 403 Forbidden برمیگرداند؟
این مشکل 2 علت دارد و هر دو به پیکربندی مربوط هستند. یا json در فهرست formats زیر search: در settings.yml وجود ندارد که وضعیت پیشفرض است، یا محدودکننده فعال است و اسکریپت شما را ربات تشخیص داده است. ابتدا قالب را اضافه کنید، با docker compose restart core راهاندازی مجدد کنید و سپس دوباره تلاش کنید. اگر همچنان شکست خورد، limiter: false را تنظیم کنید و دسترسی را در reverse proxy کنترل کنید.
اگر محدودکننده را خاموش نگه دارم، آیا به کانتینر Valkey نیاز دارم؟
آن را در حال اجرا نگه دارید. SearXNG بدون آن نیز کار میکند، اما بدون این کانتینر نمیتوانید محدودکننده را بعداً فعال کنید و این کانتینر وضعیت کوتاهمدت دیگری را نیز نگه میدارد. کانتینر کوچک است و فقط دادههای cacheشده را ذخیره میکند؛ بنابراین حذف آن صرفهجویی بسیار کمی ایجاد میکند و امکان فعالسازی بعدی را از شما میگیرد.
چگونه SearXNG را بهروزرسانی کنم؟
ابتدا docker compose pull و سپس docker compose up -d را در /opt/searxng اجرا کنید. Compose هر کانتینری را که image آن تغییر کرده باشد دوباره ایجاد میکند و دایرکتوری core-config/ شما را بدون تغییر باقی میگذارد؛ بنابراین settings.yml حفظ میشود. چون use_default_settings: true کلیدهای شما را روی مقادیر پیشفرض ارائهشده ادغام میکند، گزینههایی که در نسخههای بالادستی اضافه شدهاند با مقادیر منطقی وارد میشوند و باعث خراب شدن فایل نمیشوند.
آیا چند نفر میتوانند از یک نمونه مشترک استفاده کنند؟
بله. در این حالت محدودکننده را فعال کنید و public_instance: true را تنظیم کنید. تنظیمات هر بازدیدکننده در مرورگر خودش ذخیره میشود؛ بنابراین نیازی به مدیریت حسابها نیست. پس از در دسترس عموم قرار دادن نمونه، /stats را بهمدت 1 هفته بررسی کنید، زیرا موتورهای بالادستی مدتها پیش از آنکه متوجه نبودن نتایج شوید، شروع به رد کردن سرور شما میکنند.