A simple proxy server for SearXNG meta-search engine with authentication, designed to provide secure access to privacy-respecting search.
π Table of Contents
- API Key Authentication: Secure access control via Bearer tokens
- Cloudflare Tunnel Integration: Built-in support for secure external access
- Docker Support: Complete containerized setup with Docker Compose
- Health Check Endpoints: Monitor proxy status (authenticated + unauthenticated)
- Multi-Engine Search: Aggregates results from Google, Bing, DuckDuckGo, Qwant, Yahoo, Brave
- Flexible Configuration: Environment-based configuration
- Comprehensive Tests: Unit and integration tests with Jest
- Unlimited Searches: No rate limits (self-hosted)
- JSON & HTML Output: Support for both JSON API and HTML responses
π Prerequisites
- Docker and Docker Compose
- Node.js 18+ (for local development)
- Cloudflare account (optional, for tunnel)
-
Clone the repository:
git clone https://github.com/loonylabs-dev/searxng-proxy.git cd searxng-proxy -
Set up environment:
cp .env.example .env # Edit .env with your API key -
Generate API Key:
# Generate a secure API key openssl rand -base64 32 # Add to .env: # API_KEY=your_generated_key_here
-
Start services:
docker-compose up -d
-
Verify:
# Check services docker-compose ps # Test local endpoint (requires port mapping, see Configuration) curl -H "Authorization: Bearer YOUR_API_KEY" \ "http://localhost:3000/search?q=test&format=json"
π» Local Development
-
Install dependencies:
npm install
-
Set up environment:
cp .env.example .env # Edit .env with your configuration (use SEARXNG_URL=http://localhost:8080) -
Start SearXNG (Docker):
docker run -d -p 8080:8080 -v ./searxng:/etc/searxng searxng/searxng:latest
-
Start the proxy:
npm run dev # Development mode # or npm run build && npm start # Production mode
The proxy provides secure access to SearXNG with API key authentication.
All requests (except /healthz) require a Bearer token:
Authorization: Bearer YOUR_API_KEYSearch with SearXNG.
Parameters:
q(required) - Search queryformat(optional) - Response format:json(default) orhtmlengines(optional) - Specific engines to use- Additional SearXNG parameters (language, time_range, etc.)
Example:
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://search.loonylabs.dev/search?q=typescript+best+practices&format=json"Response (JSON):
{
"query": "typescript best practices",
"number_of_results": 42,
"results": [
{
"title": "TypeScript Best Practices",
"url": "https://example.com/typescript-best-practices",
"content": "Learn the best practices for TypeScript...",
"engine": "google"
}
]
}Health check (requires authentication).
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://search.loonylabs.dev/health"Response:
{
"status": "ok",
"service": "searxng-proxy"
}Health check (no authentication required - for Cloudflare monitoring).
curl "https://search.loonylabs.dev/healthz"Response:
{
"status": "ok",
"service": "searxng-proxy"
}// searxng-client.ts
import fetch from 'node-fetch';
const SEARXNG_URL = 'https://search.loonylabs.dev';
const SEARXNG_API_KEY = process.env.SEARXNG_API_KEY;
export async function search(query: string, maxResults = 10) {
const response = await fetch(
`${SEARXNG_URL}/search?q=${encodeURIComponent(query)}&format=json`,
{
headers: {
'Authorization': `Bearer ${SEARXNG_API_KEY}`,
},
}
);
if (!response.ok) {
throw new Error(`Search failed: ${response.statusText}`);
}
const data = await response.json();
return data.results.slice(0, maxResults);
}Usage:
const results = await search('machine learning tutorials', 10);
console.log(results);For secure external access:
-
Set up Cloudflare Tunnel:
# Install cloudflared and create a tunnel cloudflared tunnel create searxng-proxy -
Configure tunnel:
cp cloudflare/config.example.yml cloudflare/config.yml # Edit config.yml with your tunnel ID and domain -
Add tunnel credentials: Place your tunnel credentials JSON file in
cloudflare/ -
Configure DNS:
cloudflared tunnel route dns searxng-proxy search.loonylabs.dev
-
The tunnel will automatically start with Docker Compose
See cloudflare/README.md for detailed setup instructions.
π§ Environment Variables
Create .env from .env.example:
| Variable | Default | Description |
|---|---|---|
API_KEY |
Required | Authentication key for API access |
SEARXNG_URL |
http://searxng:8080 (Docker)http://localhost:8080 (local) |
SearXNG server URL |
PORT |
3000 |
Proxy server port (local dev only) |
PROXY_URL |
- | Proxy URL for integration tests (optional) |
Example .env:
API_KEY=your_secret_api_key_here
SEARXNG_URL=http://searxng:8080
# For integration tests (optional)
PROXY_URL=https://search.loonylabs.devπ SearXNG Settings
Edit searxng/settings.yml to customize:
- Search engines
- UI theme
- Rate limiting
- Result formatting
- Language preferences
See SearXNG Documentation for all options.
π³ Docker Configuration
The Docker setup includes:
- SearXNG container: Meta-search engine (internal only)
- Proxy container: Express server with API key authentication
- Cloudflared container: Cloudflare Tunnel client (optional)
Architecture:
Internet (HTTPS)
β
Cloudflare Tunnel
β
Proxy (Express + API Key Auth)
β
SearXNG (Meta-Search Engine)
Port Exposure: By default, no ports are exposed to the host for security. Access is via Cloudflare Tunnel.
To expose port 3000 for local testing, add to docker-compose.yml:
proxy:
ports:
- "3000:3000" # Add this lineThe project includes comprehensive unit and integration tests.
# Run all tests
npm test
# Run only unit tests (no Docker required)
npm run test:unit
# Run only integration tests (Docker required)
npm run test:integration
# Run tests in watch mode
npm run test:unit:watch
# Run tests with coverage
npm run test:unit:coverage/tests
βββ /unit # Unit tests (no Docker required)
β βββ /api # API endpoint tests
β βββ health.test.ts # Health endpoint tests (9 tests)
β βββ search.test.ts # Search logic tests (21 tests)
βββ /integration # Integration tests (Docker required)
β βββ searxng-integration.test.ts # End-to-end search tests (17 tests)
βββ README.md # Detailed testing documentation
Integration tests require running Docker containers:
# 1. Start services
docker-compose up -d
# 2. Configure PROXY_URL in .env
# Option A: Use Cloudflare Tunnel URL (recommended)
PROXY_URL=https://search.loonylabs.dev
# Option B: Use localhost (requires port mapping)
# Add "ports: - 3000:3000" to proxy service in docker-compose.yml
PROXY_URL=http://localhost:3000
# 3. Run integration tests
npm run test:integrationTest Coverage:
- β 47+ tests across unit and integration suites
- β
Health check endpoints (
/health,/healthz) - β Search functionality (JSON/HTML formats)
- β Authentication & authorization
- β Error handling (missing params, invalid API keys)
- β Response validation
- β Special characters & unicode support
For detailed testing documentation, see tests/README.md.
searxng-proxy/
βββ src/
β βββ index.ts # Express proxy server with API key auth
βββ tests/ # Test suite
β βββ unit/ # Unit tests
β β βββ api/ # API endpoint unit tests
β β βββ health.test.ts
β β βββ search.test.ts
β βββ integration/ # Integration tests
β β βββ searxng-integration.test.ts
β βββ README.md # Testing documentation
βββ searxng/
β βββ settings.yml # SearXNG configuration
βββ cloudflare/
β βββ config.example.yml # Cloudflare tunnel template
β βββ README.md # Cloudflare setup guide
βββ docker-compose.yml # Complete stack (searxng + proxy + cloudflared)
βββ Dockerfile # Proxy service image
βββ .env.example # Environment variables template
βββ jest.config.js # Jest test configuration
βββ jest.setup.js # Jest setup file
βββ package.json # Node.js dependencies
βββ tsconfig.json # TypeScript configuration
βββ README.md # This file
- API Key: Use a strong, randomly generated key (32+ characters)
- HTTPS Only: Cloudflare Tunnel provides automatic HTTPS
- Credentials: Never commit
.env,config.yml, or*.jsonfiles - Rate Limiting: Consider adding rate limiting in production
- Monitoring: Monitor usage via Cloudflare Analytics
- Port Exposure: By default, no ports are exposed to host (secure)
# Check Docker
docker --version
docker-compose --version
# Check logs
docker-compose logs
# Check specific service
docker-compose logs proxy
docker-compose logs searxng- Verify API key in
.envmatches your request header - Check:
Authorization: Bearer YOUR_API_KEY(space after "Bearer") - API key is case-sensitive
- Ensure no extra spaces or newlines in API key
# Check cloudflared logs
docker-compose logs cloudflared
# Verify tunnel configuration
cat cloudflare/config.yml
# Test tunnel status (on Cloudflare dashboard)
# https://one.dash.cloudflare.com/# Check SearXNG logs
docker-compose logs searxng
# Test SearXNG directly (inside Docker network)
docker-compose exec proxy wget -O- "http://searxng:8080/search?q=test&format=json"
# Check if SearXNG is running
docker-compose ps searxngCause: Proxy port not exposed to host (intentional for security)
Solutions:
-
Use Cloudflare Tunnel (recommended):
# In .env PROXY_URL=https://search.yourdomain.com -
Temporarily expose port for testing:
# In docker-compose.yml proxy: ports: - "3000:3000"
Then restart:
docker-compose down && docker-compose up -d
# Clear npm cache
npm cache clean --force
# Remove node_modules and package-lock.json
rm -rf node_modules package-lock.json
# Reinstall
npm installMIT License - see LICENSE file for details.
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests if applicable
- Run tests:
npm test - Submit a pull request
For questions or support, please open an issue on GitHub.
This project follows the same pattern as:
- ollama-proxy - Ollama API with authentication and Cloudflare Tunnel
- SearXNG: https://github.com/searxng/searxng
- SearXNG Docs: https://docs.searxng.org
- Cloudflare Tunnels: https://developers.cloudflare.com/cloudflare-one/connections/connect-apps
Made with β€οΈ by loonylabs-dev
Privacy-Respecting Meta-Search API β