SearXNGをストイック仕様に改造する

1. 構築環境と目的

  • 環境: 1vCPU / RAM 512MB / SWAP 4GB
  • 目的: 「画像・動画」を一切表示せず、セーフサーチ設定すらUIから消去した「文字情報専用」の検索エンジンを作る。

2. 詰まったポイントと解決策

① Dockerマルチステージビルドの罠

当初、ソースコードを直接書き換えて docker build しようとしたが、512MBのメモリではビルドプロセスのコンパイル(特にPythonのネイティブ依存関係)でリソースを食い潰し、起動が極端に不安定(502 Bad Gateway)になった。

  • 解決策: 公式の軽量版Dockerイメージ (searxng/searxng) を使い、中身をいじるのではなく外側(Nginx)でねじ伏せる方針に転換。

② HTMLの「ダブルスペース」問題

Nginxの sub_filter でセーフサーチのプルダウンを消そうとしたが、当初全く反応しなかった。

  • 原因: 実際のHTMLソースを確認すると、属性の間に意図しないダブルスペースが混入していた。
    • NG: <select name="safesearch">
    • OK: <select name="safesearch">(スペースが2つ)
  • 教訓: 正規表現が使えない sub_filter では、curl で生ソースを叩いて1文字単位で一致させる必要がある。

③ セーフサーチがCookie/JSで書き換わる

URLパラメータをNginxで弾いても、UI上のセレクトボックスを操作するとJS経由で設定が切り替わってしまう。

  • 解決策: Nginxの sub_filter で、ブラウザに届く前のHTMLから <select> タグそのものを display:none に書き換え、さらにJSの初期設定オブジェクト内の値を強制上書きした。

3. 最終的な構成(技術スタック)

Nginx: The Content Crusher

Nginxを単なるリバースプロキシではなく、コンテンツ・フィルターとして使用。

location / {
    # 1. セーフサーチ解除(0 or 1)のURLパラメータを入口で叩き落とす
    if ($arg_safesearch ~ '^(0|1)$') { return 403; }

    # 2. レスポンスの圧縮を強制解除(これがないとsub_filterが効かない)
    proxy_set_header Accept-Encoding '';

    # 3. HTMLの物理破壊
    sub_filter '<select  name="safesearch"' '<select style="display:none" disabled';
    sub_filter '<img ' '<span style="display:none" ';
    sub_filter 'class="category_images"' 'style="display:none"';
    
    sub_filter_types text/html;
    sub_filter_once off;
}

SearXNG: Settings Lock

settings.yml でバックエンド側からもロックをかける。

  • safe_search: 2 (Strict)
  • lock: [safesearch, categories, engines] (UIからの変更不可)

4. まとめ

ソースコードを汚さず(ビルドせず)、Nginxの設定だけでアプリケーションの挙動とUIを完全にコントロールする手法は、低リソース環境での運用において非常に強力。