SSD Nodes Learn Hosting plans →
指南 Matt Connor作者: Matt Connor · 更新于 2026-09-05

如何自行托管 SearXNG 私有搜索引擎

使用 Docker Compose 在 VPS 上部署私有 SearXNG,配置 settings.yml 和 limiter,并通过 nginx 启用 TLS;同时提供脚本可调用的 JSON 搜索 API。

您要构建的内容

自行托管 SearXNG,可以在自己的服务器上运行私有搜索引擎。SearXNG 是一个元搜索引擎:它接收您的查询,向 Google、Bing、DuckDuckGo 和 Wikipedia 等其他搜索引擎发起请求,然后将返回结果合并到一个结果页面中。系统不会建立用户画像,也不会设置跟踪 Cookie,因为唯一保存您查询内容的机器就是您自己的服务器。如果您找到过将其简称为 Searx 的旧教程,那么它指的就是 SearXNG 分叉自的项目。该项目自 2023 年以来没有新的提交,因此请先查看两者的当前状态,再选择教程

整个技术栈很小。两个容器、一个配置文件和一个反向代理即可。它可以稳定运行在一台小型 VPS 上,但并非所有自托管服务都如此:PhotoPrism 与 Immich 的对比中提到的照片库,其最低内存需求取决于索引器,而不是 Web 应用。真正需要决定的是实例是否为私有实例:私有实例只允许您和自己的脚本访问;公共实例则允许互联网上的任何人发起查询。这个选择会改变安全设置,因此请在输入任何内容前作出决定。默认应选择私有实例。

运行 SearXNG 还有第二个原因。SearXNG 实例提供 JSON 接口,因此您编写的任何脚本或 AI 代理都可以使用自己拥有的搜索 API,无需密钥、按查询付费或处理配额通知邮件。

使用 Docker Compose 安装 SearXNG

该项目提供容器镜像和 Compose 文件。将二者拉取到全新的 Ubuntu 24.04 服务器上。服务器需要已经安装 Docker Engine 和 Compose 插件。如果您不熟悉 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 .env

Compose 文件定义了两个服务。core 是 SearXNG 本身,valkey 是用于速率限制和短期状态存储的内存数据存储。它将 ./core-config/ 挂载到容器内的 /etc/searxng/,因此您配置的所有内容都位于主机上的同一个目录中。

现在编辑 .env。项目提供的示例中每一行都被注释掉了,因此容器会在所有地址的 8080 端口上启动。取消注释并设置以下三项。

SEARXNG_VERSION=latest
SEARXNG_HOST=127.0.0.1
SEARXNG_PORT=8080

SEARXNG_HOST=127.0.0.1 是关键配置。它将发布端口设置为 127.0.0.1:8080:8080,而不是 [::]:8080:8080,因此容器只响应环回地址,互联网无法直接访问它。如果跳过此项,容器启动后就会立即暴露,因为 Docker 发布的端口会插入到防火墙规则之前。请完整阅读这一常见陷阱:已发布的 Docker 端口会绕过 ufw

学习期间使用 SEARXNG_VERSION=latest 没有问题。但在正式服务器上,应固定镜像标签。截至 2026 年 7 月,发布标签采用日期格式,例如 2026.3.25-541c6c3cb。这样,部署只会在您决定时升级,而不会因镜像仓库发生变化而自动升级。对于服务器上其他需要长期运行的服务,也应遵循同样的原则。这也是为什么 自托管 RustDesk 中继 同样固定镜像标签:远程访问服务无人值守升级,往往会在最不合适的时候暴露问题。

settings.yml:需要关注的部分

在首次启动前创建 core-config/settings.ymluse_default_settings: true 会让 SearXNG 先加载自身随附的默认设置,再仅应用您写入的键,因此文件可以保持简短,并且在升级添加新选项后仍然有效。

先生成密钥,因为该值会直接写入文件。

openssl rand -hex 32
use_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
    - json

secret_key 用于签名会话和令牌数据。随附的默认值是字面字符串 ultrasecretkey;如果保留该值,任何知道默认值的人都可以伪造这些令牌。替换一次后保持不变:之后更改它会丢弃所有已保存的偏好设置。

base_url 必须是公开的 HTTPS 地址,并且以斜杠结尾。SearXNG 会将其写入生成的链接中。如果保留为 localhost,远程浏览器中的“下一页”链接就会指向读者自己的计算机,并因此失效。

formats 决定 Web 端点生成哪些输出类型。json 不在默认列表中,因此添加它之前,JSON 请求会返回 403。image_proxy: true 会通过您的服务器转发结果缩略图,因此托管这些图像的网站不会看到访问者的地址。

valkey.url 使用主机名 valkey,因为这是 Compose 文件中的服务名;Compose 会将两个容器放在同一网络中,并解析服务名。将其指向 localhost 会导致限流器失败,因为在 core 容器内部,localhost 指向该容器本身。

密钥位于普通文件中,因此应保护包含它的目录,而不是仅保护文件本身。chmod 750 /opt/searxng 可以阻止其他主机用户访问该目录。不要将 core-config/settings.yml 收紧为模式 600:容器以自身的非特权用户运行,而该用户无法读取文件时,SearXNG 将完全无法启动。

启动堆栈并检查状态。

cd /opt/searxng
docker compose up -d
docker compose ps
curl -I http://127.0.0.1:8080/

docker compose ps 应显示两个容器的状态均为 runningcurl 应返回 HTTP/1.1 200 OK。如果没有返回内容,请查看 docker compose logs core,因为 settings.yml 中的 YAML 错误会在那里显示为包含行号的解析错误。

使用 TLS 将其置于 nginx 后

容器仅监听 loopback,因此需要通过 nginx 访问它;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.com

重新加载前,nginx -t 会打印 syntax is oktest is successful。Certbot 会重写同一个文件,使其通过证书监听 443 端口,并添加从 80 端口到 HTTPS 的重定向。search.example.com 的 DNS 记录必须已经指向此服务器,因为证书颁发机构会通过 HTTP 获取文件来验证所有权。完整的操作步骤(包括续期)请参阅 适用于 Ubuntu 24.04 的 Certbot 和 nginx 指南

这两个转发标头并非可有可无。缺少 X-Forwarded-ForX-Real-IP 时,到达 SearXNG 的每个请求都会携带代理服务器地址。因此,速率限制器会将所有流量视为来自同一个客户端,无法区分不同的访问者。

为什么脚本和代理需要 JSON 搜索 API

配置 jsonformats 后,渲染页面的同一端点也会返回结构化数据。

curl -s 'http://127.0.0.1:8080/search?q=wireguard+mtu&format=json' \
  | jq -r '.results[0:5][] | .url'

返回结果是一个包含 results 数组的对象。每个条目都包含 urltitlecontent、提供结果的搜索引擎,以及 answersinfoboxessuggestions。这些数据足以供摘要生成器、链接检查器或研究循环使用。将这些结果交给语言模型比看起来更复杂,因为搜索结果是不受信任的文本,其中可能包含自身的指令。让 AI 代理连接到您的 SearXNG 实例会详细处理这一问题。

这对任何具有代理特征的系统都很重要。语言模型有训练数据截止时间,因此需要实时搜索来回答当前问题;商业搜索 API 按查询次数收费,而且通常有严格的速率限制。本地实例只需占用您已经付费的服务器中的一个容器,查询也不会离开该服务器。如果您要将工具接入模型,同样的原因也适用于在 VPS 上运行 MCP 服务器,搜索工具通常是人们首先添加的工具。

API 使用需要遵守两条规则。保持实例私有:将 API 端绑定到 loopback 地址或私有网络,只允许您自己的主机访问。然后以适当频率发送查询。SearXNG 会将您的请求转发到实际的搜索引擎,因此脚本每秒运行一百次查询,就可能导致 Google 屏蔽您的服务器。

公共实例的限制器及其变化

限制器是 SearXNG 的机器人防护机制。它会监控请求标头、地址和请求速率,并丢弃看起来像自动化程序发出的流量。它需要使用 Valkey 保存这些状态,因此 Compose 文件会一并部署 Valkey。

对于私有实例,请保留 limiter: false。您自己的脚本本质上就是自动化流量,因此限制器会拦截您部署该实例正是为了提供的 JSON 请求。访问控制应由反向代理负责:可以在 nginx location 中配置一对 allowdeny,使用 HTTP 基本身份验证,或配置仅允许其他服务器访问的防火墙。如果您需要从网络环境经常变化的笔记本电脑访问私有实例,可以在实例前面配置 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 实例是一项持续工作。私有实例则不需要这样维护,因此它通常位于2026 年值得自行托管的项目短名单中。这些名单中的条目也并非都属于基础设施:将 Jellyfin 媒体库重建成可步行浏览的 90 年代租赁店,同样只是位于同一个 nginx 配置块后的同一个容器,只是面向夜间消遣,而不是某项工作流。

搜索没有返回结果

在实例上打开 /stats。该页面列出每个引擎的错误率和响应时间。结果明显变少时,先检查这里。

显示“Access denied”或“CAPTCHA”错误的引擎已阻止您的服务器地址。数据中心地址段中的地址经常遇到这种情况,因为搜索引擎会假定这些地址属于抓取程序。随后,SearXNG 会暂时停用失败的引擎,而不是不断重试,因此某个被阻止的引擎会悄然从结果中消失。您可以在 settings.yml 中禁用它,也可以接受结果减少这一情况。但并非只有这两种处理方式,因为部分 CAPTCHA 阻止可以通过配置修复,并在重启后保持生效。其余引擎仍会返回结果。429 是一种含义不明确的情况,因为它可能来自您自己的限流器,也可能来自拒绝您服务器的上游引擎;在修改设置前,日志行会说明当前属于哪一种情况

如果所有引擎同时失败,说明容器无法正常进行出站名称解析,或无法路由到互联网。请在容器内部进行测试。

docker compose exec core wget -qO- https://duckduckgo.com > /dev/null && echo ok

系统中没有任何组件会在该检查开始失败时通知您。因此,请通过 cron 定期运行检查,并让失败情况通过您自己的 ntfy 服务器向手机推送告警,不要等到发现搜索结果明显减少后才处理。

FAQ

SearXNG 能让我的搜索匿名吗?

它会向所查询的搜索引擎隐藏您的身份,因为这些引擎看到的是您的服务器发起请求,而不是您的浏览器。它不会对您的服务器隐藏查询内容,也不会对这些引擎隐藏您的服务器。在单用户实例中,来自该地址的所有流量都属于您,因此该地址本身就会成为标识符。您的浏览器与实例之间的流量受 TLS 证书保护。对于您的 ISP、公共实例的运营者以及搜索引擎,SearXNG 实际隐藏了哪些信息,请参阅SearXNG 实际隐藏的内容

为什么 JSON 请求会返回 403 Forbidden?

原因有两个,而且都与配置有关。第一种情况是,json 未添加到 settings.ymlsearch: 下的 formats 列表中,这是默认状态。第二种情况是限制器已启用,并将您的脚本识别为机器人。先添加该格式,再使用 docker compose restart core 重启,然后重试。如果仍然失败,请设置 limiter: false,改为在反向代理处控制访问。

如果我关闭限制器,还需要 Valkey 容器吗?

请保持其运行。SearXNG 没有它也能工作,但之后无法在没有它的情况下启用限制器,而且它还会保存其他短期状态。该容器很小,只存储缓存数据,因此删除它节省不了多少资源,却会失去以后启用限制器的选项。

如何更新 SearXNG?

/opt/searxng 中先运行 docker compose pull,然后运行 docker compose up -d。Compose 会重新创建镜像已更改的容器,并保留您的 core-config/ 目录不变,因此 settings.yml 会继续保留。由于 use_default_settings: true 会将您的密钥合并到已发布的默认值之上,上游新增的选项会获得合理的值,不会导致该文件失效。

多人可以共用一个实例吗?

可以。这种情况下应启用限制器并设置 public_instance: true。偏好设置保存在每位访问者自己的浏览器中,因此无需管理账户。开放实例后的一周内请监控 /stats,因为上游搜索引擎通常会在您注意到搜索结果缺失之前很久,就开始拒绝您的服务器。