SSD Nodes Learn 8GB 内存 — 每年 $66
指南 Matt Connor作者: Matt Connor · 更新于 2026-08-01

如何用 Docker Compose 自建私有 SearXNG

在 VPS 上用 Docker Compose 部署私有 SearXNG,配置 settings.yml、limiter 和 nginx TLS,并启用无需密钥的 JSON 搜索 API,供脚本调用。

您要构建的内容

自行托管 SearXNG,可以在自己的服务器上运行私有搜索引擎。SearXNG 是一个元搜索引擎:它接收您的查询,向 Google、Bing、DuckDuckGo 和 Wikipedia 等其他搜索引擎发起请求,然后将返回的结果合并到一个结果页面中。系统不会建立用户画像,也不会设置跟踪 Cookie,因为只有您自己的计算机会保存您的查询。

整个技术栈很小。两个容器、一个 settings 文件和一个反向代理。真正需要决定的是实例应保持私有,还是公开访问。私有表示只有您和您自己的脚本可以访问;公开表示互联网上的任何人都可以查询。这个选择会改变安全设置,因此请在输入任何内容前先做出决定。默认选择是私有。

运行自己的实例还有第二个原因。SearXNG 实例支持 JSON,因此您编写的任何脚本或 AI agent 都可以使用由您控制的搜索 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,因此容器只响应 loopback 地址,互联网无法直接访问它。如果跳过此设置,容器启动后就会立即暴露,因为 Docker 发布的端口会插入到防火墙规则之前。请完整阅读相关注意事项:Docker 发布的端口会绕过 ufw

学习期间使用 SEARXNG_VERSION=latest 即可。在需要长期维护的服务器上,应固定 tag。截至 2026 年 7 月,release tag 基于日期,格式类似 2026.3.25-541c6c3cb。这样,部署只会在你决定时升级,而不会因 registry 发生变化而自动升级。

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 错误会在那里显示为包含行号的解析错误。

将其置于 nginx 后并启用 TLS

容器仅监听 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 的重定向。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。这些数据足以供摘要生成器、链接检查器或研究循环使用。

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

使用 API 时有两条规则。保持实例私有:将 API 端绑定到回环地址或私有网络,只允许你自己的主机访问。然后以适当的频率查询。SearXNG 会将请求转发给实际的搜索引擎,因此每秒运行一百次查询的脚本会导致 Google 封禁你的服务器。

限流器,以及公开实例的变化

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

对于私有实例,请保留 limiter: false。您自己的脚本本质上属于自动化流量,因此限流器会阻止您部署该实例正是为了处理的 JSON 请求。访问控制应由反向代理负责:在 nginx location 中配置 allowdeny,使用 HTTP 基本身份验证,或配置仅允许其他服务器访问的防火墙。

如果您确实要向其他人公开实例,请同时启用这两个开关。

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 年自行托管的事物 简短清单中的原因。

搜索没有返回结果的原因

在您的实例上打开 /stats。该页面列出每个引擎的错误率和响应时间。结果过少时,应首先查看此页面。

如果某个引擎显示“Access denied”或“CAPTCHA”错误,说明它已阻止您的服务器地址。数据中心地址段中的地址经常出现这种情况,因为搜索引擎通常会将其视为爬虫地址。SearXNG 随后会暂时停用持续失败的引擎,而不是重试。因此,被阻止的引擎会悄然停止返回结果。您可以在 settings.yml 中停用该引擎,也可以接受结果减少。其余引擎仍会返回结果。

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

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

FAQ

SearXNG 能让我的搜索匿名吗?

它会向所查询的搜索引擎隐藏您的身份,因为这些引擎看到的是您的服务器发出的请求,而不是您的浏览器发出的请求。它不会对您的服务器隐藏查询内容,也不会向这些引擎隐藏您的服务器。在单用户实例中,来自该地址的所有流量都属于您,因此该地址本身会成为标识符。您的浏览器与实例之间的流量由 TLS 证书保护。

为什么 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 一周,因为上游搜索引擎会在您发现搜索结果缺失之前很久,就开始拒绝您的服务器。

#searxng#search#privacy#自托管#Docker