feat: deploy SearXNG search engine with Valkey rate limiting

- Add SearXNG service on port 6060 (replaces old port 11112)
- Add Valkey for rate limiting (5/min, 60/hour, 500/day)
- Add Nginx reverse proxy with X-Real-IP and X-Forwarded-For headers
- Configure JSON format and French locale
- Add rate limiting configuration in limiter.toml
- Add Valkey configuration in valkey.conf
This commit is contained in:
Effi Server
2026-07-20 15:41:44 +00:00
parent 2e83369483
commit 14460d387b
5 changed files with 189 additions and 5 deletions
+30 -5
View File
@@ -6,20 +6,44 @@
services:
# ─────────────────────────────────────────────────────────
# 0. SEARXNG - Meta-search Engine (Web Search)
# → http://192.168.1.27:11112
# 0. VALKEY - Backend de rate limiting pour SearXNG
# → Port interne uniquement (non exposé)
# ─────────────────────────────────────────────────────────
valkey:
image: valkey/valkey:7-alpine
container_name: effi-valkey
restart: unless-stopped
command: valkey-server /usr/local/etc/valkey/valkey.conf
volumes:
- ./searxng-config/valkey.conf:/usr/local/etc/valkey/valkey.conf:ro
- valkey-data:/data/valkey-data
networks:
- effi-net
# ─────────────────────────────────────────────────────────
# 1. SEARXNG - Meta-search Engine (API JSON)
# → http://192.168.1.27:6060
# ─────────────────────────────────────────────────────────
searxng:
image: searxng/searxng:latest
container_name: effi-searxng
restart: unless-stopped
ports:
- "11112:8080"
- "6060:8080"
volumes:
- ./searxng-data:/etc/searxng:rw
- ./searxng-config/settings.yml:/etc/searxng/settings.yml:ro
environment:
- SEARXNG_BASE_URL=http://192.168.1.27:11112/
- SEARXNG_BASE_URL=http://192.168.1.27:6060/
- SEARXNG_SECRET=${SEARXNG_SECRET_KEY}
- SEARXNG_SETTINGS_PATH=/etc/searxng/settings.yml
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/healthz"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
depends_on:
- valkey
networks:
- effi-net
@@ -265,3 +289,4 @@ volumes:
open-webui-data:
pipelines-data:
whisper-cache:
redis-data:
+22
View File
@@ -0,0 +1,22 @@
events {
worker_connections 1024;
}
http {
upstream searxng {
server effi-searxng:8080;
}
server {
listen 6060;
server_name localhost;
location / {
proxy_pass http://searxng;
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;
}
}
}
+50
View File
@@ -0,0 +1,50 @@
[botdetection]
# The prefix defines the number of leading bits in an address that are compared
# to determine whether or not an address is part of a (client) network.
ipv4_prefix = 32
ipv6_prefix = 48
# If the request IP is in trusted_proxies list, the client IP address is
# extracted from the X-Forwarded-For and X-Real-IP headers. This should be
# used if SearXNG is behind a reverse proxy or load balancer.
trusted_proxies = [
'127.0.0.0/8',
'::1',
'172.19.0.0/16',
# '192.168.0.0/16',
# '172.16.0.0/12',
# '10.0.0.0/8',
# 'fd00::/8',
]
[botdetection.ip_limit]
# To get unlimited access in a local network, by default link-local addresses
# (networks) are not monitored by the ip_limit
filter_link_local = false
# activate link_token method in the ip_limit method
link_token = false
[botdetection.ip_lists]
# In the limiter, the ip_lists method has priority over all other methods -> if
# an IP is in the pass_ip list, it has unrestricted access and it is also not
# checked if e.g. the "user agent" suggests a bot (e.g. curl).
block_ip = [
# '93.184.216.34', # IPv4 of example.org
# '257.1.1.1', # invalid IP --> will be ignored, logged in ERROR class
]
pass_ip = [
# '192.168.0.0/16', # IPv4 private network
# 'fe80::/10' # IPv6 linklocal / wins over botdetection.ip_limit.filter_link_local
]
# Activate passlist of (hardcoded) IPs from the SearXNG organization,
# e.g. `check.searx.space`.
pass_searxng_org = true
+61
View File
@@ -0,0 +1,61 @@
use_default_settings: true
general:
instance_name: "Effi Search"
debug: false
search:
format: json
max_results: 15
default_lang: fr
safe_search: 0
autocomplete: "google"
default_locale: fr
formats:
- html
- json
server:
secret_key: "${SEARXNG_SECRET_KEY}"
bind_address: "0.0.0.0"
port: 8080
limiter: true
image_proxy: true
public_instance: false
method: "GET"
default_http_headers:
X-Content-Type-Options: nosniff
X-Download-Options: noopen
X-Robots-Tag: noindex, nofollow
Referrer-Policy: no-referrer
valkey:
url: "valkey://172.19.0.12:6379/0"
limiter:
enabled: true
search_url: false
key:
- "client_ip"
limits:
search: "5/minute;60/hour;500/day"
other: "10/minute;100/hour"
whitelist: []
ui:
default_theme: simple
static_use_hash: true
default_view: index
infinite_scroll: false
outgoing:
request_timeout: 10.0
max_request_timeout: 15.0
pool_connections: 100
pool_maxsize: 20
enable_http2: true
useragent_suffix: ""
enable_obfuscation: false
enable_http2: true
+26
View File
@@ -0,0 +1,26 @@
# Redis configuration for SearXNG rate limiting
bind 0.0.0.0
protected-mode no
port 6379
tcp-backlog 511
timeout 0
tcp-keepalive 300
daemonize no
supervised no
pidfile /var/run/redis_6379.pid
loglevel notice
databases 1
save 900 1
save 300 10
save 60 10000
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
dir /data
appendonly no
appendfilename "appendonly.aof"
hz 10
dynamic-hz yes
aof-rewrite-incremental-fsync yes
rdb-save-incremental-fsync yes