Spaces:
Running
Running
File size: 13,648 Bytes
34c5839 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 | # Configuration
## Environment Variables
All configuration is done via environment variables. Create a `.env` file in the project root.
### Access Control
| Variable | Default | Description |
|----------|---------|-------------|
| `ACCESS_KEYS` | `''` | Comma-separated list of valid access keys (e.g., `'key1,key2,key3'`) |
| `ACCESS_KEY_TIMEOUT_HOURS` | `24` | Hours to cache validated keys in browser. Set to `0` to require validation on every request |
**Example:**
```bash
ACCESS_KEYS="my-secret-key-1,my-secret-key-2"
ACCESS_KEY_TIMEOUT_HOURS="24"
```
### AI Model Defaults
Configure default models for different inference types:
| Variable | Default | Description |
|----------|---------|-------------|
| `WLLAMA_DEFAULT_MODEL_ID` | `littlelamb-290m` | Default Wllama model ID (used for both WebGPU-accelerated and CPU inference) |
### Internal API Configuration
For self-hosted OpenAI-compatible APIs:
| Variable | Default | Description |
|----------|---------|-------------|
| `INTERNAL_OPENAI_COMPATIBLE_API_BASE_URL` | `''` | Base URL of your API (e.g., `https://api.internal.company.com/v1`) |
| `INTERNAL_OPENAI_COMPATIBLE_API_KEY` | `''` | API key for authentication |
| `INTERNAL_OPENAI_COMPATIBLE_API_MODEL` | `''` | Model ID to use (auto-detected if empty) |
| `INTERNAL_OPENAI_COMPATIBLE_API_NAME` | `Internal API` | Display name shown in UI |
**Example:**
```bash
INTERNAL_OPENAI_COMPATIBLE_API_BASE_URL="https://llm.internal.company.com/v1"
INTERNAL_OPENAI_COMPATIBLE_API_KEY="sk-internal-xxx"
INTERNAL_OPENAI_COMPATIBLE_API_MODEL="llama-3.1-8b"
INTERNAL_OPENAI_COMPATIBLE_API_NAME="Company LLM"
```
### Default Behavior
| Variable | Default | Description |
|----------|---------|-------------|
| `DEFAULT_INFERENCE_TYPE` | `browser` | Default AI inference type (`browser`, `openai`, `horde`, `internal`) |
### Server Configuration
These variables control the Vite development/preview server behavior:
| Variable | Default | Description |
|----------|---------|-------------|
| `HOST` | `0.0.0.0` | Host address for the Vite server to bind to |
| `PORT` | `7860` | Port number for the main server |
| `HMR_PORT` | `7861` | Port for Hot Module Replacement during development |
| `ALLOWED_HOSTS` | `true` | Comma-separated list of allowed hostnames for the preview server |
| `BASIC_SSL` | `false` | Enable basic SSL for HTTPS support during development |
| `TRUST_PROXY` | `false` | Trust `X-Forwarded-For`/`X-Real-IP` for the per-client rate-limit key. Enable **only** behind a reverse proxy that sets the rightmost `X-Forwarded-For` entry. Leave off when the instance is exposed directly - otherwise clients could forge the header to evade rate limiting. |
These defaults are provided by `docker-compose.yml`/`docker-compose.production.yml` (e.g. `PORT=${PORT:-7860}`), not by the application itself - `vite.config.ts` reads these variables with no fallback, so when running directly via `npm run dev`/`vite preview` without Docker, unset variables fall through to Vite's own built-in defaults.
## Application Settings
Settings are stored in browser localStorage and can be changed via the Settings UI.
### Core Settings
| Setting | Type | Default | Description |
|---------|------|---------|-------------|
| `enableAiResponse` | boolean | `false` | Enable AI-generated responses for searches |
| `showEnableAiResponsePrompt` | boolean | `true` | Show prompt to enable AI response on first use |
| `enableImageSearch` | boolean | `true` | Include image results in searches |
| `enableTextSearch` | boolean | `true` | Include text results in searches |
| `searchResultsLimit` | number | `15` | Maximum search results to fetch |
| `systemPrompt` | string | (template) | Custom system prompt template for AI |
| `enterToSubmit` | boolean | `true` | Press Enter to submit query (vs Shift+Enter for new line) |
| `enableAiResponseScrolling` | boolean | `true` | Auto-scroll AI response as it generates |
| `enableNotificationOnAiComplete` | boolean | `false` | Show a browser notification when AI response generation finishes |
### Inference Settings
| Setting | Type | Default | Description |
|---------|------|---------|-------------|
| `inferenceType` | enum | `'browser'` | AI provider: `browser`, `openai`, `horde`, `internal` |
| `cpuThreads` | number | (auto) | Number of CPU threads for inference (Wllama), defaults to `navigator.hardwareConcurrency - 2` |
| `allowAiModelDownload` | boolean | `false` | Allow automatic AI model downloads |
| `wllamaModelId` | string | `WLLAMA_DEFAULT_MODEL_ID` env var | Default Wllama model ID |
| `hordeApiKey` | string | `'0000000000'` | AI Horde API key (default is anonymous) |
| `hordeModel` | string | `''` | Specific AI Horde model to request |
| `openAiApiBaseUrl` | string | `''` | Base URL for the OpenAI-compatible API |
| `openAiApiKey` | string | `''` | API key for the OpenAI-compatible API |
| `openAiApiModel` | string | `''` | Model identifier for the OpenAI-compatible API |
| `openAiContextLength` | number | `4096` | Context window size for OpenAI-compatible models, sent as `max_tokens` |
### Model Selection
**Wllama Models:**
- 30+ pre-configured models
- Range from 135M to 4B parameters
- All quantized to Q4_K_S or UD-Q4_K_XL
- Stored at: `Felladrin/gguf-sharded-*` on HuggingFace
**OpenAI/Internal:**
- Any OpenAI-compatible API
- Auto-model detection if not specified
- Supports streaming and reasoning models
**AI Horde:**
- Uses aihorde.net distributed network
- Anonymous or authenticated access
- Parallel generation with race conditions
### History Settings
| Setting | Type | Default | Description |
|---------|------|---------|-------------|
| `enableHistory` | boolean | `true` | Enable search history persistence |
| `historyRetentionDays` | number | `30` | Days to keep search history |
| `historyMaxEntries` | number | `1000` | Maximum history entries before cleanup |
| `historyAutoCleanup` | boolean | `true` | Automatically clean old history entries |
| `historyGroupByDate` | boolean | `true` | Group history entries by date in UI |
### System Prompt Configuration
The default system prompt supports template placeholders populated at runtime:
```typescript
{
systemPrompt: `Answer using the search results below as your primary source, supplemented by your own knowledge when needed. Write your response in the same language as the query.
Cite every fact taken from the search results with an inline Markdown link immediately after it. Format: [domain.com](https://full-url). Use only the top-level domain (no https://, www., or paths) as link text. Example: [youtube.com](https://www.youtube.com/watch?v=dQw4w9WgXcQ).
When the search results disagree with each other, point out the conflict. When you rely on your own knowledge because the results don't cover something, make that clear rather than presenting it as sourced.
Today's date is {{currentDate}}. Use it to resolve relative date references in both the question and the results.
You are allowed to use these Markdown elements: anchor, bold, italic, code, quote, table.
Search results:
{{searchResults}}`,
reasoningStartMarker: '<think>',
reasoningEndMarker: '</think>'
}
```
**Placeholders:**
- `{{currentDate}}`: Current date injected at generation time
- `{{dateTime}}`: Alias for `{{currentDate}}` - both are replaced with the same current date value
- `{{searchResults}}`: Formatted search results from the web search
**Reasoning Markers:** Models that output internal thought processes use `<think>` and `</think>` markers. The UI extracts and separately displays reasoning content from the final response.
### Privacy Settings
| Setting | Type | Default | Description |
|---------|------|---------|-------------|
| `selectedVoiceId` | string | `""` | Voice ID for text-to-speech |
| `reasoningStartMarker` | string | `"<think>"` | Marker for start of reasoning content |
| `reasoningEndMarker` | string | `"</think>"` | Marker for end of reasoning content |
## Docker Configuration
### docker-compose.yml (Development)
```yaml
services:
development-server:
environment:
- HOST=${HOST:-0.0.0.0}
- PORT=${PORT:-7860}
- BASIC_SSL=${BASIC_SSL:-false}
- HMR_PORT=${HMR_PORT:-7861}
ports:
- "${PORT:-7860}:7860"
- "${HMR_PORT:-7861}:7861"
build:
dockerfile: Dockerfile
context: .
volumes:
- .:/home/node/app/ # Live code mounting
command:
[
"(cd /usr/local/searxng/searxng-src && /usr/local/searxng/searxng-venv/bin/python -m searx.webapp > /tmp/searxng.log 2>&1) & (npm install && npm run dev)",
]
```
### docker-compose.production.yml
Same structure but without volume mounts and with pre-built assets.
### Dockerfile Environment
The Dockerfile sets up a single runtime stage:
- Node.js LTS
- Python 3 + SearXNG
The app runs under the `node` user, with the app directory at `/home/node/app`. The production image starts the app with `npm start -- --host` (i.e. `vite preview`), not `npm run dev`.
**Multi-service container** runs SearXNG and Node.js concurrently via shell process composition.
### Nothing Is Configured at Build Time
The Dockerfile declares no `ARG` for any of the settings above, and
`.dockerignore` excludes `.env` files from the build context. Both are
deliberate: build args are recorded in `docker history`, and a copied `.env`
becomes a readable image layer, so either one would publish `ACCESS_KEYS` and
`INTERNAL_OPENAI_COMPATIBLE_API_KEY` to anyone who pulls the image.
Pass configuration when you start the container, via `docker run -e`, the
`environment:` block in a compose file, or a secret manager. Building your own
image with `--build-arg ACCESS_KEYS=...` has no effect, and neither does
relying on a local `.env` being baked in; without runtime values the app falls
back to the `.env.example` defaults. See
[Runtime Configuration](#runtime-configuration) for how those values reach the
client.
## Runtime Configuration
Client-facing configuration (access keys, inference type, internal API settings) is resolved at runtime via the `/api/config` endpoint. The client fetches this endpoint on app initialization, so the published Docker image is fully configurable via environment variables at runtime - no rebuild needed.
### `/api/config` Response
```json
{
"accessKeysEnabled": true,
"accessKeyTimeoutHours": 24,
"wllamaDefaultModelId": "littlelamb-290m",
"internalApiEnabled": true,
"internalApiName": "Internal API",
"defaultInferenceType": "browser"
}
```
### Build-Time vs Runtime Configuration
| Value | Resolved At | Notes |
|-------|-------------|-------|
| `VITE_SEARCH_TOKEN` | Build time | CSRF protection token, regenerated on each build |
| `VITE_BUILD_DATE_TIME` | Build time | Epoch milliseconds when the build occurred |
| `VITE_COMMIT_SHORT_HASH` | Build time | Git commit hash at build time (if available) |
| `ACCESS_KEYS` | Runtime | Read from `/api/config` |
| `ACCESS_KEY_TIMEOUT_HOURS` | Runtime | Read from `/api/config` |
| `WLLAMA_DEFAULT_MODEL_ID` | Runtime | Read from `/api/config` |
| `INTERNAL_OPENAI_COMPATIBLE_API_*` | Runtime | Read from `/api/config` (except `API_KEY` which is server-only) |
| `DEFAULT_INFERENCE_TYPE` | Runtime | Read from `/api/config` |
### Security Considerations
- `VITE_SEARCH_TOKEN`, `VITE_BUILD_DATE_TIME`, and `VITE_COMMIT_SHORT_HASH` are bundled into the client JavaScript as build-time constants (CSRF token and build metadata)
- All other configuration is fetched at runtime from `/api/config` and never appears in the bundled JavaScript
- Server-only variables like `INTERNAL_OPENAI_COMPATIBLE_API_KEY` are never exposed to the client
## Configuration Patterns
### Scenario: Private Team Instance
```bash
# .env
ACCESS_KEYS="team-alpha-2024,team-beta-2024"
ACCESS_KEY_TIMEOUT_HOURS="8"
DEFAULT_INFERENCE_TYPE="internal"
INTERNAL_OPENAI_COMPATIBLE_API_BASE_URL="https://llm.company.com/v1"
INTERNAL_OPENAI_COMPATIBLE_API_KEY="sk-xxx"
INTERNAL_OPENAI_COMPATIBLE_API_MODEL="llama-3.1-70b"
```
### Scenario: Public Demo (No AI)
```bash
# .env - empty, no access keys
# AI disabled by default in settings
```
### Scenario: Browser-Only AI
```bash
# .env - minimal or empty
# Users choose the Wllama model in settings (WebGPU used automatically when available)
# Models download to user's browser (no server AI)
```
## Debugging Configuration
MiniSearch logs internal events to an in-app log panel (see the Logs section of the menu), backed by `logEntriesPubSub` in `client/modules/logEntries.ts`. There is no separate browser-console debug flag to enable.
**Diagnosing empty search results:** if a search returns no results, the client only sees a generic failure. The actual reason is printed to the server's console (via `server/webSearchService.ts`, always-on `debug` logging), either the SearXNG engines that failed (timeouts, suspensions, rate limits, from SearXNG's `unresponsive_engines` field) or a note that all returned results were discarded during processing (missing title, snippet, or media source). Check the server logs (`docker compose logs`) when troubleshooting failed searches.
Check effective configuration:
```typescript
// In browser console
console.log('Settings:', JSON.parse(localStorage.getItem('settings') || '{}'));
console.log('Server config:', await fetch('/api/config').then(r => r.json()));
```
## Related Topics
- **AI Integration**: `docs/ai-integration.md` - Detailed inference type configuration
- **Security**: `docs/security.md` - Access control and privacy details
- **Deployment**: `docs/overview.md` - Container architecture and production setup
|