# SearXNG Tier A captcha fix (2026-09-18): remove scraped engine families that # CAPTCHA this egress (brave/duckduckgo/startpage), wikidata 403'd too. # # ⚠ SUPERSEDED FOR THE SETTINGS FILE — read the scope of this note. # The v4 design here assumed settings.yml could pull the Brave key via # `!ENV SEARXNG_BRAVE_API_KEY`. This build has NO !ENV YAML constructor: that # attempt made the file unparseable and crash-looped the container ten times # with fleet search down. The key is now INLINE in the canonical settings file # (operator decision, the key is low-value free-tier), and settings deployment # goes through `scripts/deploy-stack.sh nh3-docker searxng --conf` like every # other stack. Do NOT upload a settings file from here expecting !ENV to work. # # What is still worth keeping below: the `.env` merge step and the # `up -d`-not-`restart` step, plus the two ⚠ notes recording real bugs this # playbook hit (a wholesale .env overwrite that clobbered SEARXNG_SECRET, and a # sed that inserted literal backslash-n into compose.yaml). # # Rerunnable. Pass the key at the CLI: --var brave_key=... (never store it here). vars: conf: /opt/docker/conf/searxng/searxng-settings.yml compose_dir: /opt/docker/compose/searxng brave_key: "" searxng_secret: "" # from vault nh3-docker/searxng-secret, passed via --var steps: - name: Timestamped backup of current settings shell: cp {{ conf }} {{ conf }}.bak-$(date +%Y%m%d-%H%M%S) when: "! grep -q 'Tier A (v4' {{ conf }}" - name: Install new settings upload: src: /tmp/searxng-tierA/searxng-settings.yml dest: "{{ conf }}" mode: "0644" when: "! grep -q 'Tier A (v4' {{ conf }}" - name: Write .env with BOTH keys (a previous run clobbered SEARXNG_SECRET) # ⚠ This dir already had a .env holding SEARXNG_SECRET; an earlier version # of this step overwrote the file wholesale. Merge, never truncate. sudo: true shell: | test -n '{{ brave_key }}' && test -n '{{ searxng_secret }}' && \ printf 'SEARXNG_SECRET=%s\nSEARXNG_BRAVE_API_KEY=%s\n' '{{ searxng_secret }}' '{{ brave_key }}' | tee {{ compose_dir }}/.env >/dev/null && \ chown infra-ops:docker {{ compose_dir }}/.env && chmod 600 {{ compose_dir }}/.env # Skip only when .env already holds both keys (values are stable; to force # a rewrite, delete the file). when: "grep -q SEARXNG_SECRET {{ compose_dir }}/.env 2>/dev/null && grep -q SEARXNG_BRAVE_API_KEY {{ compose_dir }}/.env && exit 1 || exit 0" - name: Ensure compose references the key (undo bad sed, then append cleanly) # ⚠ `sed 's/$/\\n.../'` inserted LITERAL backslash-n text, not a newline — # compose then parsed one env entry. awk-append instead. sudo: true shell: | sed -i 's|\\n - SEARXNG_BRAVE_API_KEY=${SEARXNG_BRAVE_API_KEY}||' {{ compose_dir }}/compose.yaml grep -q SEARXNG_BRAVE_API_KEY {{ compose_dir }}/compose.yaml || \ awk '{print} /SEARXNG_SECRET/ {print " - SEARXNG_BRAVE_API_KEY=${SEARXNG_BRAVE_API_KEY}"}' {{ compose_dir }}/compose.yaml > {{ compose_dir }}/.c.new && mv {{ compose_dir }}/.c.new {{ compose_dir }}/compose.yaml when: "! grep -q 'SEARXNG_SECRET=${SEARXNG_SECRET}$' {{ compose_dir }}/compose.yaml || ! grep -q SEARXNG_BRAVE_API_KEY {{ compose_dir }}/compose.yaml" - name: Recreate container (env changes need up -d, not restart) shell: cd {{ compose_dir }} && docker compose up -d verify: - name: New config in place shell: grep -q 'Tier A (v4' {{ conf }} changed_when: "false" - name: Compose references the key shell: grep -q SEARXNG_BRAVE_API_KEY {{ compose_dir }}/compose.yaml changed_when: "false" - name: Key is in the container env shell: docker exec searxng printenv SEARXNG_BRAVE_API_KEY >/dev/null changed_when: "false" - name: Container serving /healthz after recreate shell: sleep 8; curl -sf http://127.0.0.1:9996/healthz changed_when: "false"