diff --git a/services/searxng.md b/services/searxng.md new file mode 100644 index 0000000..0d6dcf7 --- /dev/null +++ b/services/searxng.md @@ -0,0 +1,122 @@ +--- +title: SearXNG 검색 엔진 +updated: 2026-03-21 +tags: [search, proxy, google] +--- + +## 개요 + +SearXNG 메타 검색 엔진. K3s 클러스터(searxng 네임스페이스)에 Helm으로 배포. + +- URL: https://searxng.inouter.com/ +- Helm chart: `searxng/searxng` +- 설정 repo: `gitea.anvil.it.com/kaffa/k3s-config` → `searxng/` +- Values: `searxng/values.yaml` + +## Google 차단 우회 (tlsproxy) + +Google이 SearXNG의 요청을 차단하는 두 가지 메커니즘: + +1. **TLS fingerprint** — Python httpx의 TLS ClientHello가 봇으로 인식됨 +2. **GSA User-Agent** — SearXNG가 사용하는 Google Search App UA가 특정 IP에서 차단됨 + +### tlsproxy + +Go + [[https://github.com/refraction-networking/utls|utls]] 기반 MITM forward proxy. HTTP CONNECT 프록시로 동작하며, Google 도메인에 대해 Chrome TLS fingerprint로 연결을 중계함. + +- 소스: sandbox-tokyo `/tmp/tlsproxy/` (TODO: Gitea repo로 이관) +- Docker 이미지: `tlsproxy:latest` (각 서버에서 로컬 빌드) +- 포트: 8443 +- CA 인증서: `/opt/tlsproxy/ca.crt` (10년 유효, 서버 간 공유 필요) + +동작 방식: +1. SearXNG → HTTP CONNECT → tlsproxy +2. tlsproxy가 Google에 Chrome TLS fingerprint(utls `HelloChrome_Auto`, ALPN http/1.1)로 연결 +3. 클라이언트에게 자체 CA로 서명한 인증서 제시 +4. 양방향 relay + +### 배포 현황 + +| 서버 | 상태 | GSA UA | 비고 | +|------|------|--------|------| +| sandbox-tokyo (100.79.87.48:8443) | **운영 중** | 200 | 현재 SearXNG가 사용 중 | +| apisix-osaka (100.108.39.107:8443) | 대기 | 403 | IP 차단됨, IPv4 전용(`tcp4`) | +| relay4wd | 미배포 | 403 | IP 차단됨 | +| incus-jp1 | 미배포 | 403 | IP 차단됨 | + +### SearXNG 설정 + +`outgoing.networks`에 `google_proxy` 네트워크를 정의하고, Google 엔진에서 `network: google_proxy`로 참조. + +```yaml +outgoing: + networks: + google_proxy: + enable_http2: false + verify: /etc/ssl/custom/ca-certificates.crt + proxies: http://100.79.87.48:8443 +engines: + - name: google + engine: google + network: google_proxy +``` + +### CA 인증서 주입 + +Helm chart가 `extraVolumes`를 지원하지 않아 `kubectl patch`로 적용. **helm upgrade 시 재적용 필요.** + +```bash +# CA 번들 Secret (시스템 CA + tlsproxy CA) +kubectl get secret searxng-ca-bundle -n searxng + +# Deployment 패치 (helm upgrade 후 재실행) +kubectl patch deployment searxng -n searxng --type=json -p='[ + {"op":"add","path":"/spec/template/spec/volumes/-","value":{"name":"ca-bundle","secret":{"secretName":"searxng-ca-bundle"}}}, + {"op":"add","path":"/spec/template/spec/containers/0/volumeMounts/-","value":{"name":"ca-bundle","mountPath":"/etc/ssl/custom/ca-certificates.crt","subPath":"ca-certificates.crt","readOnly":true}}, + {"op":"add","path":"/spec/template/spec/containers/0/env/-","value":{"name":"SSL_CERT_FILE","value":"/etc/ssl/custom/ca-certificates.crt"}}, + {"op":"add","path":"/spec/template/spec/containers/0/env/-","value":{"name":"REQUESTS_CA_BUNDLE","value":"/etc/ssl/custom/ca-certificates.crt"}} +]' +``` + +### IP 차단 상태 확인 방법 + +서버에서 GSA UA로 Google 검색을 요청하여 확인: + +```bash +curl -4 -s -o /dev/null -w '%{http_code}' --max-time 10 \ + -H "User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 17_7_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) GSA/406.0.862495628 Mobile/15E148 Safari/604.1" \ + "https://www.google.com/search?q=test&hl=en-US" +# 200 = OK, 403 = 차단됨 +``` + +### 주의사항 + +- **GSA UA 필수**: SearXNG Google 엔진 파서가 GSA 응답 형식에 의존. Chrome UA로 바꾸면 파싱 실패 (결과 0) +- **프록시 round-robin 불가**: SearXNG의 `proxies`를 dict(list) 형태로 넣으면 프록시를 무시하는 버그 있음. 단일 문자열만 동작 +- **CA 번들 패치 영속성**: helm upgrade 시 volume mount/env 패치가 사라짐. upgrade 후 반드시 `kubectl patch` 재실행 +- **새 프록시 서버 추가 시**: CA 키를 공유(`/opt/tlsproxy/ca.crt`, `ca.key`)하고, K8s Secret의 CA 번들도 갱신 필요 + +## 기타 프록시 (SOCKS5) + +이전에 Google 우회 목적으로 배포했으나, TLS fingerprint 문제로 Google에는 무효. 다른 엔진이나 용도로는 사용 가능. + +| 서버 | 포트 | 타입 | +|------|------|------| +| sandbox-tokyo | 1080 | Docker microsocks (IPv4) | +| relay4wd | 1080 | Docker microsocks | +| incus-jp1 socks5-proxy | 1080 | Incus 컨테이너 microsocks | +| apisix-osaka | 1081, 1082 | Docker microsocks (IPv6 `1d00::1`, `1d01::1`) | + +## Helm 업그레이드 절차 + +```bash +# 1. Helm upgrade +helm upgrade searxng searxng/searxng -n searxng -f ~/path/to/values.yaml + +# 2. CA 번들 패치 재적용 (위 kubectl patch 명령) + +# 3. 검증 +kubectl exec -n searxng deploy/searxng -- wget -qO- \ + "http://localhost:8080/search?q=test&format=json&engines=google" | \ + python3 -c "import sys,json; d=json.load(sys.stdin); print(len(d['results']), 'results')" +```