Projects/Self-Hosting a SearXNG Search Engine
AI

Self-Hosting a SearXNG Search Engine

Run a private aggregated search on a VPS for AI and browsers without relying on third-party search APIs.

What it is

A private SearXNG meta-search instance running on an overseas VPS. DSH's web_search previously had only a single Bing source and queried cn.bing.com; now a single query fans out to engines such as Google CSE, Bing, and Wikipedia, then merges and ranks the results. Chinese and English results are both more complete and more timely, and it is still key-free and does not consume search quota.

Why it is on a VPS

SearXNG's upstream engines are blocked in mainland China, so it can only run on a Hong Kong VPS; the internal machine at .223 only retrieves results through the tunnel. The whole setup adds no public ports: on the VPS, the container only listens on 127.0.0.1:8888, so it is completely unreachable from the public internet, and not a single security group rule needs to be changed.

Path

DSH (.223) → local 127.0.0.1:8888 → persistent systemd ssh -L tunnel → VPS loopback port → Docker container. If the tunnel drops, it reconnects in 5 seconds; after the VPS reboots, the container is automatically brought back up by restart: unless-stopped.

Now

Running. healthz returns 200, a single search takes 1.2–2.5 seconds, each query gets 20 raw results, and the tool layer takes the top 8. A public web version with Basic Auth is also attached, which can be bookmarked and used directly in a mobile browser.

Features

  • 把单源 Bing 换成多引擎聚合,一次查询 fan-out 后合并排序
  • 容器只绑回环地址,靠 SSH 隧道对内网暴露,公网零新增端口
  • systemd 常驻隧道自动重连,容器 restart 策略兜住 VPS 重启
  • 自写 DSH 搜索插件,provider id 固定为 searxng,一条命令可回退 Bing
  • 复用通配符证书挂出 Basic Auth 网页版,手机浏览器可用

Stack: SearXNG · Docker · SSH 隧道 · systemd · frp · Nginx Proxy Manager · Let's Encrypt

1. Start the container on the VPS

Write /opt/searxng/docker-compose.yml, use image searxng/searxng:latest, and set the port mapping to 127.0.0.1:8888:8080. Keep CHOWN, SETGID, and SETUID in cap_add; do not write cap_drop: ALL, otherwise the entrypoint will get Permission denied when writing settings.yml, and the container will restart endlessly.

2. Modify settings.yml

Add json to search.formats (if the json endpoint is not enabled, it directly returns 403); set server.limiter to false; replace server.secret_key with a 32-byte random value. Do not set locale to zh-CN; that is not a valid value and will cause a 500 on every request. The valid forms are zh-Hans / zh-Hant; this project simply does not set it.

3. Establish the tunnel

On .223, create searxng-tunnel.service, with a command like ssh -NT -L 127.0.0.1:8888:127.0.0.1:8888 vps, and Restart=always. Verify:

curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8888/healthz, expect 200.

4. Integrate into DSH

Place the plugin in /root/dsh-plugins/dsh-searxng/, and use searxng as the provider id; insert the web-search-searxng line in the patch, and change web.searchProvider to searxng. When installing via